30
30
from bzrlib.commands import Command
31
31
from bzrlib.option import _global_option, Option
32
32
from bzrlib.merge import merge_inner
33
from bzrlib.revision import NULL_REVISION
34
from bzrlib.tree import EmptyTree
33
from bzrlib.revision import NULL_REVISION, is_null
36
35
import bzrlib.ui.text
37
36
from bzrlib.workingtree import WorkingTree
272
275
br_from.bzrdir.clone(to_location, revision_id)
273
276
except NoSuchRevision:
274
277
rmtree(to_location)
275
msg = "The branch %s has no revision %s." % (from_location,
278
msg = "The branch %s has no revision %s." % (from_location,
277
280
raise UserError(msg)
281
def get_remaining_revisions(output_dir, version, reuse_history_from=[]):
284
def get_remaining_revisions(output_dir, version, encoding,
285
reuse_history_from=[]):
282
286
last_patch = None
284
288
output_exists = os.path.exists(output_dir)
286
290
# We are starting from an existing directory, figure out what
287
291
# the current version is
288
292
branch = Branch.open(output_dir)
289
last_patch = get_last_revision(branch)
293
last_patch, last_encoding = get_last_revision(branch)
294
assert encoding == last_encoding
290
295
if last_patch is None:
291
if branch.last_revision() != None:
296
if not is_null(branch.last_revision()):
292
297
raise NotPreviousImport(branch.base)
293
298
elif version is None:
294
299
version = last_patch.version
305
310
# try to grab a copy of ancestor
306
311
# note that is not optimised: we could look for namespace
307
# transitions and only look for the past after the
312
# transitions and only look for the past after the
309
314
for history_root in reuse_history_from:
310
315
possible_source = os.path.join(history_root,
311
316
map_namespace(ancestor.version))
313
318
source = Branch.open(possible_source)
314
rev_id = revision_id(ancestor)
319
rev_id = revision_id(ancestor, encoding)
315
320
if rev_id in source.revision_history():
316
321
do_branch(source, output_dir, rev_id)
317
322
last_patch = ancestor
329
334
raise UserError("Directory \"%s\" already exists, and the last "
330
"revision (%s) is not in the ancestry of %s" %
335
"revision (%s) is not in the ancestry of %s" %
331
336
(output_dir, last_patch, version))
332
337
# Strip off all of the ancestors which are already present
333
338
# And get a directory starting with the latest ancestor
340
345
###class Importer(object):
341
346
### """An importer.
343
348
### Currently this is used as a parameter object, though more behaviour is
344
349
### possible later.
347
352
### def __init__(self, output_dir, version, fast=False,
348
### verbose=False, dry_run=False, max_count=None,
353
### verbose=False, dry_run=False, max_count=None,
349
354
### reuse_history_from=[]):
350
355
### self.output_dir = output_dir
351
356
### self.version = version
355
def import_version(output_dir, version, fast=False,
360
def import_version(output_dir, version, encoding, fast=False,
356
361
verbose=False, dry_run=False, max_count=None,
357
362
reuse_history_from=[], standalone=True):
359
364
>>> q = test_environ()
361
366
Progress bars output to stderr, but doctest does not capture that.
363
368
>>> old_stderr = sys.stderr
370
375
>>> bzrlib.ui.ui_factory = bzrlib.ui.text.TextUIFactory(
371
376
... bar_type=bzrlib.progress.DotsProgressBar)
373
>>> import_version('/', version, dry_run=True)
378
>>> import_version('/', version, None, dry_run=True)
374
379
Traceback (most recent call last):
375
380
NotPreviousImport: / is not the location of a previous import.
376
>>> import_version(result_path, version, dry_run=True)
381
>>> import_version(result_path, version, None, dry_run=True)
377
382
Traceback (most recent call last):
378
383
UserError: The version test@example.com/test--test--0.1 does not exist.
379
384
>>> version = pybaz.Version("test@example.com/test--test--0")
380
>>> import_version(result_path, version, dry_run=True) #doctest: +ELLIPSIS
385
>>> import_version(result_path, version, None, dry_run=True) #doctest: +ELLIPSIS
381
386
importing test@example.com/test--test--0 into ...
383
388
revisions: ..........................................
384
389
Dry run, not modifying output_dir
386
>>> import_version(result_path, version) #doctest: +ELLIPSIS
391
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
387
392
importing test@example.com/test--test--0 into ...
389
394
revisions: .....................................................................
392
>>> import_version(result_path, version) #doctest: +ELLIPSIS
397
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
393
398
Tree is up-to-date with test@example.com/test--test--0--patch-2
394
399
>>> commit_more_test_revisions()
395
>>> import_version(result_path, version) #doctest: +ELLIPSIS
400
>>> import_version(result_path, version, None) #doctest: +ELLIPSIS
396
401
importing test@example.com/test--test--0 into ...
397
402
revisions: ....................................................
412
418
progress_bar.note('Version %s has no revisions.' % version)
414
420
if len(ancestors) == 0:
415
last_revision = get_last_revision(Branch.open(output_dir))
421
last_revision, last_encoding = \
422
get_last_revision(Branch.open(output_dir))
416
423
progress_bar.note('Tree is up-to-date with %s' % last_revision)
419
426
progress_bar.note("importing %s into %s" % (version, output_dir))
421
428
tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
422
429
dir=os.path.dirname(output_dir))
424
431
wt = WorkingTree.open(output_dir)
425
432
except (NotBranchError, NoWorkingTree):
428
old_basis = EmptyTree()
430
old_basis = wt.basis_tree()
432
435
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
pb=progress_bar, encoding=encoding, fast=fast,
437
verbose=verbose, dry_run=dry_run, max_count=max_count,
438
standalone=standalone):
436
439
show_progress(progress_bar, result)
438
441
progress_bar.note('Dry run, not modifying output_dir')
441
444
# Update the working tree of the branch
443
446
wt = WorkingTree.open(output_dir)
446
449
if wt is not None:
447
450
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)
451
wt.set_root_id(BAZ_IMPORT_ROOT)
454
456
progress_bar.note('Cleaning up')
455
457
shutil.rmtree(tempdir)
456
458
progress_bar.note("Import complete.")
458
460
progress_bar.finished()
460
462
class UserError(BzrCommandError):
461
463
def __init__(self, message):
462
464
"""Exception to throw when a user makes an impossible request
480
482
:param arch_revision: The Arch revision to generate an ID for.
482
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
484
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"), None)
483
485
'Arch-1:you@example.com%cat--br--0--base-0'
486
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"), 'utf-8')
487
'Arch-1-utf-8:you@example.com%cat--br--0--base-0'
485
return "Arch-1:%s" % str(arch_revision).replace('/', '%')
492
encoding = '-' + encoding
493
return "Arch-1%s:%s" % (encoding, str(arch_revision).replace('/', '%'))
487
495
class NotArchRevision(Exception):
488
496
def __init__(self, revision_id):
498
506
>>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
499
507
Traceback (most recent call last):
500
508
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'
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])
517
>>> str(arch_revision('null:'))
504
if revision_id is None:
506
if revision_id[:7] != 'Arch-1:':
520
if is_null(revision_id):
522
if revision_id[:7] not in ('Arch-1:', 'Arch-1-'):
507
523
raise NotArchRevision(revision_id)
510
return pybaz.Revision(revision_id[7:].replace('%', '/'))
526
encoding, arch_name = revision_id[6:].split(':', 1)
527
arch_name = arch_name.replace('%', '/')
531
encoding = encoding[1:]
532
return pybaz.Revision(arch_name), encoding
511
533
except pybaz.errors.NamespaceError, e:
512
534
raise NotArchRevision(revision_id)
532
554
if revision_id is None:
533
555
revision_id = source.last_revision()
534
556
wt = create_checkout(source, to_location, NULL_REVISION)
535
wt.set_last_revision(revision_id)
536
wt._write_inventory(wt.basis_tree().inventory)
559
wt.set_last_revision(revision_id)
561
if revision_id not in (NULL_REVISION, None):
562
basis = wt.basis_tree()
565
wt._write_inventory(basis.inventory)
540
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
541
verbose=False, dry_run=False, max_count=None,
573
def iter_import_version(output_dir, ancestors, tempdir, pb, encoding,
574
fast=False, verbose=False, dry_run=False,
575
max_count=None, standalone=False):
577
log_encoding = 'ascii'
578
if encoding is not None:
579
log_encoding = encoding
545
581
# Uncomment this for testing, it basically just has baz2bzr only update
546
582
# 5 patches at a time
633
668
if missing_ancestor:
634
669
# if we want it to be in revision-history, do that here.
635
target_tree.add_pending_merge(revision_id(missing_ancestor))
670
target_tree.set_parent_ids(
671
[revision_id(missing_ancestor, encoding)],
672
allow_leftmost_as_ghost=True)
636
673
missing_ancestor = None
637
674
for merged_rev in direct_merges:
638
target_tree.add_pending_merge(revision_id(merged_rev))
675
target_tree.add_pending_merge(revision_id(merged_rev,
677
target_tree.set_root_id(BAZ_IMPORT_ROOT)
639
679
target_tree.set_inventory(baz_inv)
640
680
commitobj = Commit(reporter=ImportCommitReporter())
641
681
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,
682
message=log_message.decode(log_encoding, 'replace'),
683
verbose=False, committer=log_creator, timestamp=timestamp,
684
timezone=0, rev_id=rev_id, revprops={})
647
686
target_tree.unlock()
653
692
previous_version = revision.version
654
693
if pybaz.WorkingTree(revdir).tree_version != previous_version:
655
694
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,
695
log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir,
696
revision.category.nonarch, revision.branch.nonarch,
658
697
revision.version.nonarch, revision.archive, revision.patchlevel)
659
698
temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
660
699
os.rename(log_path, temp_path)
680
719
tree = revision.get(revdir)
681
720
log = get_log(tree, revision)
683
return tree, bzr_inventory_data(tree), log
722
return tree, bzr_inventory_data(tree), log
684
723
except BadFileKind, e:
685
raise UserError("Cannot convert %s because %s is a %s" %
724
raise UserError("Cannot convert %s because %s is a %s" %
686
725
(revision,e.path, e.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."""
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)
771
def baz_import_branch(to_location, from_branch, fast, max_count, verbose,
772
encoding, dry_run, reuse_history_list):
773
to_location = os.path.realpath(str(to_location))
774
if from_branch is not None:
776
from_branch = pybaz.Version(from_branch)
777
except pybaz.errors.NamespaceError:
778
print "%s is not a valid Arch branch." % from_branch
780
if reuse_history_list is None:
781
reuse_history_list = []
782
import_version(to_location, from_branch, encoding, max_count=max_count,
783
reuse_history_from=reuse_history_list)
753
786
class NotInABranch(Exception):
759
class cmd_baz_import(Command):
760
"""Import an Arch or Baz archive into a bzr repository.
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)
793
def baz_import(to_root_dir, from_archive, encoding, verbose=False,
794
reuse_history_list=[], prefixes=None):
795
if reuse_history_list is None:
796
reuse_history_list = []
797
to_root = str(os.path.realpath(to_root_dir))
798
if not os.path.exists(to_root):
800
if prefixes is not None:
801
prefixes = prefixes.split(':')
802
import_archive(to_root, from_archive, verbose, encoding,
803
reuse_history_list, prefixes=prefixes)
794
806
def import_archive(to_root, from_archive, verbose,
795
reuse_history_from=[], standalone=False,
807
encoding, reuse_history_from=[], standalone=False,
797
809
def selected(version):
798
810
if prefixes is None:
824
836
if not os.path.exists(os.path.dirname(target)):
825
837
os.makedirs(os.path.dirname(target))
827
import_version(target, version,
828
reuse_history_from=reuse_history_from,
839
import_version(target, version, encoding,
840
reuse_history_from=reuse_history_from,
829
841
standalone=standalone)
830
842
except pybaz.errors.ExecProblem,e:
831
843
if str(e).find('The requested revision cannot be built.') != -1: