333
248
# Strip off all of the ancestors which are already present
334
249
# And get a directory starting with the latest ancestor
335
250
latest_ancestor = ancestors[i]
336
old_revno = Branch.open(output_dir).revno()
251
old_revno = find_branch(output_dir).revno()
337
252
ancestors = ancestors[i+1:]
338
253
return ancestors, old_revno
341
###class Importer(object):
344
### Currently this is used as a parameter object, though more behaviour is
348
### def __init__(self, output_dir, version, printer, fancy=True, fast=False,
349
### verbose=False, dry_run=False, max_count=None,
350
### reuse_history_from=[]):
351
### self.output_dir = output_dir
352
### self.version = version
356
def import_version(output_dir, version, printer, fancy=True, fast=False,
357
verbose=False, dry_run=False, max_count=None,
358
reuse_history_from=[], standalone=True):
255
def import_version(output_dir, version, fancy=True, fast=False, verbose=False,
256
dry_run=False, max_count=None, skip_symlinks=False):
360
258
>>> q = test_environ()
361
259
>>> result_path = os.path.join(q, "result")
362
260
>>> commit_test_revisions()
363
261
>>> version = pybaz.Version("test@example.com/test--test--0.1")
364
>>> def printer(message): print message
365
>>> import_version('/', version, printer, fancy=False, dry_run=True)
262
>>> import_version('/', version, fancy=False, dry_run=True)
366
263
Traceback (most recent call last):
367
NotPreviousImport: / is not the location of a previous import.
368
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
264
UserError: / exists, but is not a bzr branch.
265
>>> import_version(result_path, version, fancy=False, dry_run=True)
369
266
Traceback (most recent call last):
370
267
UserError: The version test@example.com/test--test--0.1 does not exist.
371
268
>>> version = pybaz.Version("test@example.com/test--test--0")
372
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
269
>>> import_version(result_path, version, fancy=False, dry_run=True)
375
272
Dry run, not modifying output_dir
377
>>> import_version(result_path, version, printer, fancy=False)
274
>>> import_version(result_path, version, fancy=False)
382
>>> import_version(result_path, version, printer, fancy=False)
279
>>> import_version(result_path, version, fancy=False)
383
280
Tree is up-to-date with test@example.com/test--test--0--patch-2
384
281
>>> commit_more_test_revisions()
385
>>> import_version(result_path, version, printer, fancy=False)
282
>>> import_version(result_path, version, fancy=False)
390
287
>>> teardown_environ(q)
393
ancestors, old_revno = get_remaining_revisions(output_dir, version,
395
except NotBranchError, e:
290
ancestors, old_revno = get_remaining_revisions(output_dir, version)
291
except NotInABranch, e:
396
292
raise NotPreviousImport(e.path)
397
if old_revno is None and len(ancestors) == 0:
398
print 'Version %s has no revisions.' % version
400
293
if len(ancestors) == 0:
401
last_revision = get_last_revision(Branch.open(output_dir))
294
last_revision = get_last_revision(find_branch(output_dir))
402
295
print 'Tree is up-to-date with %s' % last_revision
405
progress_bar = bzrlib.ui.ui_factory.progress_bar()
298
progress_bar = ProgressBar()
406
299
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
407
300
dir=os.path.dirname(output_dir))
409
wt = WorkingTree.open(output_dir)
410
except (NotBranchError, NoWorkingTree):
413
old_basis = EmptyTree()
415
old_basis = wt.basis_tree()
418
303
print "not fancy"
420
305
for result in iter_import_version(output_dir, ancestors, tempdir,
421
progress_bar, fast=fast, verbose=verbose, dry_run=dry_run,
422
max_count=max_count, standalone=standalone):
306
fast=fast, verbose=verbose, dry_run=dry_run,
307
max_count=max_count, skip_symlinks=skip_symlinks):
424
309
show_progress(progress_bar, result)
434
319
print 'Dry run, not modifying output_dir'
321
if os.path.exists(output_dir):
322
# Move the bzr control directory back, and update the working tree
323
tmp_bzr_dir = os.path.join(tempdir, '.bzr')
325
bzr_dir = os.path.join(output_dir, '.bzr')
326
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
437
# Update the working tree of the branch
439
wt = WorkingTree.open(output_dir)
440
except NoWorkingTree:
443
wt.set_last_revision(wt.branch.last_revision())
444
merge_inner(wt.branch, wt.basis_tree(), old_basis,
445
ignore_zero=True, this_tree=wt)
328
os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way
329
os.rename(new_bzr_dir, bzr_dir)
331
bzrlib.merge.merge((output_dir, -1), (output_dir, old_revno),
332
check_clean=False, this_dir=output_dir,
335
# If something failed, move back the original bzr directory
336
os.rename(bzr_dir, new_bzr_dir)
337
os.rename(tmp_bzr_dir, bzr_dir)
340
revdir = os.path.join(tempdir, "rd")
341
os.rename(revdir, output_dir)
449
printer('Cleaning up')
450
345
shutil.rmtree(tempdir)
451
printer("Import complete.")
346
print "Import complete."
453
348
class UserError(BzrCommandError):
454
349
def __init__(self, message):
486
381
def arch_revision(revision_id):
488
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0"))
489
Traceback (most recent call last):
490
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0 does not look like it came from Arch.
491
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
492
Traceback (most recent call last):
493
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
494
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
383
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0"))
384
Traceback (most recent call last):
385
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0 does not look like it came from Arch.
386
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--base-5"))
387
Traceback (most recent call last):
388
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
389
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--patch-5"))
495
390
'jrandom@example.com/test--test--0--patch-5'
497
392
if revision_id is None:
499
if revision_id[:7] != 'Arch-1:':
394
if revision_id[:7] != 'Arch-x:':
500
395
raise NotArchRevision(revision_id)
503
398
return pybaz.Revision(revision_id[7:].replace('%', '/'))
504
399
except pybaz.errors.NamespaceError, e:
505
400
raise NotArchRevision(revision_id)
508
def create_shared_repository(output_dir):
509
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
510
bd.create_repository(shared=True)
512
def create_branch(output_dir):
514
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
515
return bd.create_branch()
518
def create_checkout(source, to_location, revision_id=None):
519
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
520
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
521
return checkout.create_workingtree(revision_id)
524
def create_checkout_metadata(source, to_location, revision_id=None):
525
if revision_id is None:
526
revision_id = source.last_revision()
527
wt = create_checkout(source, to_location, NULL_REVISION)
528
wt.set_last_revision(revision_id)
529
wt._write_inventory(wt.basis_tree().inventory)
533
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
402
def iter_import_version(output_dir, ancestors, tempdir, fast=False,
534
403
verbose=False, dry_run=False, max_count=None,
404
skip_symlinks=False):
538
407
# Uncomment this for testing, it basically just has baz2bzr only update
579
431
previous_version = version
581
433
yield Progress("revisions", i, len(ancestors))
583
if target_branch.repository.has_revision(rev_id):
584
target_branch.append_revision(rev_id)
586
434
if revdir is None:
587
435
revdir = os.path.join(tempdir, "rd")
589
tree, baz_inv, log = get_revision(revdir, revision)
590
except pybaz.errors.ExecProblem, e:
591
if ("%s" % e.args).find('could not connect') == -1:
593
missing_ancestor = revision
595
print ("unable to access ancestor %s, making into a merge."
598
target_tree = create_checkout_metadata(target_branch, revdir)
599
branch = target_tree.branch
436
baz_inv, log = get_revision(revdir, revision,
437
skip_symlinks=skip_symlinks)
438
if os.path.exists(output_dir):
439
bzr_dir = os.path.join(output_dir, '.bzr')
440
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
441
# This would be much faster with a simple os.rename(), but if
442
# we fail, we have corrupted the original .bzr directory. Is
443
# that a big problem, as we can just back out the last
444
# revisions in .bzr/revision_history I don't really know
445
shutil.copytree(bzr_dir, new_bzr_dir)
446
# Now revdir should have a tree with the latest .bzr, and the
447
# next revision of the baz tree
448
branch = find_branch(revdir)
450
branch = Branch.initialize(revdir)
601
452
old = os.path.join(revdir, ".bzr")
602
453
new = os.path.join(tempdir, ".bzr")
603
454
os.rename(old, new)
604
baz_inv, log = apply_revision(tree, revision)
455
baz_inv, log = apply_revision(revdir, revision,
456
skip_symlinks=skip_symlinks)
605
457
os.rename(new, old)
606
target_tree = WorkingTree.open(revdir)
607
branch = target_tree.branch
608
# cached so we can delete the log
610
log_summary = log.summary
611
log_description = log.description
612
is_continuation = log.continuation_of is not None
613
log_creator = log.creator
614
direct_merges = get_direct_merges(revdir, revision, log)
616
timestamp = email.Utils.mktime_tz(log_date + (0,))
617
if log_summary is None:
619
# log_descriptions of None and "" are ignored.
620
if not is_continuation and log_description:
621
log_message = "\n".join((log_summary, log_description))
623
log_message = log_summary
624
target_tree.lock_write()
458
branch = find_branch(revdir)
459
timestamp = email.Utils.mktime_tz(log.date + (0,))
460
rev_id = revision_id(revision)
625
461
branch.lock_write()
628
# if we want it to be in revision-history, do that here.
629
target_tree.add_pending_merge(revision_id(missing_ancestor))
630
missing_ancestor = None
631
for merged_rev in direct_merges:
632
target_tree.add_pending_merge(revision_id(merged_rev))
633
target_tree.set_inventory(baz_inv)
634
commitobj = Commit(reporter=ImportCommitReporter(pb))
635
commitobj.commit(working_tree=target_tree,
636
message=log_message.decode('ascii', 'replace'),
637
verbose=False, committer=log_creator,
638
timestamp=timestamp, timezone=0, rev_id=rev_id,
463
branch.working_tree().set_inventory(baz_inv)
464
bzrlib.trace.silent = True
465
wt = branch.working_tree()
466
wt.commit(log.summary, verbose=False, committer=log.creator,
467
timestamp=timestamp, timezone=0, rev_id=rev_id)
469
bzrlib.trace.silent = False
643
471
yield Progress("revisions", len(ancestors), len(ancestors))
645
def get_direct_merges(revdir, revision, log):
646
continuation = log.continuation_of
647
previous_version = revision.version
648
if pybaz.WorkingTree(revdir).tree_version != previous_version:
649
pybaz.WorkingTree(revdir).set_tree_version(previous_version)
650
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
651
revision.category.nonarch, revision.branch.nonarch,
652
revision.version.nonarch, revision.archive, revision.patchlevel)
653
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
654
os.rename(log_path, temp_path)
655
merges = list(iter_new_merges(revdir, revision.version))
656
direct = direct_merges(merges, [continuation])
657
os.rename(temp_path, log_path)
660
def unlink_unversioned(wt):
661
for unversioned in wt.extras():
662
path = wt.abspath(unversioned)
472
unlink_unversioned(branch, revdir)
474
def unlink_unversioned(branch, revdir):
475
for unversioned in branch.working_tree().extras():
476
path = os.path.join(revdir, unversioned)
663
477
if os.path.isdir(path):
664
478
shutil.rmtree(path)
668
482
def get_log(tree, revision):
669
log = pybaz.Patchlog(revision, tree=tree)
483
log = tree.iter_logs(version=revision.version, reverse=True).next()
670
484
assert str(log.revision) == str(revision), (log.revision, revision)
673
def get_revision(revdir, revision):
674
tree = revision.get(revdir)
487
def get_revision(revdir, revision, skip_symlinks=False):
489
tree = pybaz.tree_root(revdir)
675
490
log = get_log(tree, revision)
677
return tree, bzr_inventory_data(tree), log
492
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log
678
493
except BadFileKind, e:
679
raise UserError("Cannot convert %s because %s is a %s" %
680
(revision,e.path, e.kind))
683
def apply_revision(tree, revision):
494
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) )
497
def apply_revision(revdir, revision, skip_symlinks=False):
498
tree = pybaz.tree_root(revdir)
684
499
revision.apply(tree)
685
500
log = get_log(tree, revision)
687
return bzr_inventory_data(tree), log
502
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log
688
503
except BadFileKind, e:
689
raise UserError("Cannot convert %s because %s is a %s" %
690
(revision,e.path, e.kind))
504
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) )
693
509
class BadFileKind(Exception):
725
_global_option('max-count', type = int)
726
class cmd_baz_import_branch(Command):
542
class NotInABranch(Exception):
543
def __init__(self, path):
544
Exception.__init__(self, "%s is not in a branch." % path)
548
def find_branch(path):
551
Traceback (most recent call last):
552
NotInABranch: / is not in a branch.
553
>>> sb = bzrlib.ScratchBranch()
554
>>> isinstance(find_branch(sb.base), Branch)
558
return Branch.open(path)
559
except NotBranchError, e:
560
raise NotInABranch(path)
562
class cmd_baz_import(Command):
727
563
"""Import an Arch or Baz branch into a bzr branch"""
728
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
729
takes_options = ['verbose', 'max-count']
731
def printer(self, name):
734
def run(self, to_location, from_branch=None, fast=False, max_count=None,
735
verbose=False, dry_run=False, reuse_history_list=[]):
564
takes_args = ['to_location', 'from_branch?']
565
takes_options = ['verbose']
567
def run(self, to_location, from_branch=None, skip_symlinks=False,
568
fast=False, max_count=None, verbose=False, dry_run=False):
736
569
to_location = os.path.realpath(str(to_location))
737
570
if from_branch is not None:
740
573
except pybaz.errors.NamespaceError:
741
574
print "%s is not a valid Arch branch." % from_branch
743
if reuse_history_list is None:
744
reuse_history_list = []
745
import_version(to_location, from_branch, self.printer,
747
reuse_history_from=reuse_history_list)
750
class NotInABranch(Exception):
751
def __init__(self, path):
752
Exception.__init__(self, "%s is not in a branch." % path)
756
class cmd_baz_import(Command):
757
"""Import an Arch or Baz archive into bzr branches.
759
This command should be used on local archives (or mirrors) only. It is
760
quite slow on remote archives.
762
reuse_history allows you to specify any previous imports you
763
have done of different archives, which this archive has branches
764
tagged from. This will dramatically reduce the time to convert
765
the archive as it will not have to convert the history already
766
converted in that other branch.
768
If you specify prefixes, only branches whose names start with that prefix
769
will be imported. Skipped branches will be listed, so you can import any
770
branches you missed by accident. Here's an example of doing a partial
771
import from thelove@canonical.com:
772
bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
774
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
775
takes_options = ['verbose', Option('prefixes', type=str,
776
help="Prefixes of branches to import, colon-separated")]
778
def printer(self, name):
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, self.printer,
791
reuse_history_list, prefixes=prefixes)
794
def import_archive(to_root, from_archive, verbose, printer,
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
for version in pybaz.Archive(str(from_archive)).iter_versions():
816
if not selected(version):
817
print "Skipping %s" % version
819
target = os.path.join(to_root, map_namespace(version))
820
printer("importing %s into %s" % (version, target))
821
if not os.path.exists(os.path.dirname(target)):
822
os.makedirs(os.path.dirname(target))
824
import_version(target, version, printer,
825
reuse_history_from=reuse_history_from,
826
standalone=standalone)
827
except pybaz.errors.ExecProblem,e:
828
if str(e).find('The requested revision cannot be built.') != -1:
829
printer("Skipping version %s as it cannot be built due"
830
" to a missing parent archive." % version)
834
if str(e).find('already exists, and the last revision ') != -1:
835
printer("Skipping version %s as it has had commits made"
836
" since it was converted to bzr." % version)
841
def map_namespace(a_version):
842
a_version = pybaz.Version("%s" % a_version)
843
parser = NameParser(a_version)
844
version = parser.get_version()
845
branch = parser.get_branch()
846
category = parser.get_category()
847
if branch is None or branch == '':
850
return "%s/%s" % (category, branch)
851
return "%s/%s/%s" % (category, version, branch)
853
def map_file_id(file_id):
854
"""Convert a baz file id to a bzr one."""
855
return file_id.replace('%', '%25').replace('/', '%2f')
576
import_version(to_location, from_branch)