~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to baz_import.py

  • Committer: Aaron Bentley
  • Date: 2006-03-07 15:23:15 UTC
  • mfrom: (321.1.2 bzrtools)
  • mto: (147.4.31 trunk)
  • mto: This revision was merged to the branch mainline in revision 324.
  • Revision ID: abentley@panoramicfeedback.com-20060307152315-42337454a0ad956b
MergeĀ fromĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
from bzrlib.errors import (BzrError,
22
22
                           NotBranchError,
23
23
                           NoWorkingTree,
24
 
                           BzrCommandError,
 
24
                           BzrCommandError, 
25
25
                           NoSuchRevision,
26
26
                           NoRepositoryPresent,
27
27
                          )
31
31
from bzrlib.option import _global_option, Option
32
32
from bzrlib.merge import merge_inner
33
33
from bzrlib.revision import NULL_REVISION
 
34
from bzrlib.tree import EmptyTree
34
35
import bzrlib.ui
35
 
import bzrlib.ui.text
36
36
from bzrlib.workingtree import WorkingTree
37
37
from errors import NoPyBaz
38
38
try:
56
56
import email.Utils
57
57
from progress import *
58
58
 
59
 
 
60
 
BAZ_IMPORT_ROOT = 'TREE_ROOT'
61
 
 
62
 
 
63
59
class ImportCommitReporter(NullCommitReporter):
 
60
    def __init__(self, pb):
 
61
        self.pb = pb
64
62
 
65
63
    def escaped(self, escape_count, message):
 
64
        self.pb.clear()
66
65
        bzrlib.trace.warning("replaced %d control characters in message" %
67
66
                             escape_count)
68
67
 
84
83
 
85
84
def make_archive(name, location):
86
85
    pb_location = pybaz.ArchiveLocation(location)
