1
# Copyright (C) 2005, 2006 by Aaron Bentley
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from bzrlib.bzrdir import BzrDir
20
import bzrlib.bzrdir as bzrdir
21
from bzrlib.errors import (BzrError,
28
from bzrlib.branch import Branch
29
from bzrlib.commit import Commit, NullCommitReporter
30
from bzrlib.commands import Command
31
from bzrlib.option import _global_option, Option
32
from bzrlib.merge import merge_inner
33
from bzrlib.revision import NULL_REVISION
34
from bzrlib.tree import EmptyTree
37
from bzrlib.workingtree import WorkingTree
38
from errors import NoPyBaz
42
from pybaz import NameParser as NameParser
43
from pybaz.backends.baz import null_cmd
46
from fai import iter_new_merges, direct_merges
54
import bzrlib.inventory
58
from progress import *
60
class ImportCommitReporter(NullCommitReporter):
62
def escaped(self, escape_count, message):
63
bzrlib.trace.warning("replaced %d control characters in message" %
66
def add_id(files, id=None):
67
"""Adds an explicit id to a list of files.
69
:param files: the name of the file to add an id to
70
:type files: list of str
71
:param id: tag one file using the specified id, instead of generating id
76
args.extend(["--id", id])
82
def make_archive(name, location):
83
pb_location = pybaz.ArchiveLocation(location)
84
pb_location.create_master(pybaz.Archive(name),
85
pybaz.ArchiveLocationParams())
89
>>> q = test_environ()
92
>>> os.path.exists(os.path.join(q, "home", ".arch-params"))
94
>>> teardown_environ(q)
99
saved_dir = os.getcwdu()
100
tdir = tempfile.mkdtemp(prefix="testdir-")
101
os.environ["HOME"] = os.path.join(tdir, "home")
102
os.mkdir(os.environ["HOME"])
103
arch_dir = os.path.join(tdir, "archive_dir")
104
make_archive("test@example.com", arch_dir)
105
work_dir = os.path.join(tdir, "work_dir")
108
pybaz.init_tree(work_dir, "test@example.com/test--test--0")
109
lib_dir = os.path.join(tdir, "lib_dir")
111
pybaz.register_revision_library(lib_dir)
112
pybaz.set_my_id("Test User<test@example.org>")
115
def add_file(path, text, id):
117
>>> q = test_environ()
118
>>> add_file("path with space", "text", "lalala")
119
>>> tree = pybaz.tree_root(".")
120
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
121
>>> ("x_lalala", "path with space") in inv
123
>>> teardown_environ(q)
125
file(path, "wb").write(text)
129
def add_dir(path, id):
131
>>> q = test_environ()
132
>>> add_dir("path with\(sp) space", "lalala")
133
>>> tree = pybaz.tree_root(".")
134
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
135
>>> ("x_lalala", "path with\(sp) space") in inv
137
>>> teardown_environ(q)
142
def teardown_environ(tdir):
146
def timport(tree, summary):
147
msg = tree.log_message()
148
msg["summary"] = summary
151
def commit(tree, summary):
153
>>> q = test_environ()
154
>>> tree = pybaz.tree_root(".")
155
>>> timport(tree, "import")
156
>>> commit(tree, "commit")
157
>>> logs = [str(l.revision) for l in tree.iter_logs()]
161
'test@example.com/test--test--0--base-0'
163
'test@example.com/test--test--0--patch-1'
164
>>> teardown_environ(q)
166
msg = tree.log_message()
167
msg["summary"] = summary
170
def commit_test_revisions():
172
>>> q = test_environ()
173
>>> commit_test_revisions()
174
>>> a = pybaz.Archive("test@example.com")
175
>>> revisions = list(a.iter_revisions("test--test--0"))
178
>>> str(revisions[2])
179
'test@example.com/test--test--0--base-0'
180
>>> str(revisions[1])
181
'test@example.com/test--test--0--patch-1'
182
>>> str(revisions[0])
183
'test@example.com/test--test--0--patch-2'
184
>>> teardown_environ(q)
186
tree = pybaz.tree_root(".")
187
add_file("mainfile", "void main(void){}", "mainfile by aaron")
188
timport(tree, "Created mainfile")
189
file("mainfile", "wb").write("or something like that")
190
commit(tree, "altered mainfile")
191
add_file("ofile", "this is another file", "ofile by aaron")
192
commit(tree, "altered mainfile")
195
def commit_more_test_revisions():
197
>>> q = test_environ()
198
>>> commit_test_revisions()
199
>>> commit_more_test_revisions()
200
>>> a = pybaz.Archive("test@example.com")
201
>>> revisions = list(a.iter_revisions("test--test--0"))
204
>>> str(revisions[0])
205
'test@example.com/test--test--0--patch-3'
206
>>> teardown_environ(q)
208
tree = pybaz.tree_root(".")
209
add_file("trainfile", "void train(void){}", "trainfile by aaron")
210
commit(tree, "altered trainfile")
212
class NoSuchVersion(Exception):
213
def __init__(self, version):
214
Exception.__init__(self, "The version %s does not exist." % version)
215
self.version = version
217
def version_ancestry(version):
219
>>> q = test_environ()
220
>>> commit_test_revisions()
221
>>> version = pybaz.Version("test@example.com/test--test--0")
222
>>> ancestors = version_ancestry(version)
223
>>> str(ancestors[0])
224
'test@example.com/test--test--0--base-0'
225
>>> str(ancestors[1])
226
'test@example.com/test--test--0--patch-1'
227
>>> version = pybaz.Version("test@example.com/test--test--0.5")
228
>>> ancestors = version_ancestry(version)
229
Traceback (most recent call last):
230
NoSuchVersion: The version test@example.com/test--test--0.5 does not exist.
231
>>> teardown_environ(q)
234
revision = version.iter_revisions(reverse=True).next()
235
except StopIteration:
239
if not version.exists():
240
raise NoSuchVersion(version)
243
ancestors = list(revision.iter_ancestors(metoo=True))
247
def get_last_revision(branch):
248
last_patch = branch.last_revision()
250
return arch_revision(last_patch)
251
except NotArchRevision:
253
"Directory \"%s\" already exists, and the last revision is not"
254
" an Arch revision (%s)" % (branch.base, last_patch))
256
def do_branch(br_from, to_location, revision_id):
257
"""Derived from branch in builtins."""
261
os.mkdir(to_location)
263
if e.errno == errno.EEXIST:
264
raise UserError('Target directory "%s" already'
265
' exists.' % to_location)
266
if e.errno == errno.ENOENT:
267
raise UserError('Parent of "%s" does not exist.' %
272
br_from.bzrdir.clone(to_location, revision_id)
273
except NoSuchRevision:
275
msg = "The branch %s has no revision %s." % (from_location,
281
def get_remaining_revisions(output_dir, version, reuse_history_from=[]):
284
output_exists = os.path.exists(output_dir)
286
# We are starting from an existing directory, figure out what
287
# the current version is
288
branch = Branch.open(output_dir)
289
last_patch = get_last_revision(branch)
290
if last_patch is None:
291
if branch.last_revision() != None:
292
raise NotPreviousImport(branch.base)
293
elif version is None:
294
version = last_patch.version
295
elif version is None:
296
raise UserError("No version specified, and directory does not exist.")
299
ancestors = version_ancestry(version)
300
if not output_exists and reuse_history_from != []:
301
for ancestor in reversed(ancestors):
302
if last_patch is not None:
303
# found something to copy
305
# try to grab a copy of ancestor
306
# note that is not optimised: we could look for namespace
307
# transitions and only look for the past after the
309
for history_root in reuse_history_from:
310
possible_source = os.path.join(history_root,
311
map_namespace(ancestor.version))
313
source = Branch.open(possible_source)
314
rev_id = revision_id(ancestor)
315
if rev_id in source.revision_history():
316
do_branch(source, output_dir, rev_id)
317
last_patch = ancestor
319
except NotBranchError:
321
except NoSuchVersion, e:
322
raise UserError(str(e))
325
for i in range(len(ancestors)):
326
if ancestors[i] == last_patch:
329
raise UserError("Directory \"%s\" already exists, and the last "
330
"revision (%s) is not in the ancestry of %s" %
331
(output_dir, last_patch, version))
332
# Strip off all of the ancestors which are already present
333
# And get a directory starting with the latest ancestor
334
latest_ancestor = ancestors[i]
335
old_revno = Branch.open(output_dir).revno()
336
ancestors = ancestors[i+1:]
337
return ancestors, old_revno
340
###class Importer(object):
343
### Currently this is used as a parameter object, though more behaviour is
347
### def __init__(self, output_dir, version, fast=False,
348
### verbose=False, dry_run=False, max_count=None,
349
### reuse_history_from=[]):
350
### self.output_dir = output_dir
351
### self.version = version
355
def import_version(output_dir, version, fast=False,
356
verbose=False, dry_run=False, max_count=None,
357
reuse_history_from=[], standalone=True):
359
>>> q = test_environ()
361
Progress bars output to stderr, but doctest does not capture that.
363
>>> old_stderr = sys.stderr
364
>>> sys.stderr = sys.stdout
366
>>> result_path = os.path.join(q, "result")
367
>>> commit_test_revisions()
368
>>> version = pybaz.Version("test@example.com/test--test--0.1")
369
>>> old_ui = bzrlib.ui.ui_factory
370
>>> bzrlib.ui.ui_factory = bzrlib.ui.text.TextUIFactory(
371
... bar_type=bzrlib.progress.DotsProgressBar)
373
>>> import_version('/', version, dry_run=True)
374
Traceback (most recent call last):
375
NotPreviousImport: / is not the location of a previous import.
376
>>> import_version(result_path, version, dry_run=True)
377
Traceback (most recent call last):
378
UserError: The version test@example.com/test--test--0.1 does not exist.
379
>>> version = pybaz.Version("test@example.com/test--test--0")
380
>>> import_version(result_path, version, dry_run=True) #doctest: +ELLIPSIS
381
importing test@example.com/test--test--0 into ...
383
revisions: ..........................................
384
Dry run, not modifying output_dir
386
>>> import_version(result_path, version) #doctest: +ELLIPSIS
387
importing test@example.com/test--test--0 into ...
389
revisions: .....................................................................
392
>>> import_version(result_path, version) #doctest: +ELLIPSIS
393
Tree is up-to-date with test@example.com/test--test--0--patch-2
394
>>> commit_more_test_revisions()
395
>>> import_version(result_path, version) #doctest: +ELLIPSIS
396
importing test@example.com/test--test--0 into ...
397
revisions: ....................................................
400
>>> bzrlib.ui.ui_factory = old_ui
401
>>> sys.stderr = old_stderr
402
>>> teardown_environ(q)
404
progress_bar = bzrlib.ui.ui_factory.nested_progress_bar()
407
ancestors, old_revno = get_remaining_revisions(output_dir, version,
409
except NotBranchError, e:
410
raise NotPreviousImport(e.path)
411
if old_revno is None and len(ancestors) == 0:
412
progress_bar.note('Version %s has no revisions.' % version)
414
if len(ancestors) == 0:
415
last_revision = get_last_revision(Branch.open(output_dir))
416
progress_bar.note('Tree is up-to-date with %s' % last_revision)
419
progress_bar.note("importing %s into %s" % (version, output_dir))
421
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
422
dir=os.path.dirname(output_dir))
424
wt = WorkingTree.open(output_dir)
425
except (NotBranchError, NoWorkingTree):
428
old_basis = EmptyTree()
430
old_basis = wt.basis_tree()
432
for result in iter_import_version(output_dir, ancestors, tempdir,
434
fast=fast, verbose=verbose, dry_run=dry_run,
435
max_count=max_count, standalone=standalone):
436
show_progress(progress_bar, result)
438
progress_bar.note('Dry run, not modifying output_dir')
441
# Update the working tree of the branch
443
wt = WorkingTree.open(output_dir)
444
except NoWorkingTree:
447
wt.set_last_revision(wt.branch.last_revision())
448
merge_inner(wt.branch, wt.basis_tree(), old_basis,
449
ignore_zero=True, this_tree=wt)
454
progress_bar.note('Cleaning up')
455
shutil.rmtree(tempdir)
456
progress_bar.note("Import complete.")
458
progress_bar.finished()
460
class UserError(BzrCommandError):
461
def __init__(self, message):
462
"""Exception to throw when a user makes an impossible request
463
:param message: The message to emit when printing this exception
464
:type message: string
466
BzrCommandError.__init__(self, message)
468
class NotPreviousImport(UserError):
469
def __init__(self, path):
470
UserError.__init__(self, "%s is not the location of a previous import."
474
def revision_id(arch_revision):
476
Generate a Bzr revision id from an Arch revision id. 'x' in the id
477
designates a revision imported with an experimental algorithm. A number
478
would indicate a particular standardized version.
480
:param arch_revision: The Arch revision to generate an ID for.
482
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
483
'Arch-1:you@example.com%cat--br--0--base-0'
485
return "Arch-1:%s" % str(arch_revision).replace('/', '%')
487
class NotArchRevision(Exception):
488
def __init__(self, revision_id):
489
msg = "The revision id %s does not look like it came from Arch."\
491
Exception.__init__(self, msg)
493
def arch_revision(revision_id):
495
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0"))
496
Traceback (most recent call last):
497
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0 does not look like it came from Arch.
498
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
499
Traceback (most recent call last):
500
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
501
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
502
'jrandom@example.com/test--test--0--patch-5'
504
if revision_id is None:
506
if revision_id[:7] != 'Arch-1:':
507
raise NotArchRevision(revision_id)
510
return pybaz.Revision(revision_id[7:].replace('%', '/'))
511
except pybaz.errors.NamespaceError, e:
512
raise NotArchRevision(revision_id)
515
def create_shared_repository(output_dir):
516
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
517
bd.create_repository(shared=True)
519
def create_branch(output_dir):
521
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
522
return bd.create_branch()
525
def create_checkout(source, to_location, revision_id=None):
526
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
527
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
528
return checkout.create_workingtree(revision_id)
531
def create_checkout_metadata(source, to_location, revision_id=None):
532
if revision_id is None:
533
revision_id = source.last_revision()
534
wt = create_checkout(source, to_location, NULL_REVISION)
535
wt.set_last_revision(revision_id)
536
wt._write_inventory(wt.basis_tree().inventory)
540
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
541
verbose=False, dry_run=False, max_count=None,
545
# Uncomment this for testing, it basically just has baz2bzr only update
546
# 5 patches at a time
548
ancestors = ancestors[:max_count]
550
# Not sure if I want this output. basically it tells you ahead of time
551
# what it is going to do, but then later it tells you as it is doing it.
552
# what probably would be best would be to collapse it into ranges, so that
553
# this gives the simple view, and then later it gives the blow by blow.
555
# print 'Adding the following revisions:'
556
# for a in ancestors:
559
previous_version=None
560
missing_ancestor = None
562
dry_output_dir = os.path.join(tempdir, 'od')
563
if os.path.exists(output_dir):
564
shutil.copytree(output_dir, dry_output_dir)
565
output_dir = dry_output_dir
567
if os.path.exists(output_dir):
568
target_branch = Branch.open(output_dir)
571
wt = BzrDir.create_standalone_workingtree(output_dir)
572
target_branch = wt.branch
574
target_branch = create_branch(output_dir)
576
for i in range(len(ancestors)):
577
revision = ancestors[i]
578
rev_id = revision_id(revision)
581
version = str(revision.version)
582
if version != previous_version:
583
pb.note('On version: %s' % version)
584
yield Progress(str(revision.patchlevel), i, len(ancestors))
585
previous_version = version
587
yield Progress("revisions", i, len(ancestors))
589
if target_branch.repository.has_revision(rev_id):
590
target_branch.append_revision(rev_id)
593
revdir = os.path.join(tempdir, "rd")
595
tree, baz_inv, log = get_revision(revdir, revision)
596
except pybaz.errors.ExecProblem, e:
597
if ("%s" % e.args).find('could not connect') == -1:
599
missing_ancestor = revision
601
pb.note("unable to access ancestor %s, making into a merge."
604
target_tree = create_checkout_metadata(target_branch, revdir)
605
branch = target_tree.branch
607
old = os.path.join(revdir, ".bzr")
608
new = os.path.join(tempdir, ".bzr")
610
baz_inv, log = apply_revision(tree, revision)
612
target_tree = WorkingTree.open(revdir)
613
branch = target_tree.branch
614
# cached so we can delete the log
616
log_summary = log.summary
617
log_description = log.description
618
is_continuation = log.continuation_of is not None
619
log_creator = log.creator
620
direct_merges = get_direct_merges(revdir, revision, log)
622
timestamp = email.Utils.mktime_tz(log_date + (0,))
623
if log_summary is None:
625
# log_descriptions of None and "" are ignored.
626
if not is_continuation and log_description:
627
log_message = "\n".join((log_summary, log_description))
629
log_message = log_summary
630
target_tree.lock_write()
634
# if we want it to be in revision-history, do that here.
635
target_tree.add_pending_merge(revision_id(missing_ancestor))
636
missing_ancestor = None
637
for merged_rev in direct_merges:
638
target_tree.add_pending_merge(revision_id(merged_rev))
639
target_tree.set_inventory(baz_inv)
640
commitobj = Commit(reporter=ImportCommitReporter())
641
commitobj.commit(working_tree=target_tree,
642
message=log_message.decode('ascii', 'replace'),
643
verbose=False, committer=log_creator,
644
timestamp=timestamp, timezone=0, rev_id=rev_id,
649
yield Progress("revisions", len(ancestors), len(ancestors))
651
def get_direct_merges(revdir, revision, log):
652
continuation = log.continuation_of
653
previous_version = revision.version
654
if pybaz.WorkingTree(revdir).tree_version != previous_version:
655
pybaz.WorkingTree(revdir).set_tree_version(previous_version)
656
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
657
revision.category.nonarch, revision.branch.nonarch,
658
revision.version.nonarch, revision.archive, revision.patchlevel)
659
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
660
os.rename(log_path, temp_path)
661
merges = list(iter_new_merges(revdir, revision.version))
662
direct = direct_merges(merges, [continuation])
663
os.rename(temp_path, log_path)
666
def unlink_unversioned(wt):
667
for unversioned in wt.extras():
668
path = wt.abspath(unversioned)
669
if os.path.isdir(path):
674
def get_log(tree, revision):
675
log = pybaz.Patchlog(revision, tree=tree)
676
assert str(log.revision) == str(revision), (log.revision, revision)
679
def get_revision(revdir, revision):
680
tree = revision.get(revdir)
681
log = get_log(tree, revision)
683
return tree, bzr_inventory_data(tree), log
684
except BadFileKind, e:
685
raise UserError("Cannot convert %s because %s is a %s" %
686
(revision,e.path, e.kind))
689
def apply_revision(tree, revision):
691
log = get_log(tree, revision)
693
return bzr_inventory_data(tree), log
694
except BadFileKind, e:
695
raise UserError("Cannot convert %s because %s is a %s" %
696
(revision,e.path, e.kind))
699
class BadFileKind(Exception):
700
"""The file kind is not permitted in bzr inventories"""
701
def __init__(self, tree_root, path, kind):
702
self.tree_root = tree_root
705
Exception.__init__(self, "File %s is of forbidden type %s" %
706
(os.path.join(tree_root, path), kind))
709
def bzr_inventory_data(tree):
710
inv_iter = tree.iter_inventory_ids(source=True, both=True)
712
for arch_id, path in inv_iter:
713
bzr_file_id = map_file_id(arch_id)
714
inv_map[path] = bzr_file_id
717
for path, file_id in inv_map.iteritems():
718
full_path = os.path.join(tree, path)
719
kind = bzrlib.osutils.file_kind(full_path)
720
if kind not in ("file", "directory", "symlink"):
721
raise BadFileKind(tree, path, kind)
722
parent_dir = os.path.dirname(path)
724
parent_id = inv_map[parent_dir]
726
parent_id = bzrlib.inventory.ROOT_ID
727
bzr_inv.append((path, file_id, parent_id, kind))
731
_global_option('max-count', type = int)
732
class cmd_baz_import_branch(Command):
733
"""Import an Arch or Baz branch into a bzr branch. <BZRTOOLS>"""
734
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
735
takes_options = ['verbose', 'max-count']
737
def run(self, to_location, from_branch=None, fast=False, max_count=None,
738
verbose=False, dry_run=False, reuse_history_list=[]):
739
to_location = os.path.realpath(str(to_location))
740
if from_branch is not None:
742
from_branch = pybaz.Version(from_branch)
743
except pybaz.errors.NamespaceError:
744
print "%s is not a valid Arch branch." % from_branch
746
if reuse_history_list is None:
747
reuse_history_list = []
748
import_version(to_location, from_branch,
750
reuse_history_from=reuse_history_list)
753
class NotInABranch(Exception):
754
def __init__(self, path):
755
Exception.__init__(self, "%s is not in a branch." % path)
759
class cmd_baz_import(Command):
760
"""Import an Arch or Baz archive into a bzr repository. <BZRTOOLS>
762
This command should be used on local archives (or mirrors) only. It is
763
quite slow on remote archives.
765
reuse_history allows you to specify any previous imports you
766
have done of different archives, which this archive has branches
767
tagged from. This will dramatically reduce the time to convert
768
the archive as it will not have to convert the history already
769
converted in that other branch.
771
If you specify prefixes, only branches whose names start with that prefix
772
will be imported. Skipped branches will be listed, so you can import any
773
branches you missed by accident. Here's an example of doing a partial
774
import from thelove@canonical.com:
775
bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
777
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
778
takes_options = ['verbose', Option('prefixes', type=str,
779
help="Prefixes of branches to import, colon-separated")]
781
def run(self, to_root_dir, from_archive, verbose=False,
782
reuse_history_list=[], prefixes=None):
783
if reuse_history_list is None:
784
reuse_history_list = []
785
to_root = str(os.path.realpath(to_root_dir))
786
if not os.path.exists(to_root):
788
if prefixes is not None:
789
prefixes = prefixes.split(':')
790
import_archive(to_root, from_archive, verbose,
791
reuse_history_list, prefixes=prefixes)
794
def import_archive(to_root, from_archive, verbose,
795
reuse_history_from=[], standalone=False,
797
def selected(version):
801
for prefix in prefixes:
802
if version.nonarch.startswith(prefix):
805
real_to = os.path.realpath(to_root)
806
history_locations = [real_to] + reuse_history_from
807
if standalone is False:
809
bd = BzrDir.open(to_root)
811
except NotBranchError:
812
create_shared_repository(to_root)
813
except NoRepositoryPresent:
814
raise BzrCommandError("Can't create repository at existing branch.")
815
versions = list(pybaz.Archive(str(from_archive)).iter_versions())
816
progress_bar = bzrlib.ui.ui_factory.nested_progress_bar()
818
for num, version in enumerate(versions):
819
progress_bar.update("Branch", num, len(versions))
820
if not selected(version):
821
print "Skipping %s" % version
823
target = os.path.join(to_root, map_namespace(version))
824
if not os.path.exists(os.path.dirname(target)):
825
os.makedirs(os.path.dirname(target))
827
import_version(target, version,
828
reuse_history_from=reuse_history_from,
829
standalone=standalone)
830
except pybaz.errors.ExecProblem,e:
831
if str(e).find('The requested revision cannot be built.') != -1:
833
"Skipping version %s as it cannot be built due"
834
" to a missing parent archive." % version)
838
if str(e).find('already exists, and the last revision ') != -1:
840
"Skipping version %s as it has had commits made"
841
" since it was converted to bzr." % version)
845
progress_bar.finished()
848
def map_namespace(a_version):
849
a_version = pybaz.Version("%s" % a_version)
850
parser = NameParser(a_version)
851
version = parser.get_version()
852
branch = parser.get_branch()
853
category = parser.get_category()
854
if branch is None or branch == '':
857
return "%s/%s" % (category, branch)
858
return "%s/%s/%s" % (category, version, branch)
861
def map_file_id(file_id):
862
"""Convert a baz file id to a bzr one."""
863
return file_id.replace('%', '%25').replace('/', '%2f')