/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2008-02-13 03:30:01 UTC
  • mfrom: (3221 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3224.
  • Revision ID: robertc@robertcollins.net-20080213033001-rw70ul0zb02ph856
Merge to fix conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
610
610
            else:
611
611
                display_url = urlutils.unescape_for_display(stored_loc,
612
612
                        self.outf.encoding)
613
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
613
                if not is_quiet():
 
614
                    self.outf.write("Using saved location: %s\n" % display_url)
614
615
                location = stored_loc
615
616
                location_transport = transport.get_transport(
616
617
                    location, possible_transports=possible_transports)
747
748
            # The destination doesn't exist; create it.
748
749
            # XXX: Refactor the create_prefix/no_create_prefix code into a
749
750
            #      common helper function
 
751
 
 
752
            def make_directory(transport):
 
753
                transport.mkdir('.')
 
754
                return transport
 
755
 
 
756
            def redirected(redirected_transport, e, redirection_notice):
 
757
                return transport.get_transport(e.get_target_url())
 
758
 
750
759
            try:
751
 
                to_transport.mkdir('.')
 
760
                to_transport = transport.do_catching_redirections(
 
761
                    make_directory, to_transport, redirected)
752
762
            except errors.FileExists:
753
763
                if not use_existing_dir:
754
764
                    raise errors.BzrCommandError("Target directory %s"
763
773
                        " leading parent directories."
764
774
                        % location)
765
775
                _create_prefix(to_transport)
 
776
            except errors.TooManyRedirections:
 
777
                raise errors.BzrCommandError("Too many redirections trying "
 
778
                                             "to make %s." % location)
766
779
 
767
780
            # Now the target directory exists, but doesn't have a .bzr
768
781
            # directory. So we need to create it, along with any work to create
862
875
            raise errors.BzrCommandError(
863
876
                'bzr branch --revision takes exactly 1 revision value')
864
877
 
865
 
        br_from = Branch.open(from_location)
 
878
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
 
879
            from_location)
866
880
        br_from.lock_read()
867
881
        try:
868
882
            if len(revision) == 1 and revision[0] is not None:
890
904
            try:
891
905
                # preserve whatever source format we have.
892
906
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
893
 
                                            possible_transports=[to_transport])
 
907
                                            possible_transports=[to_transport],
 
908
                                            accelerator_tree=accelerator_tree)
894
909
                branch = dir.open_branch()
895
910
            except errors.NoSuchRevision:
896
911
                to_transport.delete_tree('.')
935
950
                                 "common operations like diff and status without "
936
951
                                 "such access, and also support local commits."
937
952
                            ),
 
953
                     Option('files-from',
 
954
                            help="Get file contents from this tree.", type=str)
938
955
                     ]
939
956
    aliases = ['co']
940
957
 
941
958
    def run(self, branch_location=None, to_location=None, revision=None,
942
 
            lightweight=False):
 
959
            lightweight=False, files_from=None):
943
960
        if revision is None:
944
961
            revision = [None]
945
962
        elif len(revision) > 1:
948
965
        if branch_location is None:
949
966
            branch_location = osutils.getcwd()
950
967
            to_location = branch_location
951
 
        source = Branch.open(branch_location)
 
968
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
 
969
            branch_location)
 
970
        if files_from is not None:
 
971
            accelerator_tree = WorkingTree.open(files_from)
952
972
        if len(revision) == 1 and revision[0] is not None:
953
973
            revision_id = _mod_revision.ensure_null(
954
974
                revision[0].in_history(source)[1])
966
986
            except errors.NoWorkingTree:
967
987
                source.bzrdir.create_workingtree(revision_id)
968
988
                return
969
 
        source.create_checkout(to_location, revision_id, lightweight)
 
989
        source.create_checkout(to_location, revision_id, lightweight,
 
990
                               accelerator_tree)
970
991
 
971
992
 
972
993
class cmd_renames(Command):
1255
1276
        bzr init
1256
1277
        bzr add .
1257
1278
        bzr status
1258
 
        bzr commit -m 'imported project'
 
1279
        bzr commit -m "imported project"
1259
1280
    """
1260
1281
 
1261
1282
    _see_also = ['init-repository', 'branch', 'checkout']
1378
1399
 
1379
1400
 
1380
1401
class cmd_diff(Command):
1381
 
    """Show differences in the working tree or between revisions.
 
1402
    """Show differences in the working tree, between revisions or branches.
1382
1403
    
1383
 
    If files are listed, only the changes in those files are listed.
1384
 
    Otherwise, all changes for the tree are listed.
 
1404
    If no arguments are given, all changes for the current tree are listed.
 
1405
    If files are given, only the changes in those files are listed.
 
1406
    Remote and multiple branches can be compared by using the --old and
 
1407
    --new options. If not provided, the default for both is derived from
 
1408
    the first argument, if any, or the current tree if no arguments are
 
1409
    given.
1385
1410
 
1386
1411
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1387
1412
    produces patches suitable for "patch -p1".
1405
1430
 
1406
1431
            bzr diff -r1..2
1407
1432
 
 
1433
        Difference between revision 2 and revision 1 for branch xxx::
 
1434
 
 
1435
            bzr diff -r1..2 xxx
 
1436
 
 
1437
        Show just the differences for file NEWS::
 
1438
 
 
1439
            bzr diff NEWS
 
1440
 
 
1441
        Show the differences in working tree xxx for file NEWS::
 
1442
 
 
1443
            bzr diff xxx/NEWS
 
1444
 
 
1445
        Show the differences from branch xxx to this working tree:
 
1446
 
 
1447
            bzr diff --old xxx
 
1448
 
 
1449
        Show the differences between two branches for file NEWS::
 
1450
 
 
1451
            bzr diff --old xxx --new yyy NEWS
 
1452
 
1408
1453
        Same as 'bzr diff' but prefix paths with old/ and new/::
1409
1454
 
1410
1455
            bzr diff --prefix old/:new/
1411
 
 
1412
 
        Show the differences between the two working trees::
1413
 
 
1414
 
            bzr diff bzr.mine bzr.dev
1415
 
 
1416
 
        Show just the differences for 'foo.c'::
1417
 
 
1418
 
            bzr diff foo.c
1419
1456
    """