87
 
    pb_location.create_master(pybaz.Archive(name),
 
86
    pb_location.create_master(pybaz.Archive(name), 
88
87
                              pybaz.ArchiveLocationParams())
89
88
 
90
89
def test_environ():
275
274
            br_from.bzrdir.clone(to_location, revision_id)
276
275
        except NoSuchRevision:
277
276
            rmtree(to_location)
278
 
            msg = "The branch %s has no revision %s." % (from_location,
 
277
            msg = "The branch %s has no revision %s." % (from_location, 
279
278
                                                         revision_id)
280
279
            raise UserError(msg)
281
280
    finally:
282
281
        br_from.unlock()
283
282
 
284
 
def get_remaining_revisions(output_dir, version, encoding,
285
 
                            reuse_history_from=[]):
 
283
def get_remaining_revisions(output_dir, version, reuse_history_from=[]):
286
284
    last_patch = None
287
285
    old_revno = None
288
286
    output_exists = os.path.exists(output_dir)
290
288
        # We are starting from an existing directory, figure out what
291
289
        # the current version is
292
290
        branch = Branch.open(output_dir)
293
 
        last_patch, last_encoding = get_last_revision(branch)
294
 
        assert encoding == last_encoding
 
291
        last_patch = get_last_revision(branch)
295
292
        if last_patch is None:
296
 
            if branch.last_revision() != None:
297
 
                raise NotPreviousImport(branch.base)
298
 
        elif version is None:
 
293
            raise NotPreviousImport(branch.base)
 
294
        if version is None:
299
295
            version = last_patch.version
300
296
    elif version is None:
301
297
        raise UserError("No version specified, and directory does not exist.")
309
305
                    break
310
306
                # try to grab a copy of ancestor
311
307
                # note that is not optimised: we could look for namespace
312
 
                # transitions and only look for the past after the
 
308
                # transitions and only look for the past after the 
313
309
                # transition.
314
310
                for history_root in reuse_history_from:
315
311
                    possible_source = os.path.join(history_root,
316
312
                        map_namespace(ancestor.version))
317
313
                    try:
318
314
                        source = Branch.open(possible_source)
319
 
                        rev_id = revision_id(ancestor, encoding)
 
315
                        rev_id = revision_id(ancestor)
320
316
                        if rev_id in source.revision_history():
321
317
                            do_branch(source, output_dir, rev_id)
322
318
                            last_patch = ancestor
332
328
                break
333
329
        else:
334
330
            raise UserError("Directory \"%s\" already exists, and the last "
335
 
                "revision (%s) is not in the ancestry of %s" %
 
331
                "revision (%s) is not in the ancestry of %s" % 
336
332
                (output_dir, last_patch, version))
337
333
        # Strip off all of the ancestors which are already present
338
334
        # And get a directory starting with the latest ancestor
344
340
 
345
341
###class Importer(object):
346
342
###    """An importer.
347
 
###
 
343
###    
348
344
###    Currently this is used as a parameter object, though more behaviour is
349
345
###    possible later.
350
346
###    """
351
347
###
352
 
###    def __init__(self, output_dir, version, fast=False,
353
 
###                 verbose=False, dry_run=False, max_count=None,
 
348
###    def __init__(self, output_dir, version, printer, fancy=True, fast=False,
 
349
###                 verbose=False, dry_run=False, max_count=None, 
354
350
###                   reuse_history_from=[]):
355
351
###        self.output_dir = output_dir
356
352
###        self.version = version
357
353
###        self.
358
354
 
359
355
 
360
 
def import_version(output_dir, version, encoding, fast=False,
 
356
def import_version(output_dir, version, printer, fancy=True, fast=False,
361
357
                   verbose=False, dry_run=False, max_count=None,
362
358
                   reuse_history_from=[], standalone=True):
363
359
    """
364
360
    >>> q = test_environ()
365
 
 
366
 
    Progress bars output to stderr, but doctest does not capture that.
367
 
 
368
 
    >>> old_stderr = sys.stderr
369
 
    >>> sys.stderr = sys.stdout
370
 
 
371
361
    >>> result_path = os.path.join(q, "result")
372
362
    >>> commit_test_revisions()
373
363
    >>> 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)
377
 
 
378
 
    >>> import_version('/', version, None, dry_run=True)
 
364
    >>> def printer(message): print message
 
365
    >>> import_version('/', version, printer, fancy=False, dry_run=True)
379
366
    Traceback (most recent call last):
380
367
    NotPreviousImport: / is not the location of a previous import.
381
 
    >>> import_version(result_path, version, None, dry_run=True)
 
368
    >>> import_version(result_path, version, printer, fancy=False, dry_run=True)
382
369
    Traceback (most recent call last):
383
370
    UserError: The version test@example.com/test--test--0.1 does not exist.
384
371
    >>> 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 ...
387
 
    ...
388
 
    revisions: ..........................................
 
372
    >>> import_version(result_path, version, printer, fancy=False, dry_run=True)
 
373
    not fancy
 
374
    ....
389
375
    Dry run, not modifying output_dir
390
376
    Cleaning up
391
 
    >>> import_version(result_path, version, None) #doctest: +ELLIPSIS
392
 
    importing test@example.com/test--test--0 into ...
393
 
    ...
394
 
    revisions: .....................................................................
 
377
    >>> import_version(result_path, version, printer, fancy=False)
 
378
    not fancy
 
379
    ....
395
380
    Cleaning up
396
381
    Import complete.
397
 
    >>> import_version(result_path, version, None) #doctest: +ELLIPSIS
 
382
    >>> import_version(result_path, version, printer, fancy=False)
398
383
    Tree is up-to-date with test@example.com/test--test--0--patch-2
399
384
    >>> commit_more_test_revisions()
400
 
    >>> import_version(result_path, version, None) #doctest: +ELLIPSIS
401
 
    importing test@example.com/test--test--0 into ...
402
 
    revisions: ....................................................
 
385
    >>> import_version(result_path, version, printer, fancy=False)
 
386
    not fancy
 
387
    ..
403
388
    Cleaning up
404
389
    Import complete.
405
 
    >>> bzrlib.ui.ui_factory = old_ui
406
 
    >>> sys.stderr = old_stderr
407
390
    >>> teardown_environ(q)
408
391
    """
409
 
    progress_bar = bzrlib.ui.ui_factory.nested_progress_bar()
410
 
    try:
 
392
    try:
 
393
        ancestors, old_revno = get_remaining_revisions(output_dir, version,
 
394
                                                       reuse_history_from)
 
395
    except NotBranchError, e:
 
396
        raise NotPreviousImport(e.path)
 
397
    if old_revno is None and len(ancestors) == 0:
 
398
        print 'Version %s has no revisions.' % version
 
399
        return
 
400
    if len(ancestors) == 0:
 
401
        last_revision = get_last_revision(Branch.open(output_dir))
 
402
        print 'Tree is up-to-date with %s' % last_revision
 
403
        return
 
404
 
 
405
    progress_bar = bzrlib.ui.ui_factory.progress_bar()
 
406
    tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
 
407
                               dir=os.path.dirname(output_dir))
 
408
    try:
 
409
        wt = WorkingTree.open(output_dir)
 
410
    except (NotBranchError, NoWorkingTree):
 
411
        wt = None
 
412
    if wt is None:
 
413
        old_basis = EmptyTree()
 
414
    else:
 
415
        old_basis = wt.basis_tree()
 
416
    try:
 
417
        if not fancy:
 
418
            print "not fancy"
411
419
        try:
412
 
            ancestors, old_revno = get_remaining_revisions(output_dir, version,
413
 
                                                           encoding,
414
 
                                                           reuse_history_from)
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)
419
 
            return
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)
424
 
            return
