~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to baz_import.py

  • Committer: Aaron Bentley
  • Date: 2008-02-20 14:28:36 UTC
  • Revision ID: aaron@aaronbentley.com-20080220142836-jqsca0avvl2p3bar
Remove ImportReplacer hack

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