1420
 
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1421
 
    #       or a graphical diff.
1422
 
 
1423
 
    # TODO: Python difflib is not exactly the same as unidiff; should
1424
 
    #       either fix it up or prefer to use an external diff.
1425
 
 
1426
 
    # TODO: Selected-file diff is inefficient and doesn't show you
1427
 
    #       deleted files.
1428
 
 
1429
 
    # TODO: This probably handles non-Unix newlines poorly.
1430
 
 
1431
1457
    _see_also = ['status']
1432
1458
    takes_args = ['file*']
1433
1459
    takes_options = [
1437
1463
               short_name='p',
1438
1464
               help='Set prefixes added to old and new filenames, as '
1439
1465
                    'two values separated by a colon. (eg "old/:new/").'),
 
1466
        Option('old',
 
1467
            help='Branch/tree to compare from.',
 
1468
            type=unicode,
 
1469
            ),
 
1470
        Option('new',
 
1471
            help='Branch/tree to compare to.',
 
1472
            type=unicode,
 
1473
            ),
1440
1474
        'revision',
1441
1475
        'change',
 
1476
        Option('using',
 
1477
            help='Use this command to compare files.',
 
1478
            type=unicode,
 
1479
            ),
1442
1480
        ]
1443
1481
    aliases = ['di', 'dif']
1444
1482
    encoding_type = 'exact'
1445
1483
 
1446
1484
    @display_command
1447
1485
    def run(self, revision=None, file_list=None, diff_options=None,
1448
 
            prefix=None):
1449
 
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
 
1486
            prefix=None, old=None, new=None, using=None):
 
1487
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1450
1488
 
1451
1489
        if (prefix is None) or (prefix == '0'):
1452
1490
            # diff -p0 format
1466
1504
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1467
1505
                                         ' one or two revision specifiers')
1468
1506
 
1469
 
        try:
1470
 
            tree1, file_list = internal_tree_files(file_list)
1471
 
            tree2 = None
1472
 
            b = None
1473
 
            b2 = None
1474
 
        except errors.FileInWrongBranch:
1475
 
            if len(file_list) != 2:
1476
 
                raise errors.BzrCommandError("Files are in different branches")
1477
 
 
1478
 
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1479
 
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1480
 
            if file1 != "" or file2 != "":
1481
 
                # FIXME diff those two files. rbc 20051123
1482
 
                raise errors.BzrCommandError("Files are in different branches")
1483
 
            file_list = None
1484
 
        except errors.NotBranchError:
1485
 
            if (revision is not None and len(revision) == 2
1486
 
                and not revision[0].needs_branch()
1487
 
                and not revision[1].needs_branch()):
1488
 
                # If both revision specs include a branch, we can
1489
 
                # diff them without needing a local working tree
1490
 
                tree1, tree2 = None, None
1491
 
            else:
1492
 
                raise
1493
 
 
1494
 
        if tree2 is not None:
1495
 
            if revision is not None:
1496
 
                # FIXME: but there should be a clean way to diff between
1497
 
                # non-default versions of two trees, it's not hard to do
1498
 
                # internally...
1499
 
                raise errors.BzrCommandError(
1500
 
                        "Sorry, diffing arbitrary revisions across branches "
1501
 
                        "is not implemented yet")
1502
 
            return show_diff_trees(tree1, tree2, sys.stdout, 
1503
 
                                   specific_files=file_list,
1504
 
                                   external_diff_options=diff_options,
1505
 
                                   old_label=old_label, new_label=new_label)
1506
 
 
1507
 
        return diff_cmd_helper(tree1, file_list, diff_options,
1508
 
                               revision_specs=revision,
1509
 
                               old_label=old_label, new_label=new_label)
 
1507
        old_tree, new_tree, specific_files, extra_trees = \
 
1508
                _get_trees_to_diff(file_list, revision, old, new)
 
1509
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
 
1510
                               specific_files=specific_files,
 
1511
                               external_diff_options=diff_options,
 
1512
                               old_label=old_label, new_label=new_label,
 
1513
                               extra_trees=extra_trees, using=using)
1510
1514
 
1511
1515
 
1512
1516
class cmd_deleted(Command):
1654
1658
                        'regular expression.',
1655
1659
                   type=str),
1656
1660
            Option('limit',
 
1661
                   short_name='l',
1657
1662
                   help='Limit the output to the first N revisions.',
1658
1663
                   argname='N',
1659
1664
                   type=_parse_limit),
1915
1920
 
1916
1921
        Ignore class files in all directories::
1917
1922
 
1918
 
            bzr ignore '*.class'