425
 
 
426
 
        progress_bar.note("importing %s into %s" % (version, output_dir))
427
 
 
428
 
        tempdir = tempfile.mkdtemp(prefix="baz2bzr-",
429
 
                                   dir=os.path.dirname(output_dir))
 
420
            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):
 
423
                if fancy:
 
424
                    show_progress(progress_bar, result)
 
425
                else:
 
426
                    sys.stdout.write('.')
 
427
        finally:
 
428
            if fancy:
 
429
                progress_bar.clear()
 
430
            else:
 
431
                sys.stdout.write('\n')
 
432
 
 
433
        if dry_run:
 
434
            print 'Dry run, not modifying output_dir'
 
435
            return
 
436
 
 
437
        # Update the working tree of the branch
430
438
        try:
431
439
            wt = WorkingTree.open(output_dir)
432
 
        except (NotBranchError, NoWorkingTree):
 
440
        except NoWorkingTree:
433
441
            wt = None
434
 
        try:
435
 
            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)
440
 
            if dry_run:
441
 
                progress_bar.note('Dry run, not modifying output_dir')
442
 
                return
443
 
 
444
 
            # Update the working tree of the branch
445
 
            try:
446
 
                wt = WorkingTree.open(output_dir)
447
 
            except NoWorkingTree:
448
 
                wt = None
449
 
            if wt is not None:
450
 
                wt.set_last_revision(wt.branch.last_revision())
451
 
                wt.set_root_id(BAZ_IMPORT_ROOT)
452
 
                wt.revert([])
453
 
 
454
 
        finally:
455
 
 
456
 
            progress_bar.note('Cleaning up')
457
 
            shutil.rmtree(tempdir)
458
 
        progress_bar.note("Import complete.")
 
442
        if wt is not None:
 
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)
 
446
            wt.revert([])
 
447
 
459
448
    finally:
460
 
        progress_bar.finished()
461
 
 
 
449
        printer('Cleaning up')
 
450
        shutil.rmtree(tempdir)
 
451
    printer("Import complete.")
 
452
            
462
453
class UserError(BzrCommandError):
463
454
    def __init__(self, message):
464
455
        """Exception to throw when a user makes an impossible request
473
464
                           % path)
474
465
 
475
466
 
476
 
def revision_id(arch_revision, encoding):
 
467
def revision_id(arch_revision):
477
468
    """
478
469
    Generate a Bzr revision id from an Arch revision id.  'x' in the id
479
470
    designates a revision imported with an experimental algorithm.  A number
481
472
 
482
473
    :param arch_revision: The Arch revision to generate an ID for.
483
474
 
484
 
    >>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"), None)
 
475
    >>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
485
476
    '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'
488
477
    """
489
 
    if encoding is None:
490
 
        encoding = ''
491
 
    else:
492
 
        encoding = '-' + encoding
493
 
    return "Arch-1%s:%s" % (encoding, str(arch_revision).replace('/', '%'))
 
478
    return "Arch-1:%s" % str(arch_revision).replace('/', '%')
494
479
 
495
480
class NotArchRevision(Exception):
496
481
    def __init__(self, revision_id):
506
491
    >>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--base-5"))
507
492
    Traceback (most recent call last):
508
493
    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])
514
 
    'None'
515
 
    >>> str(arch_revision("Arch-1-utf-8:jrandom@example.com%test--test--0--patch-5")[1])
516
 
    'utf-8'
 
494
    >>> str(arch_revision("Arch-1:jrandom@example.com%test--test--0--patch-5"))
 
495
    'jrandom@example.com/test--test--0--patch-5'
517
496
    """
518
497
    if revision_id is None:
519
 
        return None, None
520
 
    if revision_id[:7] not in ('Arch-1:', 'Arch-1-'):
 
498
        return None
 
499
    if revision_id[:7] != 'Arch-1:':
521
500
        raise NotArchRevision(revision_id)
522
501
    else:
523
502
        try:
524
 
            encoding, arch_name = revision_id[6:].split(':', 1)
525
 
            arch_name = arch_name.replace('%', '/')
526
 
            if encoding == '':
527
 
                encoding = None
528
 
            else:
529
 
                encoding = encoding[1:]
530
 
            return pybaz.Revision(arch_name), encoding
 
