345
331
###class Importer(object):
346
332
### """An importer.
348
334
### Currently this is used as a parameter object, though more behaviour is
349
335
### possible later.
352
### def __init__(self, output_dir, version, fast=False,
353
### verbose=False, dry_run=False, max_count=None,
338
### def __init__(self, output_dir, version, printer, fancy=True, fast=False,
339
### verbose=False, dry_run=False, max_count=None,
354
340
### reuse_history_from=[]):
355
341
### self.output_dir = output_dir
356
342
### self.version = version
360
def import_version(output_dir, version, encoding, fast=False,
346
def import_version(output_dir, version, printer, fancy=True, fast=False,
361
347
verbose=False, dry_run=False, max_count=None,
362
reuse_history_from=[], standalone=True):
348
reuse_history_from=[]):
364
350
>>> q = test_environ()
366
Progress bars output to stderr, but doctest does not capture that.
368
>>> old_stderr = sys.stderr
369
>>> sys.stderr = sys.stdout
371
351
>>> result_path = os.path.join(q, "result")
372
352
>>> commit_test_revisions()
373
353
>>> version = pybaz.Version("test@example.com/test--test--0.1")
374
>>> old_ui = bzrlib.ui.ui_factory
375
>>> bzrlib.ui.ui_factory = bzrlib.ui.text.TextUIFactory(
376
... bar_type=bzrlib.progress.DotsProgressBar)
378
>>> import_version('/', version, None, dry_run=True)
354
>>> def printer(message): print message
355
>>> import_version('/', version, printer, fancy=False, dry_run=True)
379
356
Traceback (most recent call last):
380
357
NotPreviousImport: / is not the location of a previous import.
381
>>> import_version(result_path, version, None, dry_run=True)
358
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
382
359
Traceback (most recent call last):
383
360
UserError: The version test@example.com/test--test--0.1 does not exist.
384
361
>>> version = pybaz.Version("test@example.com/test--test--0")
385
>>> import_version(result_path, version, None, dry_run=True) #doctest: +ELLIPSIS
386
importing test@example.com/test--test--0 into ...
388
revisions: ..........................................
362
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
389
365
Dry run, not modifying output_dir
391
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
392
importing test@example.com/test--test--0 into ...
394
revisions: .....................................................................
367
>>> import_version(result_path, version, printer, fancy=False)
397
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
372
>>> import_version(result_path, version, printer, fancy=False)
398
373
Tree is up-to-date with test@example.com/test--test--0--patch-2
399
374
>>> commit_more_test_revisions()
400
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
401
importing test@example.com/test--test--0 into ...
402
revisions: ....................................................
375
>>> import_version(result_path, version, printer, fancy=False)
405
>>> bzrlib.ui.ui_factory = old_ui
406
>>> sys.stderr = old_stderr
407
380
>>> teardown_environ(q)
409
progress_bar = bzrlib.ui.ui_factory.nested_progress_bar()
412
ancestors, old_revno = get_remaining_revisions(output_dir, version,
415
except NotBranchError, e:
416
raise NotPreviousImport(e.path)
417
if old_revno is None and len(ancestors) == 0:
418
progress_bar.note('Version %s has no revisions.' % version)
420
if len(ancestors) == 0:
421
last_revision, last_encoding = \
422
get_last_revision(Branch.open(output_dir))
423
progress_bar.note('Tree is up-to-date with %s' % last_revision)
426
progress_bar.note("importing %s into %s" % (version, output_dir))
428
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
429
dir=os.path.dirname(output_dir))
431
wt = WorkingTree.open(output_dir)
432
except (NotBranchError, NoWorkingTree):
383
ancestors, old_revno = get_remaining_revisions(output_dir, version,
385
except NotBranchError, e:
386
raise NotPreviousImport(e.path)
387
if old_revno is None and len(ancestors) == 0:
388
print 'Version %s has no revisions.' % version
390
if len(ancestors) == 0:
391
last_revision = get_last_revision(Branch.open(output_dir))
392
print 'Tree is up-to-date with %s' % last_revision
395
progress_bar = ProgressBar()
396
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
397
dir=os.path.dirname(output_dir))
435
402
for result in iter_import_version(output_dir, ancestors, tempdir,
436
pb=progress_bar, encoding=encoding, fast=fast,
437
verbose=verbose, dry_run=dry_run, max_count=max_count,
438
standalone=standalone):
439
show_progress(progress_bar, result)
441
progress_bar.note('Dry run, not modifying output_dir')
444
# Update the working tree of the branch
446
wt = WorkingTree.open(output_dir)
447
except NoWorkingTree:
450
wt.set_last_revision(wt.branch.last_revision())
451
wt.set_root_id(BAZ_IMPORT_ROOT)
403
progress_bar, fast=fast, verbose=verbose, dry_run=dry_run,
404
max_count=max_count):
406
show_progress(progress_bar, result)
408
sys.stdout.write('.')
456
progress_bar.note('Cleaning up')
457
shutil.rmtree(tempdir)
458
progress_bar.note("Import complete.")
413
sys.stdout.write('\n')
416
print 'Dry run, not modifying output_dir'
418
if os.path.exists(output_dir):
419
# Move the bzr control directory back, and update the working tree
420
revdir = os.path.join(tempdir, "rd")
421
if os.path.exists(revdir):
422
# actual imports were done
423
tmp_bzr_dir = os.path.join(tempdir, '.bzr')
425
bzr_dir = os.path.join(output_dir, '.bzr')
426
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
428
# Move the original bzr out of the way
429
os.rename(bzr_dir, tmp_bzr_dir)
430
os.rename(new_bzr_dir, bzr_dir)
432
WorkingTree.open_containing(output_dir)[0].revert([])
434
# If something failed, move back the original bzr directory
435
os.rename(bzr_dir, new_bzr_dir)
436
os.rename(tmp_bzr_dir, bzr_dir)
439
# no imports - perhaps just append_revisions
441
WorkingTree.open_containing(output_dir)[0].revert([])
443
revdir = os.path.join(tempdir, "rd")
444
os.rename(revdir, output_dir)
460
progress_bar.finished()
447
printer('Cleaning up')
448
shutil.rmtree(tempdir)
449
printer("Import complete.")
462
451
class UserError(BzrCommandError):
463
452
def __init__(self, message):
464
453
"""Exception to throw when a user makes an impossible request
506
489
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
507
490
Traceback (most recent call last):
508
491
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
509
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5")[0])
510
'jrandom@example.com/test--test--0--patch-5'
511
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5")[0])
512
'jrandom@example.com/test--test--0--patch-5'
513
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5")[1])
515
>>> str(arch_revision("Arch-1-utf-8:jrandom@example.com%test--test--0--patch-5")[1])
492
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
493
'jrandom@example.com/test--test--0--patch-5'
518
495
if revision_id is None:
520
if revision_id[:7] not in ('Arch-1:', 'Arch-1-'):
497
if revision_id[:7] != 'Arch-1:':
521
498
raise NotArchRevision(revision_id)
524
encoding, arch_name = revision_id[6:].split(':', 1)
525
arch_name = arch_name.replace('%', '/')
529
encoding = encoding[1:]
530
return pybaz.Revision(arch_name), encoding
501
return pybaz.Revision(revision_id[7:].replace('%', '/'))
531
502
except pybaz.errors.NamespaceError, e:
532
503
raise NotArchRevision(revision_id)
535
def create_shared_repository(output_dir):
536
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
537
bd.create_repository(shared=True)
539
def create_branch(output_dir):
541
bd = bzrdir.BzrDirMetaFormat1().initialize(output_dir)
542
return bd.create_branch()
545
def create_checkout(source, to_location, revision_id=None):
546
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
547
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
548
return checkout.create_workingtree(revision_id)
551
def create_checkout_metadata(source, to_location, revision_id=None):
552
if revision_id is None:
553
revision_id = source.last_revision()
554
wt = create_checkout(source, to_location, NULL_REVISION)
557
wt.set_last_revision(revision_id)
559
if revision_id not in (NULL_REVISION, None):
560
basis = wt.basis_tree()
563
wt._write_inventory(basis.inventory)
571
def iter_import_version(output_dir, ancestors, tempdir, pb, encoding,
572
fast=False, verbose=False, dry_run=False,
573
max_count=None, standalone=False):
505
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
506
verbose=False, dry_run=False, max_count=None):
575
log_encoding = 'ascii'
576
if encoding is not None:
577
log_encoding = encoding
579
509
# Uncomment this for testing, it basically just has baz2bzr only update
580
510
# 5 patches at a time
593
523
previous_version=None
594
524
missing_ancestor = None
596
dry_output_dir = os.path.join(tempdir, 'od')
597
if os.path.exists(output_dir):
598
shutil.copytree(output_dir, dry_output_dir)
599
output_dir = dry_output_dir
601
if os.path.exists(output_dir):
602
target_branch = Branch.open(output_dir)
605
wt = BzrDir.create_standalone_workingtree(output_dir)
606
target_branch = wt.branch
608
target_branch = create_branch(output_dir)
610
526
for i in range(len(ancestors)):
611
527
revision = ancestors[i]
612
rev_id = revision_id(revision, encoding)
528
rev_id = revision_id(revision)
613
529
direct_merges = []
615
531
version = str(revision.version)
616
532
if version != previous_version:
617
pb.note('On version: %s' % version)
534
print '\rOn version: %s' % version
618
535
yield Progress(str(revision.patchlevel), i, len(ancestors))
619
536
previous_version = version
621
538
yield Progress("revisions", i, len(ancestors))
623
if target_branch.repository.has_revision(rev_id):
624
target_branch.append_revision(rev_id)
539
if revdir is None and os.path.exists(output_dir):
540
# check for imported revisions and if present just append
542
target_tree = WorkingTree.open(output_dir)
543
branch = target_tree.branch
544
if branch.repository.has_revision(rev_id):
545
branch.append_revision(rev_id)
626
547
if revdir is None:
627
548
revdir = os.path.join(tempdir, "rd")
633
554
missing_ancestor = revision
635
pb.note("unable to access ancestor %s, making into a merge."
556
print ("unable to access ancestor %s, making into a merge."
636
557
% missing_ancestor)
638
target_tree = create_checkout_metadata(target_branch, revdir)
639
branch = target_tree.branch
559
if os.path.exists(output_dir):
560
bzr_dir = os.path.join(output_dir, '.bzr')
561
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
562
# This would be much faster with a simple os.rename(), but if
563
# we fail, we have corrupted the original .bzr directory. Is
564
# that a big problem, as we can just back out the last
565
# revisions in .bzr/revision_history I don't really know
566
# RBC20051024 - yes, it would be a problem as we could not then
567
# apply the corrupted revision.
568
shutil.copytree(bzr_dir, new_bzr_dir)
569
# Now revdir should have a tree with the latest .bzr, and the
570
# next revision of the baz tree
571
target_tree = WorkingTree.open(revdir)
572
branch = target_tree.branch
574
target_tree = BzrDir.create_standalone_workingtree(revdir)
575
branch = target_tree.branch
641
577
old = os.path.join(revdir, ".bzr")
642
578
new = os.path.join(tempdir, ".bzr")
667
603
if missing_ancestor:
668
604
# if we want it to be in revision-history, do that here.
669
target_tree.set_parent_ids(
670
[revision_id(missing_ancestor, encoding)],
671
allow_leftmost_as_ghost=True)
605
target_tree.add_pending_merge(revision_id(missing_ancestor))
672
606
missing_ancestor = None
673
607
for merged_rev in direct_merges:
674
target_tree.add_pending_merge(revision_id(merged_rev,
676
target_tree.set_root_id(BAZ_IMPORT_ROOT)
608
target_tree.add_pending_merge(revision_id(merged_rev))
678
609
target_tree.set_inventory(baz_inv)
679
commitobj = Commit(reporter=ImportCommitReporter())
610
commitobj = Commit(reporter=ImportCommitReporter(pb))
680
611
commitobj.commit(working_tree=target_tree,
681
message=log_message.decode(log_encoding, 'replace'),
682
verbose=False, committer=log_creator, timestamp=timestamp,
683
timezone=0, rev_id=rev_id, revprops={})
612
message=log_message.decode('ascii', 'replace'),
613
verbose=False, committer=log_creator,
614
timestamp=timestamp, timezone=0, rev_id=rev_id)
685
616
target_tree.unlock()
687
618
yield Progress("revisions", len(ancestors), len(ancestors))
619
unlink_unversioned(target_tree)
689
621
def get_direct_merges(revdir, revision, log):
690
622
continuation = log.continuation_of
691
623
previous_version = revision.version
692
624
if pybaz.WorkingTree(revdir).tree_version != previous_version:
693
625
pybaz.WorkingTree(revdir).set_tree_version(previous_version)
694
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
695
revision.category.nonarch, revision.branch.nonarch,
626
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
627
revision.category.nonarch, revision.branch.nonarch,
696
628
revision.version.nonarch, revision.archive, revision.patchlevel)
697
629
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
698
630
os.rename(log_path, temp_path)
770
def baz_import_branch(to_location, from_branch, fast, max_count, verbose,
771
encoding, dry_run, reuse_history_list):
772
to_location = os.path.realpath(str(to_location))
773
if from_branch is not None:
775
from_branch = pybaz.Version(from_branch)
776
except pybaz.errors.NamespaceError:
777
print "%s is not a valid Arch branch." % from_branch
779
if reuse_history_list is None:
780
reuse_history_list = []
781
import_version(to_location, from_branch, encoding, max_count=max_count,
782
reuse_history_from=reuse_history_list)
701
_global_option('max-count', type = int)
702
class cmd_baz_import_branch(Command):
703
"""Import an Arch or Baz branch into a bzr branch"""
704
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
705
takes_options = ['verbose', 'max-count']
707
def printer(self, name):
710
def run(self, to_location, from_branch=None, fast=False, max_count=None,
711
verbose=False, dry_run=False, reuse_history_list=[]):
712
to_location = os.path.realpath(str(to_location))
713
if from_branch is not None:
715
from_branch = pybaz.Version(from_branch)
716
except pybaz.errors.NamespaceError:
717
print "%s is not a valid Arch branch." % from_branch
719
if reuse_history_list is None:
720
reuse_history_list = []
721
import_version(to_location, from_branch, self.printer,
723
reuse_history_from=reuse_history_list)
785
726
class NotInABranch(Exception):
792
def baz_import(to_root_dir, from_archive, encoding, verbose=False,
793
reuse_history_list=[], prefixes=None):
794
if reuse_history_list is None:
795
reuse_history_list = []
796
to_root = str(os.path.realpath(to_root_dir))
797
if not os.path.exists(to_root):
799
if prefixes is not None:
800
prefixes = prefixes.split(':')
801
import_archive(to_root, from_archive, verbose, encoding,
802
reuse_history_list, prefixes=prefixes)
805
def import_archive(to_root, from_archive, verbose,
806
encoding, reuse_history_from=[], standalone=False,
808
def selected(version):
812
for prefix in prefixes:
813
if version.nonarch.startswith(prefix):
732
class cmd_baz_import(Command):
733
"""Import an Arch or Baz archive into bzr branches.
735
reuse_history allows you to specify any previous imports you
736
have done of different archives, which this archive has branches
737
tagged from. This will dramatically reduce the time to convert
738
the archive as it will not have to convert the history already
739
converted in that other branch.
741
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
742
takes_options = ['verbose']
744
def printer(self, name):
747
def run(self, to_root_dir, from_archive, verbose=False,
748
reuse_history_list=[]):
749
if reuse_history_list is None:
750
reuse_history_list = []
751
to_root = str(os.path.realpath(to_root_dir))
752
if not os.path.exists(to_root):
754
import_archive(to_root, from_archive, verbose, self.printer,
758
def import_archive(to_root, from_archive, verbose, printer,
759
reuse_history_from=[]):
816
760
real_to = os.path.realpath(to_root)
817
761
history_locations = [real_to] + reuse_history_from
818
if standalone is False:
762
for version in pybaz.Archive(str(from_archive)).iter_versions():
763
target = os.path.join(to_root, map_namespace(version))
764
printer("importing %s into %s" % (version, target))
765
if not os.path.exists(os.path.dirname(target)):
766
os.makedirs(os.path.dirname(target))
820
bd = BzrDir.open(to_root)
822
except NotBranchError:
823
create_shared_repository(to_root)
824
except NoRepositoryPresent:
825
raise BzrCommandError("Can't create repository at existing branch.")
826
versions = list(pybaz.Archive(str(from_archive)).iter_versions())
827
progress_bar = bzrlib.ui.ui_factory.nested_progress_bar()
829
for num, version in enumerate(versions):
830
progress_bar.update("Branch", num, len(versions))
831
if not selected(version):
832
print "Skipping %s" % version
834
target = os.path.join(to_root, map_namespace(version))
835
if not os.path.exists(os.path.dirname(target)):
836
os.makedirs(os.path.dirname(target))
838
import_version(target, version, encoding,
839
reuse_history_from=reuse_history_from,
840
standalone=standalone)
841
except pybaz.errors.ExecProblem,e:
842
if str(e).find('The requested revision cannot be built.') != -1:
844
"Skipping version %s as it cannot be built due"
768
import_version(target, version, printer,
769
reuse_history_from=reuse_history_from)
770
except pybaz.errors.ExecProblem,e:
771
if str(e).find('The requested revision cannot be built.') != -1:
772
printer("Skipping version %s as it cannot be built due"
845
773
" to a missing parent archive." % version)
849
if str(e).find('already exists, and the last revision ') != -1:
851
"Skipping version %s as it has had commits made"
777
if str(e).find('already exists, and the last revision ') != -1:
778
printer("Skipping version %s as it has had commits made"
852
779
" since it was converted to bzr." % version)
856
progress_bar.finished()
859
784
def map_namespace(a_version):