1919
 
 
1920
 
        Ignore .o files under the lib directory::
1921
 
 
1922
 
            bzr ignore 'lib/**/*.o'
1923
 
 
1924
 
        Ignore .o files under the lib directory::
1925
 
 
1926
 
            bzr ignore 'RE:lib/.*\.o'
 
1923
            bzr ignore "*.class"
 
1924
 
 
1925
        Ignore .o files under the lib directory::
 
1926
 
 
1927
            bzr ignore "lib/**/*.o"
 
1928
 
 
1929
        Ignore .o files under the lib directory::
 
1930
 
 
1931
            bzr ignore "RE:lib/.*\.o"
1927
1932
    """
1928
1933
 
1929
1934
    _see_also = ['status', 'ignored']
1997
2002
    """List ignored files and the patterns that matched them.
1998
2003
    """
1999
2004
 
 
2005
    encoding_type = 'replace'
2000
2006
    _see_also = ['ignore']
 
2007
 
2001
2008
    @display_command
2002
2009
    def run(self):
2003
2010
        tree = WorkingTree.open_containing(u'.')[0]
2008
2015
                    continue
2009
2016
                ## XXX: Slightly inefficient since this was already calculated
2010
2017
                pat = tree.is_ignored(path)
2011
 
                print '%-50s %s' % (path, pat)
 
2018
                self.outf.write('%-50s %s\n' % (path, pat))
2012
2019
        finally:
2013
2020
            tree.unlock()
2014
2021
 
2114
2121
    def run(self, filename, revision=None, name_from_revision=False):
2115
2122
        if revision is not None and len(revision) != 1:
2116
2123
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2117
 
                                        " one number")
2118
 
 
2119
 
        tree = None
 
2124
                                         " one revision specifier")
 
2125
        tree, branch, relpath = \
 
2126
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2127
        branch.lock_read()
2120
2128
        try:
2121
 
            tree, b, relpath = \
2122
 
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2123
 
        except errors.NotBranchError:
2124
 
            pass
 
2129
            return self._run(tree, branch, relpath, filename, revision,
 
2130
                             name_from_revision)
 
2131
        finally:
 
2132
            branch.unlock()
2125
2133
 
2126
 
        if revision is not None and revision[0].get_branch() is not None:
2127
 
            b = Branch.open(revision[0].get_branch())
 
2134
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
2128
2135
        if tree is None:
2129
2136
            tree = b.basis_tree()
2130
2137
        if revision is None:
2219
2226
                    "files in the working tree."),
2220
2227
             ListOption('fixes', type=str,
2221
2228
                    help="Mark a bug as being fixed by this revision."),
2222
 
             Option('author', type=str,
 
2229
             Option('author', type=unicode,
2223
2230
                    help="Set the author's name, if it's different "
2224
2231
                         "from the committer."),
2225
2232
             Option('local',
2437
2444
 
2438
2445
        Set the current user::
2439
2446
 
2440
 
            bzr whoami 'Frank Chu <fchu@example.com>'
 
2447
            bzr whoami "Frank Chu <fchu@example.com>"
2441
2448
    """
2442
2449
    takes_options = [ Option('email',
2443
2450
                             help='Display email address only.'),
2592
2599
                                 ' expression.'),
2593
2600
                     Option('strict', help='Fail on missing dependencies or '
2594
2601
                            'known failures.'),
 
2602
                     Option('load-list', type=str, argname='TESTLISTFILE',
 
2603
                            help='Load a test id list from a text file.'),
2595
2604
                     ]
2596
2605
    encoding_type = 'replace'
2597
2606
 
2599
2608
            transport=None, benchmark=None,
2600
2609
            lsprof_timed=None, cache_dir=None,
2601
2610
            first=False, list_only=False,
2602
 
            randomize=None, exclude=None, strict=False):
 
2611
            randomize=None, exclude=None, strict=False,
 
2612
            load_list=None):
2603
2613
        import bzrlib.ui
2604
2614
        from bzrlib.tests import selftest
2605
2615
        import bzrlib.benchmarks as benchmarks
2641
2651
                              random_seed=randomize,
2642
2652
                              exclude_pattern=exclude,
2643
2653
                              strict=strict,
 
2654
                              load_list=load_list,
2644
2655
                              )
2645
2656
        finally:
2646
2657
            if benchfile is not None:
2686
2697
        
2687
2698
        branch1 = Branch.open_containing(branch)[0]
2688
2699
        branch2 = Branch.open_containing(other)[0]
2689
 
 
2690
 
        last1 = ensure_null(branch1.last_revision())
2691
 
        last2 = ensure_null(branch2.last_revision())
2692
 
 
2693
 
        graph = branch1.repository.get_graph(branch2.repository)
2694
 
        base_rev_id = graph.find_unique_lca(last1, last2)
2695
 
 
2696
 
        print 'merge base is revision %s' % base_rev_id
 
2700
        branch1.lock_read()
 
2701
        try:
 
2702
            branch2.lock_read()
 
2703
            try:
 
2704
                last1 = ensure_null(branch1.last_revision())
 
2705
                last2 = ensure_null(branch2.last_revision())
 
2706
 
 
2707
                graph = branch1.repository.get_graph(branch2.repository)
 
2708
                base_rev_id = graph.find_unique_lca(last1, last2)
 
2709
 
 
2710
                print 'merge base is revision %s' % base_rev_id
 
2711
            finally:
 
2712
                branch2.unlock()
 