503
            return pybaz.Revision(revision_id[7:].replace('%', '/'))
531
504
        except pybaz.errors.NamespaceError, e:
532
505
            raise NotArchRevision(revision_id)
533
506
 
552
525
    if revision_id is None:
553
526
        revision_id = source.last_revision()
554
527
    wt = create_checkout(source, to_location, NULL_REVISION)
555
 
    wt.lock_write()
556
 
    try:
557
 
        wt.set_last_revision(revision_id)
558
 
        wt.flush()
559
 
        if revision_id not in (NULL_REVISION, None):
560
 
            basis = wt.basis_tree()
561
 
            basis.lock_read()
562
 
            try:
563
 
                wt._write_inventory(basis.inventory)
564
 
            finally:
565
 
                basis.unlock()
566
 
    finally:
567
 
        wt.unlock()
 
528
    wt.set_last_revision(revision_id)
 
529
    wt._write_inventory(wt.basis_tree().inventory)
568
530
    return wt
569
531
 
570
532
 
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):
 
533
def iter_import_version(output_dir, ancestors, tempdir, pb, fast=False,
 
534
                        verbose=False, dry_run=False, max_count=None,
 
535
                        standalone=False):
574
536
    revdir = None
575
 
    log_encoding = 'ascii'
576
 
    if encoding is not None:
577
 
        log_encoding = encoding
578
537
 
579
538
    # Uncomment this for testing, it basically just has baz2bzr only update
580
539
    # 5 patches at a time
609
568
 
610
569
    for i in range(len(ancestors)):
611
570
        revision = ancestors[i]
612
 
        rev_id = revision_id(revision, encoding)
 
571
        rev_id = revision_id(revision)
613
572
        direct_merges = []
614
573
        if verbose:
615
574
            version = str(revision.version)
616
575
            if version != previous_version:
617
 
                pb.note('On version: %s' % version)
 
576
                clear_progress_bar()
 
577
                print '\rOn version: %s' % version
618
578
            yield Progress(str(revision.patchlevel), i, len(ancestors))
619
579
            previous_version = version
620
580
        else:
632
592
                    raise
633
593
                missing_ancestor = revision
634
594
                revdir = None
635
 
                pb.note("unable to access ancestor %s, making into a merge."
 
595
                print ("unable to access ancestor %s, making into a merge."
636
596
                       % missing_ancestor)
637
597
                continue
638
598
            target_tree = create_checkout_metadata(target_branch, revdir)
666
626
        try:
667
627
            if missing_ancestor:
668
628
                # 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)
 
629
                target_tree.add_pending_merge(revision_id(missing_ancestor))
672
630
                missing_ancestor = None
673
631
            for merged_rev in direct_merges:
674
 
                target_tree.add_pending_merge(revision_id(merged_rev,
675
 
                                                          encoding))
676
 
            target_tree.set_root_id(BAZ_IMPORT_ROOT)
677
 
            target_tree.flush()
 
632
                target_tree.add_pending_merge(revision_id(merged_rev))
678
633
            target_tree.set_inventory(baz_inv)
679
 
            commitobj = Commit(reporter=ImportCommitReporter())
 
634
            commitobj = Commit(reporter=ImportCommitReporter(pb))
680
635
            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={})
 
636
                             message=log_message.decode('ascii', 'replace'), 
 
637
                             verbose=False, committer=log_creator,
 
638
                             timestamp=timestamp, timezone=0, rev_id=rev_id,
 
639
                             revprops={'branch-nick': str(revision.version)})
684
640
        finally:
685
641
            target_tree.unlock()
686
642
            branch.unlock()
691
647
    previous_version = revision.version
692
648
    if pybaz.WorkingTree(revdir).tree_version != previous_version:
693
649
        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,
 
650
    log_path = "%s/{arch}/%s/%s/%s/%s/patch-log/%s" % (revdir, 
 
651
        revision.category.nonarch, revision.branch.nonarch, 
696
652
        revision.version.nonarch, revision.archive, revision.patchlevel)
697
653
    temp_path = tempfile.mktemp(dir=os.path.dirname(revdir))
698
654
    os.rename(log_path, temp_path)
718
674
    tree = revision.get(revdir)
719
675
    log = get_log(tree, revision)
720
676
    try:
721
 
        return tree, bzr_inventory_data(tree), log
 
677
        return tree, bzr_inventory_data(tree), log 
722
678
    except BadFileKind, e:
