326
345
###class Importer(object):
327
346
### """An importer.
329
348
### Currently this is used as a parameter object, though more behaviour is
330
349
### possible later.
333
### def __init__(self, output_dir, version, printer, fancy=True, fast=False,
334
### verbose=False, dry_run=False, max_count=None,
352
### def __init__(self, output_dir, version, fast=False,
353
### verbose=False, dry_run=False, max_count=None,
335
354
### reuse_history_from=[]):
336
355
### self.output_dir = output_dir
337
356
### self.version = version
341
def import_version(output_dir, version, printer, fancy=True, fast=False,
360
def import_version(output_dir, version, encoding, fast=False,
342
361
verbose=False, dry_run=False, max_count=None,
343
reuse_history_from=[]):
362
reuse_history_from=[], standalone=True):
345
364
>>> 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
346
371
>>> result_path = os.path.join(q, "result")
347
372
>>> commit_test_revisions()
348
373
>>> version = pybaz.Version("test@example.com/test--test--0.1")
349
>>> def printer(message): print message
350
>>> import_version('/', version, printer, fancy=False, dry_run=True)
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)
351
379
Traceback (most recent call last):
352
380
NotPreviousImport: / is not the location of a previous import.
353
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
381
>>> import_version(result_path, version, None, dry_run=True)
354
382
Traceback (most recent call last):
355
383
UserError: The version test@example.com/test--test--0.1 does not exist.
356
384
>>> version = pybaz.Version("test@example.com/test--test--0")
357
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
385
>>> import_version(result_path, version, None, dry_run=True) #doctest: +ELLIPSIS
386
importing test@example.com/test--test--0 into ...
388
revisions: ..........................................
360
389
Dry run, not modifying output_dir
362
>>> import_version(result_path, version, printer, fancy=False)
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
368
398
Tree is up-to-date with test@example.com/test--test--0--patch-2
369
399
>>> commit_more_test_revisions()
370
>>> import_version(result_path, version, printer, fancy=False)
400
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
401
importing test@example.com/test--test--0 into ...
402
revisions: ....................................................
405
>>> bzrlib.ui.ui_factory = old_ui
406
>>> sys.stderr = old_stderr
375
407
>>> teardown_environ(q)
378
ancestors, old_revno = get_remaining_revisions(output_dir, version,
380
except NotBranchError, e:
381
raise NotPreviousImport(e.path)
382
if old_revno is None and len(ancestors) == 0:
383
print 'Version %s has no revisions.' % version
385
if len(ancestors) == 0:
386
last_revision = get_last_revision(Branch.open(output_dir))
387
print 'Tree is up-to-date with %s' % last_revision
390
progress_bar = ProgressBar()
391
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
392
dir=os.path.dirname(output_dir))
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):
397
435
for result in iter_import_version(output_dir, ancestors, tempdir,
398
progress_bar, fast=fast, verbose=verbose, dry_run=dry_run,
399
max_count=max_count):
401
show_progress(progress_bar, result)
403
sys.stdout.write('.')
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)
408
sys.stdout.write('\n')
411
print 'Dry run, not modifying output_dir'
413
if os.path.exists(output_dir):
414
# Move the bzr control directory back, and update the working tree
415
revdir = os.path.join(tempdir, "rd")
416
if os.path.exists(revdir):
417
# actual imports were done
418
tmp_bzr_dir = os.path.join(tempdir, '.bzr')
420
bzr_dir = os.path.join(output_dir, '.bzr')
421
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
423
os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way
424
os.rename(new_bzr_dir, bzr_dir)
426
WorkingTree.open_containing(output_dir)[0].revert([])
428
# If something failed, move back the original bzr directory
429
os.rename(bzr_dir, new_bzr_dir)
430
os.rename(tmp_bzr_dir, bzr_dir)
433
# no imports - perhaps just append_revisions
435
WorkingTree.open_containing(output_dir)[0].revert([])
436
#bzrlib.builtins.merge((output_dir, -1), (output_dir, None), # old_revno),
437
# check_clean=False, this_dir=output_dir,
440
revdir = os.path.join(tempdir, "rd")
441
os.rename(revdir, output_dir)
456
progress_bar.note('Cleaning up')
457
shutil.rmtree(tempdir)
458
progress_bar.note("Import complete.")
444
printer('Cleaning up')
445
shutil.rmtree(tempdir)
446
printer("Import complete.")
460
progress_bar.finished()
448
462
class UserError(BzrCommandError):
449
463
def __init__(self, message):
450
464
"""Exception to throw when a user makes an impossible request
486
506
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
487
507
Traceback (most recent call last):
488
508
NotArchRevision: The revision id Arch-1:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
489
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
490
'jrandom@example.com/test--test--0--patch-5'
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
518
if revision_id is None:
494
if revision_id[:7] != 'Arch-1:':
520
if revision_id[:7] not in ('Arch-1:', 'Arch-1-'):
495
521
raise NotArchRevision(revision_id)
498
return pybaz.Revision(revision_id[7:].replace('%', '/'))
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
499
531
except pybaz.errors.NamespaceError, e:
500
532
raise NotArchRevision(revision_id)
502
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
503
verbose=False, dry_run=False, max_count=None):
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):
575
log_encoding = 'ascii'
576
if encoding is not None:
577
log_encoding = encoding
506
579
# Uncomment this for testing, it basically just has baz2bzr only update
507
580
# 5 patches at a time
520
593
previous_version=None
521
594
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)
523
610
for i in range(len(ancestors)):
524
611
revision = ancestors[i]
525
rev_id = revision_id(revision)
612
rev_id = revision_id(revision, encoding)
526
613
direct_merges = []
528
615
version = str(revision.version)
529
616
if version != previous_version:
531
print '\rOn version: %s' % version
617
pb.note('On version: %s' % version)
532
618
yield Progress(str(revision.patchlevel), i, len(ancestors))
533
619
previous_version = version
535
621
yield Progress("revisions", i, len(ancestors))
536
if revdir is None and os.path.exists(output_dir):
537
# check for imported revisions and if present just append immediately
538
branch = Branch.open(output_dir)
539
if branch.repository.has_revision(rev_id):
540
branch.append_revision(rev_id)
623
if target_branch.repository.has_revision(rev_id):
624
target_branch.append_revision(rev_id)
542
626
if revdir is None:
543
627
revdir = os.path.join(tempdir, "rd")
549
633
missing_ancestor = revision
551
print ("unable to access ancestor %s, making into a merge."
635
pb.note("unable to access ancestor %s, making into a merge."
552
636
% missing_ancestor)
554
if os.path.exists(output_dir):
555
bzr_dir = os.path.join(output_dir, '.bzr')
556
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
557
# This would be much faster with a simple os.rename(), but if
558
# we fail, we have corrupted the original .bzr directory. Is
559
# that a big problem, as we can just back out the last
560
# revisions in .bzr/revision_history I don't really know
561
# RBC20051024 - yes, it would be a problem as we could not then
562
# apply the corrupted revision.
563
shutil.copytree(bzr_dir, new_bzr_dir)
564
# Now revdir should have a tree with the latest .bzr, and the
565
# next revision of the baz tree
566
branch = Branch.open(revdir)
568
branch = Branch.initialize(revdir)
638
target_tree = create_checkout_metadata(target_branch, revdir)
639
branch = target_tree.branch
570
641
old = os.path.join(revdir, ".bzr")
571
642
new = os.path.join(tempdir, ".bzr")
572
643
os.rename(old, new)
573
644
baz_inv, log = apply_revision(tree, revision)
574
645
os.rename(new, old)
575
branch = Branch.open(revdir)
646
target_tree = WorkingTree.open(revdir)
647
branch = target_tree.branch
576
648
# cached so we can delete the log
577
649
log_date = log.date
578
650
log_summary = log.summary
589
661
log_message = "\n".join((log_summary, log_description))
591
663
log_message = log_summary
664
target_tree.lock_write()
592
665
branch.lock_write()
593
target_tree = WorkingTree(revdir ,branch=branch)
594
target_tree.lock_write()
596
667
if missing_ancestor:
597
668
# if we want it to be in revision-history, do that here.
598
target_tree.add_pending_merge(revision_id(missing_ancestor))
669
target_tree.set_parent_ids(
670
[revision_id(missing_ancestor, encoding)],
671
allow_leftmost_as_ghost=True)
599
672
missing_ancestor = None
600
673
for merged_rev in direct_merges:
601
target_tree.add_pending_merge(revision_id(merged_rev))
674
target_tree.add_pending_merge(revision_id(merged_rev,
676
target_tree.set_root_id(BAZ_IMPORT_ROOT)
602
678
target_tree.set_inventory(baz_inv)
603
commitobj = Commit(reporter=ImportCommitReporter(pb))
604
commitobj.commit(branch, log_message.decode('ascii', 'replace'),
605
verbose=False, committer=log_creator,
606
timestamp=timestamp, timezone=0, rev_id=rev_id)
679
commitobj = Commit(reporter=ImportCommitReporter())
680
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={})
608
685
target_tree.unlock()
610
687
yield Progress("revisions", len(ancestors), len(ancestors))
611
unlink_unversioned(branch, revdir)
613
689
def get_direct_merges(revdir, revision, log):
614
690
continuation = log.continuation_of
615
691
previous_version = revision.version
616
692
if pybaz.WorkingTree(revdir).tree_version != previous_version:
617
693
pybaz.WorkingTree(revdir).set_tree_version(previous_version)
618
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
619
revision.category.nonarch, revision.branch.nonarch,
694
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
695
revision.category.nonarch, revision.branch.nonarch,
620
696
revision.version.nonarch, revision.archive, revision.patchlevel)
621
697
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
622
698
os.rename(log_path, temp_path)
691
_global_option('max-count', type = int)
692
class cmd_baz_import_branch(Command):
693
"""Import an Arch or Baz branch into a bzr branch"""
694
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
695
takes_options = ['verbose', 'max-count']
697
def printer(self, name):
700
def run(self, to_location, from_branch=None, fast=False, max_count=None,
701
verbose=False, dry_run=False, reuse_history_list=[]):
702
to_location = os.path.realpath(str(to_location))
703
if from_branch is not None:
705
from_branch = pybaz.Version(from_branch)
706
except pybaz.errors.NamespaceError:
707
print "%s is not a valid Arch branch." % from_branch
709
if reuse_history_list is None:
710
reuse_history_list = []
711
import_version(to_location, from_branch, self.printer,
713
reuse_history_from=reuse_history_list)
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)
716
785
class NotInABranch(Exception):
722
class cmd_baz_import(Command):
723
"""Import an Arch or Baz archive into bzr branches.
725
reuse_history allows you to specify any previous imports you
726
have done of different archives, which this archive has branches
727
tagged from. This will dramatically reduce the time to convert
728
the archive as it will not have to convert the history already
729
converted in that other branch.
731
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
732
takes_options = ['verbose']
734
def printer(self, name):
737
def run(self, to_root_dir, from_archive, verbose=False,
738
reuse_history_list=[]):
739
if reuse_history_list is None:
740
reuse_history_list = []
741
to_root = str(os.path.realpath(to_root_dir))
742
if not os.path.exists(to_root):
744
import_archive(to_root, from_archive, verbose, self.printer,
748
def import_archive(to_root, from_archive, verbose, printer,
749
reuse_history_from=[]):
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):
750
816
real_to = os.path.realpath(to_root)
751
817
history_locations = [real_to] + reuse_history_from
752
for version in pybaz.Archive(str(from_archive)).iter_versions():
753
target = os.path.join(to_root, map_namespace(version))
754
printer("importing %s into %s" % (version, target))
755
if not os.path.exists(os.path.dirname(target)):
756
os.makedirs(os.path.dirname(target))
818
if standalone is False:
758
import_version(target, version, printer,
759
reuse_history_from=reuse_history_from)
760
except pybaz.errors.ExecProblem,e:
761
if str(e).find('The requested revision cannot be built.') != -1:
762
printer("Skipping version %s as it cannot be built due"
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"
763
845
" to a missing parent archive." % version)
767
if str(e).find('already exists, and the last revision ') != -1:
768
printer("Skipping version %s as it has had commits made"
849
if str(e).find('already exists, and the last revision ') != -1:
851
"Skipping version %s as it has had commits made"
769
852
" since it was converted to bzr." % version)
856
progress_bar.finished()
774
859
def map_namespace(a_version):