2713
        finally:
 
2714
            branch1.unlock()
2697
2715
 
2698
2716
 
2699
2717
class cmd_merge(Command):
2742
2760
            bzr merge -r 81..82 ../bzr.dev
2743
2761
    """
2744
2762
 
 
2763
    encoding_type = 'exact'
2745
2764
    _see_also = ['update', 'remerge', 'status-flags']
2746
2765
    takes_args = ['branch?']
2747
2766
    takes_options = [
2766
2785
               short_name='d',
2767
2786
               type=unicode,
2768
2787
               ),
 
2788
        Option('preview', help='Instead of merging, show a diff of the merge.')
2769
2789
    ]
2770
2790
 
2771
2791
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2772
2792
            show_base=False, reprocess=False, remember=False,
2773
2793
            uncommitted=False, pull=False,
2774
2794
            directory=None,
 
2795
            preview=False,
2775
2796
            ):
2776
2797
        # This is actually a branch (or merge-directive) *location*.
2777
2798
        location = branch
2817
2838
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2818
2839
                    pb)
2819
2840
                allow_pending = False
 
2841
                if other_path != '':
 
2842
                    merger.interesting_files = [other_path]
2820
2843
 
2821
2844
            if merger is None:
2822
2845
                merger, allow_pending = self._get_merger_from_branch(tree,
2825
2848
            merger.merge_type = merge_type
2826
2849
            merger.reprocess = reprocess
2827
2850
            merger.show_base = show_base
2828
 
            merger.change_reporter = change_reporter
2829
2851
            self.sanity_check_merger(merger)
2830
2852
            if (merger.base_rev_id == merger.other_rev_id and
2831
2853
                merger.other_rev_id != None):
2840
2862
                    result.report(self.outf)
2841
2863
                    return 0
2842
2864
            merger.check_basis(not force)
2843
 
            conflict_count = merger.do_merge()
2844
 
            if allow_pending:
2845
 
                merger.set_pending()
2846
 
            if verified == 'failed':
2847
 
                warning('Preview patch does not match changes')
2848
 
            if conflict_count != 0:
2849
 
                return 1
 
2865
            if preview:
 
2866
                return self._do_preview(merger)
2850
2867
            else:
2851
 
                return 0
 
2868
                return self._do_merge(merger, change_reporter, allow_pending,
 
2869
                                      verified)
2852
2870
        finally:
2853
2871
            for cleanup in reversed(cleanups):
2854
2872
                cleanup()
2855
2873
 
 
2874
    def _do_preview(self, merger):
 
2875
        from bzrlib.diff import show_diff_trees
 
2876
        tree_merger = merger.make_merger()
 
2877
        tt = tree_merger.make_preview_transform()
 
2878
        try:
 
2879
            result_tree = tt.get_preview_tree()
 
2880
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
2881
                            old_label='', new_label='')
 
2882
        finally:
 
2883
            tt.finalize()
 
2884
 
 
2885
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
 
2886
        merger.change_reporter = change_reporter
 
2887
        conflict_count = merger.do_merge()
 
2888
        if allow_pending:
 
2889
            merger.set_pending()
 
2890
        if verified == 'failed':
 
2891
            warning('Preview patch does not match changes')
 
2892
        if conflict_count != 0:
 
2893
            return 1
 
2894
        else:
 
2895
            return 0
 
2896
 
2856
2897
    def sanity_check_merger(self, merger):
2857
2898
        if (merger.show_base and
2858
2899
            not merger.merge_type is _mod_merge.Merge3Merger):
2872
2913
        from bzrlib.tag import _merge_tags_if_possible
2873
2914
        assert revision is None or len(revision) < 3
2874
2915
        # find the branch locations
2875
 
        other_loc, location = self._select_branch_location(tree, location,
 
2916
        other_loc, user_location = self._select_branch_location(tree, location,
2876
2917
            revision, -1)
2877
2918
        if revision is not None and len(revision) == 2:
2878
 
            base_loc, location = self._select_branch_location(tree, location,
2879
 
                                                              revision, 0)
 
2919
            base_loc, _unused = self._select_branch_location(tree,
 
2920
                location, revision, 0)
2880
2921
        else:
2881
2922
            base_loc = other_loc
2882
2923
        # Open the branches
2903
2944
        else:
2904
2945
            base_revision_id = None
2905
2946
        # Remember where we merge from
2906
 
        if ((tree.branch.get_parent() is None or remember) and
2907
 
            other_branch is not None):
2908
 
            tree.branch.set_parent(other_branch.base)
 
2947
        if ((remember or tree.branch.get_submit_branch() is None) and
 
2948
             user_location is not None):
 
2949
            tree.branch.set_submit_branch(other_branch.base)
2909
2950
        _merge_tags_if_possible(other_branch, tree.branch)
2910
2951
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2911
2952
            other_revision_id, base_revision_id, other_branch, base_branch)
2916
2957
            allow_pending = True
2917
2958
        return merger, allow_pending
2918
2959
 
2919
 
    def _select_branch_location(self, tree, location, revision=None,
 
2960
    def _select_branch_location(self, tree, user_location, revision=None,
2920
2961
                                index=None):
2921
2962
        """Select a branch location, according to possible inputs.
2922
2963
 
2924
2965
        ``revision`` and ``index`` must be supplied.)
2925
2966
 
2926
2967
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2927
 
        ``parent`` location is used, and a note is printed.
 
2968
        ``submit`` or ``parent`` location is used, and a note is printed.
2928
2969
 
2929
2970
        :param tree: The working tree to select a branch for merging into
2930
2971
        :param location: The location entered by the user
2931
2972
        :param revision: The revision parameter to the command
2932
2973
        :param index: The index to use for the revision parameter.  Negative
2933
2974
            indices are permitted.
2934
 
        :return: (selected_location, default_location).  The default location
2935
 
            will be the user-entered location, if any, or else the remembered
2936
 
            location.
 
2975
        :return: (selected_location, user_location).  The default location
 
2976
            will be the user-entered location.
2937
2977
        """
2938
2978
        if (revision is not None and index is not None
2939
2979
            and revision[index] is not None):
2940
2980
            branch = revision[index].get_branch()
2941
2981
            if branch is not None:
2942
 
                return branch, location
2943
 
        location = self._get_remembered_parent(tree, location, 'Merging from')
2944
 
        return location, location
 
2982
                return branch, branch
 
2983
        if user_location is None:
 
2984
            location = self._get_remembered(tree, 'Merging from')
 
2985
        else:
 
2986
            location = user_location
 
2987
        return location, user_location
2945
2988
 
2946
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2947
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
2989
    def _get_remembered(self, tree, verb_string):
2948
2990
        """Use tree.branch's parent if none was supplied.
2949
2991
 
2950
2992
        Report if the remembered location was used.
2951
2993
        """
2952
 
        if supplied_location is not None:
2953
 
            return supplied_location
2954
 
        stored_location = tree.branch.get_parent()
 
2994
        stored_location = tree.branch.get_submit_branch()
 
2995
        if stored_location is None:
 
2996
            stored_location = tree.branch.get_parent()
2955
2997
        mutter("%s", stored_location)
2956
2998
        if stored_location is None:
2957
2999
            raise errors.BzrCommandError("No location specified or remembered")
3005
3047
                                             " merges.  Not cherrypicking or"
3006
3048
                                             " multi-merges.")
3007
3049
            repository = tree.branch.repository
3008
 
            graph = repository.get_graph()
3009
 
            base_revision = graph.find_unique_lca(parents[0], parents[1])
3010
 
            base_tree = repository.revision_tree(base_revision)
3011
 
            other_tree = repository.revision_tree(parents[1])
3012
3050
            interesting_ids = None
3013
3051
            new_conflicts = []
3014
3052
            conflicts = tree.conflicts()
3044
3082
            # list, we imply that the working tree text has seen and rejected
3045
3083
            # all the changes from the other tree, when in fact those changes
3046
3084
            # have not yet been seen.
 
3085
            pb = ui.ui_factory.nested_progress_bar()
3047
3086
            tree.set_parent_ids(parents[:1])
3048
3087
            try:
3049
 
                conflicts = _mod_merge.merge_inner(
3050
 
                                          tree.branch, other_tree, base_tree,
3051
 
                                          this_tree=tree,
3052
 
                                          interesting_ids=interesting_ids,
3053
 
                                          other_rev_id=parents[1],
3054
 
                                          merge_type=merge_type,
3055
 
                                          show_base=show_base,
3056
 
                                          reprocess=reprocess)
 
3088
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3089
                                                             tree, parents[1])
 
3090
                merger.interesting_ids = interesting_ids
 
3091
                merger.merge_type = merge_type
 
3092
                merger.show_base = show_base
 
3093
                merger.reprocess = reprocess
 
3094
                conflicts = merger.do_merge()
3057
3095
            finally:
3058
3096
                tree.set_parent_ids(parents)
 
3097
                pb.finished()
3059
3098
        finally:
3060
3099
            tree.unlock()
3061
3100
        if conflicts > 0:
3072
3111
    last committed revision is used.
3073
3112
 
3074
3113
    To remove only some changes, without reverting to a prior version, use
3075
 
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
3076
 
    introduced by -2, without affecting the changes introduced by -1.  Or
3077
 
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
3114
    merge instead.  For example, "merge . --revision -2..-3" will remove the
 
3115
    changes introduced by -2, without affecting the changes introduced by -1.
 
3116
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3078
3117
    
3079
3118
    By default, any files that have been manually changed will be backed up
3080
3119
    first.  (Files changed only by merge are not backed up.)  Backup files have
3091
3130
 
3092
3131
    The working tree contains a list of pending merged revisions, which will
3093
3132
    be included as parents in the next commit.  Normally, revert clears that
3094
 
    list as well as reverting the files.  If any files, are specified, revert
3095
 
    leaves the pending merge list alnone and reverts only the files.  Use "bzr
 
3133
    list as well as reverting the files.  If any files are specified, revert
 
3134
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3096
3135
    revert ." in the tree root to revert all files but keep the merge record,
3097
3136
    and "bzr revert --forget-merges" to clear the pending merge list without
3098
3137
    reverting any files.
3310
3349
class cmd_plugins(Command):
3311
3350
    """List the installed plugins.
3312
3351
    
3313
 
    This command displays the list of installed plugins including the
3314
 
    path where each one is located and a short description of each.
 
3352
    This command displays the list of installed plugins including
 
3353
    version of plugin and a short description of each.
 
3354
 
 
3355
    --verbose shows the path where each plugin is located.
3315
3356
 
3316
3357
    A plugin is an external component for Bazaar that extends the
3317
3358
    revision control system, by adding or replacing code in Bazaar.
3324
3365
    install them. Instructions are also provided there on how to
3325
3366
    write new plugins using the Python programming language.
3326
3367
    """
 
3368
    takes_options = ['verbose']
3327
3369
 
3328
3370
    @display_command
3329
 
    def run(self):
 
3371
    def run(self, verbose=False):
3330
3372
        import bzrlib.plugin
3331
3373
        from inspect import getdoc
 
3374
        result = []
3332
3375
        for name, plugin in bzrlib.plugin.plugins().items():
3333
 
            print plugin.path(), "[%s]" % plugin.__version__
 
3376
            version = plugin.__version__
 
3377
            if version == 'unknown':
 
3378
                version = ''
 
3379
            name_ver = '%s %s' % (name, version)
3334
3380
            d = getdoc(plugin.module)
3335
3381
            if d:
3336
 
                print '\t', d.split('\n')[0]
 
3382
                doc = d.split('\n')[0]
 
3383
            else:
 
3384
                doc = '(no description)'
 
3385
            result.append((name_ver, doc, plugin.path()))
 
3386
        for name_ver, doc, path in sorted(result):
 
3387
            print name_ver
 
3388
            print '   ', doc
 
3389
            if verbose:
 
3390
                print '   ', path
 
3391
            print
3337
3392
 
3338
3393
 
3339
3394
class cmd_testament(Command):
3392
3447
    def run(self, filename, all=False, long=False, revision=None,
3393
3448
            show_ids=False):
3394
3449
        from bzrlib.annotate import annotate_file
3395
 
        tree, relpath = WorkingTree.open_containing(filename)
3396
 
        branch = tree.branch
3397
 
        branch.lock_read()
 
3450
        wt, branch, relpath = \
 
3451
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
3452
        if wt is not None:
 
3453
            wt.lock_read()
 
3454
        else:
 
3455
            branch.lock_read()
3398
3456
        try:
3399
3457
            if revision is None:
3400
3458
                revision_id = branch.last_revision()
3402
3460
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3403
3461
            else:
3404
3462
                revision_id = revision[0].in_history(branch).rev_id
3405
 
            file_id = tree.path2id(relpath)
 
3463
            tree = branch.repository.revision_tree(revision_id)
 
3464
            if wt is not None:
 
3465
                file_id = wt.path2id(relpath)
 
3466
            else:
 
3467
                file_id = tree.path2id(relpath)
3406
3468
            if file_id is None:
3407
3469
                raise errors.NotVersionedError(filename)
3408
 
            tree = branch.repository.revision_tree(revision_id)
3409
3470
            file_version = tree.inventory[file_id].revision
3410
3471
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3411
3472
                          show_ids=show_ids)
3412
3473
        finally:
3413
 
            branch.unlock()
 
3474
            if wt is not None:
 
3475
                wt.unlock()
 
3476
            else:
 
3477
                branch.unlock()
3414
3478
 
3415
3479
 
3416
3480
class cmd_re_sign(Command):
3422
3486
    takes_options = ['revision']
3423
3487
    
3424
3488
    def run(self, revision_id_list=None, revision=None):
3425
 
        import bzrlib.gpg as gpg
3426
3489
        if revision_id_list is not None and revision is not None:
3427
3490
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3428
3491
        if revision_id_list is None and revision is None:
3429
3492
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3430
3493
        b = WorkingTree.open_containing(u'.')[0].branch
 
3494
        b.lock_write()
 
3495
        try:
 
3496
            return self._run(b, revision_id_list, revision)
 
3497
        finally:
 
3498
            b.unlock()
 
3499
 
 
3500
    def _run(self, b, revision_id_list, revision):
 
3501
        import bzrlib.gpg as gpg
3431
3502
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3432
3503
        if revision_id_list is not None:
3433
 
            for revision_id in revision_id_list:
3434
 
                b.repository.sign_revision(revision_id, gpg_strategy)
 
3504
            b.repository.start_write_group()
 
3505
            try:
 
3506
                for revision_id in revision_id_list:
 
3507
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
3508
            except:
 
3509
                b.repository.abort_write_group()
 
3510
                raise
 
3511
            else:
 
3512
                b.repository.commit_write_group()
3435
3513
        elif revision is not None:
3436
3514
            if len(revision) == 1:
3437
3515
                revno, rev_id = revision[0].in_history(b)
3438
 
                b.repository.sign_revision(rev_id, gpg_strategy)
 
3516
                b.repository.start_write_group()
 
3517
                try:
 
3518
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
3519
                except:
 
3520
                    b.repository.abort_write_group()
 
3521
                    raise
 
3522
                else:
 
3523
                    b.repository.commit_write_group()
3439
3524
            elif len(revision) == 2:
3440
3525
                # are they both on rh- if so we can walk between them
3441
3526
                # might be nice to have a range helper for arbitrary
3446
3531
                    to_revno = b.revno()
3447
3532
                if from_revno is None or to_revno is None:
3448
3533
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3449
 
                for revno in range(from_revno, to_revno + 1):
3450
 
                    b.repository.sign_revision(b.get_rev_id(revno), 
3451
 
                                               gpg_strategy)
 
3534
                b.repository.start_write_group()
 
3535
                try:
 
3536
                    for revno in range(from_revno, to_revno + 1):
 
3537
                        b.repository.sign_revision(b.get_rev_id(revno),
 
3538
                                                   gpg_strategy)
 
3539
                except:
 
3540
                    b.repository.abort_write_group()
 
3541
                    raise
 
3542
                else:
 
3543
                    b.repository.commit_write_group()
3452
3544
            else:
3453
3545
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3454
3546
 
3526
3618
                    Option('force', help='Say yes to all questions.')]
3527
3619
    takes_args = ['location?']
3528
3620
    aliases = []
 
3621
    encoding_type = 'replace'
3529
3622
 
3530
3623
    def run(self, location=None,
3531
3624
            dry_run=False, verbose=False,
3532
3625
            revision=None, force=False):
3533
 
        from bzrlib.log import log_formatter, show_log
3534
 
        from bzrlib.uncommit import uncommit
3535
 
 
3536
3626
        if location is None:
3537
3627
            location = u'.'
3538
3628
        control, relpath = bzrdir.BzrDir.open_containing(location)
3543
3633
            tree = None
3544
3634
            b = control.open_branch()
3545
3635
 
 
3636
        if tree is not None:
 
3637
            tree.lock_write()
 
3638
        else:
 
3639
            b.lock_write()
 
3640
        try:
 
3641
            return self._run(b, tree, dry_run, verbose, revision, force)
 
3642
        finally:
 
3643
            if tree is not None:
 
3644
                tree.unlock()
 
3645
            else:
 
3646
                b.unlock()
 
3647
 
 
3648
    def _run(self, b, tree, dry_run, verbose, revision, force):
 
3649
        from bzrlib.log import log_formatter, show_log
 
3650
        from bzrlib.uncommit import uncommit
 
3651
 
 
3652
        last_revno, last_rev_id = b.last_revision_info()
 
3653
 
3546
3654
        rev_id = None
3547
3655
        if revision is None:
3548
 
            revno = b.revno()
 
3656
            revno = last_revno
 
3657
            rev_id = last_rev_id
3549
3658
        else:
3550
3659
            # 'bzr uncommit -r 10' actually means uncommit
3551
3660
            # so that the final tree is at revno 10.
3552
3661
            # but bzrlib.uncommit.uncommit() actually uncommits
3553
3662
            # the revisions that are supplied.
3554
3663
            # So we need to offset it by one
3555
 
            revno = revision[0].in_history(b).revno+1
 
3664
            revno = revision[0].in_history(b).revno + 1
 
3665
            if revno <= last_revno:
 
3666
                rev_id = b.get_rev_id(revno)
3556
3667
 
3557
 
        if revno <= b.revno():
3558
 
            rev_id = b.get_rev_id(revno)
3559
3668
        if rev_id is None or _mod_revision.is_null(rev_id):
3560
3669
            self.outf.write('No revisions to uncommit.\n')
3561
3670
            return 1
3569
3678
                 verbose=False,
3570
3679
                 direction='forward',
3571
3680
                 start_revision=revno,
3572
 
                 end_revision=b.revno())
 
3681
                 end_revision=last_revno)
3573
3682
 
3574
3683
        if dry_run:
3575
3684
            print 'Dry-run, pretending to remove the above revisions.'
3584
3693
                    return 0
3585
3694
 
3586
3695
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3587
 
                revno=revno)
 
3696
                 revno=revno)
3588
3697
 
3589
3698
 
3590
3699
class cmd_break_lock(Command):
3649
3758
        ]
3650
3759
 
3651
3760
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
3761
        from bzrlib import lockdir
3652
3762
        from bzrlib.smart import medium, server
3653
3763
        from bzrlib.transport import get_transport
3654
3764
        from bzrlib.transport.chroot import ChrootServer
3655
 
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3656
3765
        if directory is None:
3657
3766
            directory = os.getcwd()
3658
3767
        url = urlutils.local_path_to_url(directory)
3665
3774
            smart_server = medium.SmartServerPipeStreamMedium(
3666
3775
                sys.stdin, sys.stdout, t)
3667
3776
        else:
3668
 
            host = BZR_DEFAULT_INTERFACE
 
3777
            host = medium.BZR_DEFAULT_INTERFACE
3669
3778
            if port is None:
3670
 
                port = BZR_DEFAULT_PORT
 
3779
                port = medium.BZR_DEFAULT_PORT
3671
3780
            else:
3672
3781
                if ':' in port:
3673
3782
                    host, port = port.split(':')
3680
3789
        # be changed with care though, as we dont want to use bandwidth sending
3681
3790
        # progress over stderr to smart server clients!
3682
3791
        old_factory = ui.ui_factory
 
3792
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3683
3793
        try:
3684
3794
            ui.ui_factory = ui.SilentUIFactory()
 
3795
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3685
3796
            smart_server.serve()
3686
3797
        finally:
3687
3798
            ui.ui_factory = old_factory
 
3799
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3688
3800
 
3689
3801
 
3690
3802
class cmd_join(Command):
3742
3854
 
3743
3855
 
3744
3856
class cmd_split(Command):
3745
 
    """Split a tree into two trees.
 