723
 
        raise UserError("Cannot convert %s because %s is a %s" %
 
679
        raise UserError("Cannot convert %s because %s is a %s" % 
724
680
                        (revision,e.path, e.kind))
725
681
 
726
682
 
730
686
    try:
731
687
        return bzr_inventory_data(tree), log
732
688
    except BadFileKind, e:
733
 
        raise UserError("Cannot convert %s because %s is a %s" %
 
689
        raise UserError("Cannot convert %s because %s is a %s" % 
734
690
                        (revision,e.path, e.kind))
735
691
 
736
692
 
749
705
    inv_map = {}
750
706
    for arch_id, path in inv_iter:
751
707
        bzr_file_id = map_file_id(arch_id)
752
 
        inv_map[path] = bzr_file_id
 
708
        inv_map[path] = bzr_file_id 
753
709
 
754
710
    bzr_inv = []
755
711
    for path, file_id in inv_map.iteritems():
766
722
    bzr_inv.sort()
767
723
    return bzr_inv
768
724
 
769
 
 
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:
774
 
        try:
775
 
            from_branch = pybaz.Version(from_branch)
776
 
        except pybaz.errors.NamespaceError:
777
 
            print "%s is not a valid Arch branch." % from_branch
778
 
            return 1
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)
 
725
_global_option('max-count', type = int)
 
726
class cmd_baz_import_branch(Command):
 
727
    """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']
 
730
 
 
731
    def printer(self, name):
 
732
        print name
 
733
 
 
734
    def run(self, to_location, from_branch=None, fast=False, max_count=None,
 
735
            verbose=False, dry_run=False, reuse_history_list=[]):
 
736
        to_location = os.path.realpath(str(to_location))
 
737
        if from_branch is not None:
 
738
            try:
 
739
                from_branch = pybaz.Version(from_branch)
 
740
            except pybaz.errors.NamespaceError:
 
741
                print "%s is not a valid Arch branch." % from_branch
 
742
                return 1
 
743
        if reuse_history_list is None:
 
744
            reuse_history_list = []
 
745
        import_version(to_location, from_branch, self.printer, 
 
746
                       max_count=max_count, 
 
747
                       reuse_history_from=reuse_history_list)
783
748
 
784
749
 
785
750
class NotInABranch(Exception):
788
753
        self.path = path
789
754
 
790
755
 
791
 
 
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):
798
 
        os.mkdir(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)
803
 
 
804
 
 
805
 
def import_archive(to_root, from_archive, verbose,
806
 
                   encoding, reuse_history_from=[], standalone=False,
 
756
class cmd_baz_import(Command):
 
757
    """Import an Arch or Baz archive into bzr branches.
 
758
 
 
759
    This command should be used on local archives (or mirrors) only.  It is
 
760
    quite slow on remote archives.
 
761
    
 
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.
 
767
 
 
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
 
773
    """
 
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")]
 
777
 
 
778
    def printer(self, name):
 
779
        print name
 
780
 
 
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):
 
787
            os.mkdir(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)
 
792
 
 
793
 
 
794
def import_archive(to_root, from_archive, verbose, printer,
 
795
                   reuse_history_from=[], standalone=False,
807
796
                   prefixes=None):
808
797
    def selected(version):
809
798
        if prefixes is None:
823
812
            create_shared_repository(to_root)
824
813
        except NoRepositoryPresent:
825
814
            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()
828
 
    try:
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
833
 
                continue
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))
837
 
            try:
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:
843
 
                    progress_bar.note(
844
 
                        "Skipping version %s as it cannot be built due"
 
815
    for version in pybaz.Archive(str(from_archive)).iter_versions():
 
816
        if not selected(version):
 
817
            print "Skipping %s" % version
 
818
            continue
 
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))
 
823
        try:
 
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"
845
830
                        " to a missing parent archive." % version)
846
 
                else:
847
 
                    raise
848
 
            except UserError, e:
849
 
                if str(e).find('already exists, and the last revision ') != -1:
850
 
                    progress_bar.note(
851
 
                        "Skipping version %s as it has had commits made"
 
831
            else:
 
832
                raise
 
833
        except UserError, e:
 
834
            if str(e).find('already exists, and the last revision ') != -1:
 
835
                printer("Skipping version %s as it has had commits made"
852
836
                        " since it was converted to bzr." % version)
853
 
                else:
854
 
                    raise
855
 
    finally:
856
 
        progress_bar.finished()
 
837
            else:
 
838
                raise
857
839
 
858
840
 
859
841
def map_namespace(a_version):
868
850
        return "%s/%s" % (category, branch)
869
851
    return "%s/%s/%s" % (category, version, branch)
870
852
 
871
 
 
872
853
def map_file_id(file_id):
873
854
    """Convert a baz file id to a bzr one."""
874
855
    return file_id.replace('%', '%25').replace('/', '%2f')