256
236
"Directory \"%s\" already exists, and the last revision is not"
257
237
" an Arch revision (%s)" % (branch.base, last_patch))
259
def do_branch(br_from, to_location, revision_id):
260
"""Derived from branch in builtins."""
264
os.mkdir(to_location)
266
if e.errno == errno.EEXIST:
267
raise UserError('Target directory "%s" already'
268
' exists.' % to_location)
269
if e.errno == errno.ENOENT:
270
raise UserError('Parent of "%s" does not exist.' %
275
br_from.bzrdir.clone(to_location, revision_id)
276
except NoSuchRevision:
278
msg = "The branch %s has no revision %s." % (from_location,
284
def get_remaining_revisions(output_dir, version, encoding,
285
reuse_history_from=[]):
240
def get_remaining_revisions(output_dir, version):
286
241
last_patch = None
288
output_exists = os.path.exists(output_dir)
243
if os.path.exists(output_dir):
290
244
# We are starting from an existing directory, figure out what
291
245
# the current version is
292
246
branch = Branch.open(output_dir)
293
last_patch, last_encoding = get_last_revision(branch)
294
assert encoding == last_encoding
295
if last_patch is None:
296
if branch.last_revision() != None:
297
raise NotPreviousImport(branch.base)
298
elif version is None:
247
last_patch = get_last_revision(branch)
299
249
version = last_patch.version
300
250
elif version is None:
301
251
raise UserError("No version specified, and directory does not exist.")
304
254
ancestors = version_ancestry(version)
305
if not output_exists and reuse_history_from != []:
306
for ancestor in reversed(ancestors):
307
if last_patch is not None:
308
# found something to copy
310
# try to grab a copy of ancestor
311
# note that is not optimised: we could look for namespace
312
# transitions and only look for the past after the
314
for history_root in reuse_history_from:
315
possible_source = os.path.join(history_root,
316
map_namespace(ancestor.version))
318
source = Branch.open(possible_source)
319
rev_id = revision_id(ancestor, encoding)
320
if rev_id in source.revision_history():
321
do_branch(source, output_dir, rev_id)
322
last_patch = ancestor
324
except NotBranchError:
326
255
except NoSuchVersion, e:
327
256
raise UserError(str(e))
341
270
ancestors = ancestors[i+1:]
342
271
return ancestors, old_revno
345
###class Importer(object):
348
### Currently this is used as a parameter object, though more behaviour is
352
### def __init__(self, output_dir, version, fast=False,
353
### verbose=False, dry_run=False, max_count=None,
354
### reuse_history_from=[]):
355
### self.output_dir = output_dir
356
### self.version = version
360
def import_version(output_dir, version, encoding, fast=False,
361
verbose=False, dry_run=False, max_count=None,
362
reuse_history_from=[], standalone=True):
273
def import_version(output_dir, version, printer, fancy=True, fast=False,
274
verbose=False, dry_run=False, max_count=None):
364
276
>>> 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
277
>>> result_path = os.path.join(q, "result")
372
278
>>> commit_test_revisions()
373
279
>>> 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)
280
>>> def printer(message): print message
281
>>> import_version('/', version, printer, fancy=False, dry_run=True)
379
282
Traceback (most recent call last):
380
NotPreviousImport: / is not the location of a previous import.
381
>>> import_version(result_path, version, None, dry_run=True)
283
UserError: / exists, but is not a bzr branch.
284
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
382
285
Traceback (most recent call last):
383
286
UserError: The version test@example.com/test--test--0.1 does not exist.
384
287
>>> 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: ..........................................
288
>>> import_version(result_path, version, printer, fancy=False, dry_run=True)
389
291
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: .....................................................................
293
>>> import_version(result_path, version, printer, fancy=False)
397
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
298
>>> import_version(result_path, version, printer, fancy=False)
398
299
Tree is up-to-date with test@example.com/test--test--0--patch-2
399
300
>>> commit_more_test_revisions()
400
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
401
importing test@example.com/test--test--0 into ...
402
revisions: ....................................................
301
>>> import_version(result_path, version, printer, fancy=False)
405
>>> bzrlib.ui.ui_factory = old_ui
406
>>> sys.stderr = old_stderr
407
306
>>> 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):
309
ancestors, old_revno = get_remaining_revisions(output_dir, version)
310
except NotBranchError, e:
311
raise UserError("%s exists, but is not a bzr branch." % output_dir)
312
if old_revno is None and len(ancestors) == 0:
313
print 'Version %s has no revisions.' % version
315
if len(ancestors) == 0:
316
last_revision = get_last_revision(Branch.open(output_dir))
317
print 'Tree is up-to-date with %s' % last_revision
320
progress_bar = ProgressBar()
321
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
322
dir=os.path.dirname(output_dir))
435
327
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
328
progress_bar, fast=fast, verbose=verbose, dry_run=dry_run,
329
max_count=max_count):
331
show_progress(progress_bar, result)
333
sys.stdout.write('.')
338
sys.stdout.write('\n')
341
print 'Dry run, not modifying output_dir'
343
if os.path.exists(output_dir):
344
# Move the bzr control directory back, and update the working tree
345
tmp_bzr_dir = os.path.join(tempdir, '.bzr')
347
bzr_dir = os.path.join(output_dir, '.bzr')
348
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
350
os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way
351
os.rename(new_bzr_dir, bzr_dir)
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)
456
progress_bar.note('Cleaning up')
457
shutil.rmtree(tempdir)
458
progress_bar.note("Import complete.")
353
bzrlib.merge.merge((output_dir, -1), (output_dir, None), # old_revno),
354
check_clean=False, this_dir=output_dir,
357
# If something failed, move back the original bzr directory
358
os.rename(bzr_dir, new_bzr_dir)
359
os.rename(tmp_bzr_dir, bzr_dir)
362
revdir = os.path.join(tempdir, "rd")
363
os.rename(revdir, output_dir)
460
progress_bar.finished()
366
printer('Cleaning up')
367
shutil.rmtree(tempdir)
368
printer("Import complete.")
462
370
class UserError(BzrCommandError):
463
371
def __init__(self, message):
464
372
"""Exception to throw when a user makes an impossible request
506
402
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
507
403
Traceback (most recent call last):
508
404
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])
405
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
406
'jrandom@example.com/test--test--0--patch-5'
518
408
if revision_id is None:
520
if revision_id[:7] not in ('Arch-1:', 'Arch-1-'):
410
if revision_id[:7] != 'Arch-1:':
521
411
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
414
return pybaz.Revision(revision_id[7:].replace('%', '/'))
531
415
except pybaz.errors.NamespaceError, e:
532
416
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):
418
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
419
verbose=False, dry_run=False, max_count=None):
575
log_encoding = 'ascii'
576
if encoding is not None:
577
log_encoding = encoding
579
422
# Uncomment this for testing, it basically just has baz2bzr only update
580
423
# 5 patches at a time
633
458
missing_ancestor = revision
635
pb.note("unable to access ancestor %s, making into a merge."
460
print ("unable to access ancestor %s, making into a merge."
636
461
% missing_ancestor)
638
target_tree = create_checkout_metadata(target_branch, revdir)
639
branch = target_tree.branch
463
if os.path.exists(output_dir):
464
bzr_dir = os.path.join(output_dir, '.bzr')
465
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr')
466
# This would be much faster with a simple os.rename(), but if
467
# we fail, we have corrupted the original .bzr directory. Is
468
# that a big problem, as we can just back out the last
469
# revisions in .bzr/revision_history I don't really know
470
shutil.copytree(bzr_dir, new_bzr_dir)
471
# Now revdir should have a tree with the latest .bzr, and the
472
# next revision of the baz tree
473
branch = Branch.open(revdir)
475
branch = Branch.initialize(revdir)
641
477
old = os.path.join(revdir, ".bzr")
642
478
new = os.path.join(tempdir, ".bzr")
643
479
os.rename(old, new)
644
480
baz_inv, log = apply_revision(tree, revision)
645
481
os.rename(new, old)
646
target_tree = WorkingTree.open(revdir)
647
branch = target_tree.branch
482
branch = Branch.open(revdir)
648
483
# cached so we can delete the log
649
484
log_date = log.date
650
485
log_summary = log.summary
651
486
log_description = log.description
652
487
is_continuation = log.continuation_of is not None
653
488
log_creator = log.creator
654
direct_merges = get_direct_merges(revdir, revision, log)
489
direct_merges = get_direct_merges(revdir, revision)
656
491
timestamp = email.Utils.mktime_tz(log_date + (0,))
492
rev_id = revision_id(revision)
657
493
if log_summary is None:
659
495
# log_descriptions of None and "" are ignored.
661
497
log_message = "\n".join((log_summary, log_description))
663
499
log_message = log_summary
664
target_tree.lock_write()
665
500
branch.lock_write()
667
502
if missing_ancestor:
668
503
# 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)
504
branch.add_pending_merge(revision_id(missing_ancestor))
672
505
missing_ancestor = None
673
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)
678
target_tree.set_inventory(baz_inv)
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={})
506
for merge in direct_merges:
507
branch.add_pending_merge(revision_id(merge.revision))
508
branch.set_inventory(baz_inv)
509
commitobj = Commit(reporter=ImportCommitReporter(pb))
510
commitobj.commit(branch, log_message.decode('ascii', 'replace'),
511
verbose=False, committer=log_creator,
512
timestamp=timestamp, timezone=0, rev_id=rev_id)
687
515
yield Progress("revisions", len(ancestors), len(ancestors))
516
unlink_unversioned(branch, revdir)
689
def get_direct_merges(revdir, revision, log):
690
continuation = log.continuation_of
691
previous_version = revision.version
692
if pybaz.WorkingTree(revdir).tree_version != previous_version:
693
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,
518
def get_direct_merges(revdir, revision):
519
if pybaz.WorkingTree(revdir).tree_version != revision.version:
520
pybaz.WorkingTree(revdir).set_tree_version(revision.version)
521
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
522
revision.category.nonarch, revision.branch.nonarch,
696
523
revision.version.nonarch, revision.archive, revision.patchlevel)
697
524
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
698
525
os.rename(log_path, temp_path)
699
526
merges = list(iter_new_merges(revdir, revision.version))
700
direct = direct_merges(merges, [continuation])
527
direct = direct_merges (merges)
701
528
os.rename(temp_path, log_path)
704
def unlink_unversioned(wt):
705
for unversioned in wt.extras():
706
path = wt.abspath(unversioned)
531
def unlink_unversioned(branch, revdir):
532
for unversioned in branch.working_tree().extras():
533
path = os.path.join(revdir, unversioned)
707
534
if os.path.isdir(path):
708
535
shutil.rmtree(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)
785
class NotInABranch(Exception):
786
def __init__(self, path):
787
Exception.__init__(self, "%s is not in a branch." % path)
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):
816
real_to = os.path.realpath(to_root)
817
history_locations = [real_to] + reuse_history_from
818
if standalone is False:
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))
594
_global_option('max-count', type = int)
595
class cmd_baz_import_branch(Command):
596
"""Import an Arch or Baz branch into a bzr branch"""
597
takes_args = ['to_location', 'from_branch?']
598
takes_options = ['verbose', 'max-count']
600
def printer(self, name):
603
def run(self, to_location, from_branch=None, fast=False, max_count=None,
604
verbose=False, dry_run=False):
605
to_location = os.path.realpath(str(to_location))
606
if from_branch is not None:
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"
608
from_branch = pybaz.Version(from_branch)
609
except pybaz.errors.NamespaceError:
610
print "%s is not a valid Arch branch." % from_branch
612
import_version(to_location, from_branch, self.printer,
616
class cmd_baz_import(Command):
617
"""Import an Arch or Baz archive into bzr branches."""
618
takes_args = ['to_root_dir', 'from_archive']
619
takes_options = ['verbose']
621
def printer(self, name):
624
def run(self, to_root_dir, from_archive, verbose=False):
625
to_root = str(os.path.realpath(to_root_dir))
626
if not os.path.exists(to_root):
628
import_archive(to_root, from_archive, verbose, self.printer)
631
def import_archive(to_root, from_archive, verbose, printer):
632
for version in pybaz.Archive(str(from_archive)).iter_versions():
633
target = os.path.join(to_root, map_namespace(version))
634
printer("importing %s into %s" % (version, target))
635
if not os.path.exists(os.path.dirname(target)):
636
os.makedirs(os.path.dirname(target))
638
import_version(target, version, printer)
639
except pybaz.errors.ExecProblem,e:
640
if str(e).find('The requested revision cannot be built.') != -1:
641
printer("Skipping version %s as it cannot be built due"
845
642
" 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"
646
if str(e).find('already exists, and the last revision ') != -1:
647
printer("Skipping version %s as it has had commits made"
852
648
" since it was converted to bzr." % version)
856
progress_bar.finished()
859
653
def map_namespace(a_version):