3857
    """Split a subdirectory of a tree into a separate tree.
3746
3858
 
3747
 
    This command is for experimental use only.  It requires the target tree
3748
 
    to be in dirstate-with-subtree format, which cannot be converted into
3749
 
    earlier formats.
 
3859
    This command will produce a target tree in a format that supports
 
3860
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
 
3861
    converted into earlier formats like 'dirstate-tags'.
3750
3862
 
3751
3863
    The TREE argument should be a subdirectory of a working tree.  That
3752
3864
    subdirectory will be converted into an independent tree, with its own
3753
3865
    branch.  Commits in the top-level tree will not apply to the new subtree.
3754
 
    If you want that behavior, do "bzr join --reference TREE".
3755
3866
    """
3756
3867
 
3757
 
    _see_also = ['join']
 
3868
    # join is not un-hidden yet
 
3869
    #_see_also = ['join']
3758
3870
    takes_args = ['tree']
3759
3871
 
3760
 
    hidden = True
3761
 
 
3762
3872
    def run(self, tree):
3763
3873
        containing_tree, subdir = WorkingTree.open_containing(tree)
3764
3874
        sub_id = containing_tree.path2id(subdir)
3770
3880
            raise errors.UpgradeRequired(containing_tree.branch.base)
3771
3881
 
3772
3882
 
3773
 
 
3774
3883
class cmd_merge_directive(Command):
3775
3884
    """Generate a merge directive for auto-merge tools.
3776
3885
 
3898
4007
    for that mirror.
3899
4008
 
3900
4009
    Mail is sent using your preferred mail program.  This should be transparent
3901
 
    on Windows (it uses MAPI).  On *nix, it requires the xdg-email utility.  If
3902
 
    the preferred client can't be found (or used), your editor will be used.
 
4010
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
4011
    If the preferred client can't be found (or used), your editor will be used.
3903
4012
    
3904
4013
    To use a specific mail program, set the mail_client configuration option.
3905
4014
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
3957
4066
    def _run(self, submit_branch, revision, public_branch, remember, format,
3958
4067
             no_bundle, no_patch, output, from_, mail_to, message):
3959
4068
        from bzrlib.revision import NULL_REVISION
 
4069
        branch = Branch.open_containing(from_)[0]
3960
4070
        if output is None:
3961
4071
            outfile = StringIO()
3962
4072
        elif output == '-':
3963
4073
            outfile = self.outf
3964
4074
        else:
3965
4075
            outfile = open(output, 'wb')
 
4076
        # we may need to write data into branch's repository to calculate
 
4077
        # the data to send.
 
4078
        branch.lock_write()
3966
4079
        try:
3967
 
            branch = Branch.open_containing(from_)[0]
3968
4080
            if output is None:
3969
4081
                config = branch.get_config()
3970
4082
                if mail_to is None:
3971
4083
                    mail_to = config.get_user_option('submit_to')
3972
 
                if mail_to is None:
3973
 
                    raise errors.BzrCommandError('No mail-to address'
3974
 
                                                 ' specified')
3975
4084
                mail_client = config.get_mail_client()
3976
4085
            if remember and submit_branch is None:
3977
4086
                raise errors.BzrCommandError(
4052
4161
        finally:
4053
4162
            if output != '-':
4054
4163
                outfile.close()
 
4164
            branch.unlock()
4055
4165
 
4056
4166
 
4057
4167
class cmd_bundle_revisions(cmd_send):
4187
4297
class cmd_tags(Command):
4188
4298
    """List tags.
4189
4299
 
4190
 
    This tag shows a table of tag names and the revisions they reference.
 
4300
    This command shows a table of tag names and the revisions they reference.
4191
4301
    """
4192
4302
 
4193
4303
    _see_also = ['tag']
4256
4366
                     value_switches=True, enum_switch=False,
4257
4367
                     branch='Reconfigure to a branch.',
4258
4368
                     tree='Reconfigure to a tree.',
4259
 
                     checkout='Reconfigure to a checkout.'),
 
4369
                     checkout='Reconfigure to a checkout.',
 
4370
                     lightweight_checkout='Reconfigure to a lightweight'
 
4371
                     ' checkout.'),
4260
4372
                     Option('bind-to', help='Branch to bind checkout to.',
4261
4373
                            type=str),
4262
4374
                     Option('force',
4275
4387
        elif target_type == 'checkout':
4276
4388
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4277
4389
                                                                  bind_to)
 
4390
        elif target_type == 'lightweight-checkout':
 
4391
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
 
4392
                directory, bind_to)
4278
4393
        reconfiguration.apply(force)
4279
4394
 
4280
4395
 
 
4396
class cmd_switch(Command):
 
4397
    """Set the branch of a checkout and update.
 
4398
    
 
4399
    For lightweight checkouts, this changes the branch being referenced.
 
4400
    For heavyweight checkouts, this checks that there are no local commits
 
4401
    versus the current bound branch, then it makes the local branch a mirror
 
4402
    of the new location and binds to it.
 
4403
    
 
4404
    In both cases, the working tree is updated and uncommitted changes
 
4405
    are merged. The user can commit or revert these as they desire.
 
4406
 
 
4407
    Pending merges need to be committed or reverted before using switch.
 
4408
    """
 
4409
 
 
4410
    takes_args = ['to_location']
 
4411
    takes_options = [Option('force',
 
4412
                        help='Switch even if local commits will be lost.')
 
4413
                     ]
 
4414
 
 
4415
    def run(self, to_location, force=False):
 
4416
        from bzrlib import switch
 
4417
        to_branch = Branch.open(to_location)
 
4418
        tree_location = '.'
 
4419
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
4420
        switch.switch(control_dir, to_branch, force)
 
4421
        note('Switched to branch: %s',
 
4422
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
4423
 
 
4424
 
4281
4425
def _create_prefix(cur_transport):
4282
4426
    needed = [cur_transport]
4283
4427
    # Recurse upwards until we can create a directory successfully