/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: Martin Pool
  • Date: 2007-09-14 06:31:28 UTC
  • mfrom: (2822 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2823.
  • Revision ID: mbp@sourcefrog.net-20070914063128-0p7mh6zfb4pzdg9p
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
    urlutils,
54
54
    )
55
55
from bzrlib.branch import Branch
56
 
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
57
56
from bzrlib.conflicts import ConflictList
58
57
from bzrlib.revisionspec import RevisionSpec
59
58
from bzrlib.smtp_connection import SMTPConnection
61
60
""")
62
61
 
63
62
from bzrlib.commands import Command, display_command
64
 
from bzrlib.option import ListOption, Option, RegistryOption
 
63
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
65
64
from bzrlib.progress import DummyProgress, ProgressPhase
66
65
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
67
66
 
153
152
    To see ignored files use 'bzr ignored'.  For details on the
154
153
    changes to file texts, use 'bzr diff'.
155
154
    
156
 
    --short gives a status flags for each item, similar to the SVN's status
157
 
    command.
 
155
    Note that --short or -S gives status flags for each item, similar
 
156
    to Subversion's status command. To get output similar to svn -q,
 
157
    use bzr -SV.
158
158
 
159
159
    If no arguments are specified, the status of the entire working
160
160
    directory is shown.  Otherwise, only the status of the specified
168
168
    # TODO: --no-recurse, --recurse options
169
169
    
170
170
    takes_args = ['file*']
171
 
    takes_options = ['show-ids', 'revision',
172
 
                     Option('short', help='Give short SVN-style status lines.'),
173
 
                     Option('versioned', help='Only show versioned files.')]
 
171
    takes_options = ['show-ids', 'revision', 'change',
 
172
                     Option('short', help='Use short status indicators.',
 
173
                            short_name='S'),
 
174
                     Option('versioned', help='Only show versioned files.',
 
175
                            short_name='V')
 
176
                     ]
174
177
    aliases = ['st', 'stat']
175
178
 
176
179
    encoding_type = 'replace'
181
184
            versioned=False):
182
185
        from bzrlib.status import show_tree_status
183
186
 
 
187
        if revision and len(revision) > 2:
 
188
            raise errors.BzrCommandError('bzr status --revision takes exactly'
 
189
                                         ' one or two revision specifiers')
 
190
 
184
191
        tree, file_list = tree_files(file_list)
185
192
            
186
193
        show_tree_status(tree, show_ids=show_ids,
502
509
class cmd_mv(Command):
503
510
    """Move or rename a file.
504
511
 
505
 
    usage:
 
512
    :Usage:
506
513
        bzr mv OLDNAME NEWNAME
 
514
 
507
515
        bzr mv SOURCE... DESTINATION
508
516
 
509
517
    If the last argument is a versioned directory, all the other names
568
576
    """
569
577
 
570
578
    _see_also = ['push', 'update', 'status-flags']
571
 
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
 
579
    takes_options = ['remember', 'overwrite', 'revision',
 
580
        custom_help('verbose',
 
581
            help='Show logs of pulled revisions.'),
572
582
        Option('directory',
573
583
            help='Branch to pull into, '
574
584
                 'rather than the one containing the working directory.',
582
592
    def run(self, location=None, remember=False, overwrite=False,
583
593
            revision=None, verbose=False,
584
594
            directory=None):
585
 
        from bzrlib.tag import _merge_tags_if_possible
586
595
        # FIXME: too much stuff is in the command class
587
596
        revision_id = None
588
597
        mergeable = None
595
604
            tree_to = None
596
605
            branch_to = Branch.open_containing(directory)[0]
597
606
 
598
 
        reader = None
599
607
        if location is not None:
600
 
            try:
601
 
                mergeable = bundle.read_mergeable_from_url(
602
 
                    location)
603
 
            except errors.NotABundle:
604
 
                pass # Continue on considering this url a Branch
 
608
            mergeable, location_transport = _get_mergeable_helper(location)
605
609
 
606
610
        stored_loc = branch_to.get_parent()
607
611
        if location is None:
613
617
                        self.outf.encoding)
614
618
                self.outf.write("Using saved location: %s\n" % display_url)
615
619
                location = stored_loc
 
620
                location_transport = transport.get_transport(location)
616
621
 
617
622
        if mergeable is not None:
618
623
            if revision is not None:
619
624
                raise errors.BzrCommandError(
620
625
                    'Cannot use -r with merge directives or bundles')
621
 
            revision_id = mergeable.install_revisions(branch_to.repository)
 
626
            mergeable.install_revisions(branch_to.repository)
 
627
            base_revision_id, revision_id, verified = \
 
628
                mergeable.get_merge_request(branch_to.repository)
622
629
            branch_from = branch_to
623
630
        else:
624
 
            branch_from = Branch.open(location)
 
631
            branch_from = Branch.open_from_transport(location_transport)
625
632
 
626
633
            if branch_to.get_parent() is None or remember:
627
634
                branch_to.set_parent(branch_from.base)
633
640
                raise errors.BzrCommandError(
634
641
                    'bzr pull --revision takes one value.')
635
642
 
636
 
        old_rh = branch_to.revision_history()
 
643
        if verbose:
 
644
            old_rh = branch_to.revision_history()
637
645
        if tree_to is not None:
638
646
            result = tree_to.pull(branch_from, overwrite, revision_id,
639
647
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
642
650
 
643
651
        result.report(self.outf)
644
652
        if verbose:
645
 
            from bzrlib.log import show_changed_revisions
646
653
            new_rh = branch_to.revision_history()
647
 
            show_changed_revisions(branch_to, old_rh, new_rh,
648
 
                                   to_file=self.outf)
 
654
            log.show_changed_revisions(branch_to, old_rh, new_rh,
 
655
                                       to_file=self.outf)
649
656
 
650
657
 
651
658
class cmd_push(Command):
735
742
                # Found a branch, so we must have found a repository
736
743
                repository_to = br_to.repository
737
744
        push_result = None
738
 
        old_rh = []
 
745
        if verbose:
 
746
            old_rh = []
739
747
        if dir_to is None:
740
748
            # The destination doesn't exist; create it.
741
749
            # XXX: Refactor the create_prefix/no_create_prefix code into a
791
799
            # we don't need to successfully push because of possible divergence.
792
800
            if br_from.get_push_location() is None or remember:
793
801
                br_from.set_push_location(br_to.base)
794
 
            old_rh = br_to.revision_history()
 
802
            if verbose:
 
803
                old_rh = br_to.revision_history()
795
804
            try:
796
805
                try:
797
806
                    tree_to = dir_to.open_workingtree()
881
890
                                             % to_location)
882
891
            try:
883
892
                # preserve whatever source format we have.
884
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id)
 
893
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
894
                                            possible_transports=[to_transport])
885
895
                branch = dir.open_branch()
886
896
            except errors.NoSuchRevision:
887
897
                to_transport.delete_tree('.')
941
951
            to_location = branch_location
942
952
        source = Branch.open(branch_location)
943
953
        if len(revision) == 1 and revision[0] is not None:
944
 
            revision_id = revision[0].in_history(source)[1]
 
954
            revision_id = _mod_revision.ensure_null(
 
955
                revision[0].in_history(source)[1])
945
956
        else:
946
957
            revision_id = None
947
958
        if to_location is None:
954
965
            try:
955
966
                source.bzrdir.open_workingtree()
956
967
            except errors.NoWorkingTree:
957
 
                source.bzrdir.create_workingtree()
 
968
                source.bzrdir.create_workingtree(revision_id)
958
969
                return
959
 
        try:
960
 
            os.mkdir(to_location)
961
 
        except OSError, e:
962
 
            if e.errno == errno.EEXIST:
963
 
                raise errors.BzrCommandError('Target directory "%s" already'
964
 
                                             ' exists.' % to_location)
965
 
            if e.errno == errno.ENOENT:
966
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
967
 
                                             % to_location)
968
 
            else:
969
 
                raise
970
970
        source.create_checkout(to_location, revision_id, lightweight)
971
971
 
972
972
 
1010
1010
    'bzr revert' instead of 'bzr commit' after the update.
1011
1011
    """
1012
1012
 
1013
 
    _see_also = ['pull', 'working-trees']
 
1013
    _see_also = ['pull', 'working-trees', 'status-flags']
1014
1014
    takes_args = ['dir?']
1015
1015
    aliases = ['up']
1016
1016
 
1017
1017
    def run(self, dir='.'):
1018
1018
        tree = WorkingTree.open_containing(dir)[0]
1019
 
        master = tree.branch.get_master_branch()
 
1019
        possible_transports = []
 
1020
        master = tree.branch.get_master_branch(
 
1021
            possible_transports=possible_transports)
1020
1022
        if master is not None:
1021
1023
            tree.lock_write()
1022
1024
        else:
1027
1029
            if last_rev == _mod_revision.ensure_null(
1028
1030
                tree.branch.last_revision()):
1029
1031
                # may be up to date, check master too.
1030
 
                master = tree.branch.get_master_branch()
1031
1032
                if master is None or last_rev == _mod_revision.ensure_null(
1032
1033
                    master.last_revision()):
1033
1034
                    revno = tree.branch.revision_id_to_revno(last_rev)
1034
1035
                    note("Tree is up to date at revision %d." % (revno,))
1035
1036
                    return 0
1036
 
            conflicts = tree.update(delta._ChangeReporter(
1037
 
                                        unversioned_filter=tree.is_ignored))
 
1037
            conflicts = tree.update(
 
1038
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
 
1039
                possible_transports=possible_transports)
1038
1040
            revno = tree.branch.revision_id_to_revno(
1039
1041
                _mod_revision.ensure_null(tree.last_revision()))
1040
1042
            note('Updated to revision %d.' % (revno,))
1063
1065
    takes_options = ['verbose']
1064
1066
 
1065
1067
    @display_command
1066
 
    def run(self, location=None, verbose=0):
 
1068
    def run(self, location=None, verbose=False):
 
1069
        if verbose:
 
1070
            noise_level = 2
 
1071
        else:
 
1072
            noise_level = 0
1067
1073
        from bzrlib.info import show_bzrdir_info
1068
1074
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1069
 
                         verbose=verbose)
 
1075
                         verbose=noise_level)
1070
1076
 
1071
1077
 
1072
1078
class cmd_remove(Command):
1084
1090
    takes_options = ['verbose',
1085
1091
        Option('new', help='Remove newly-added files.'),
1086
1092
        RegistryOption.from_kwargs('file-deletion-strategy',
1087
 
            'The file deletion mode to be used',
 
1093
            'The file deletion mode to be used.',
1088
1094
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1089
1095
            safe='Only delete files if they can be'
1090
1096
                 ' safely recovered (default).',
1099
1105
        tree, file_list = tree_files(file_list)
1100
1106
 
1101
1107
        if file_list is not None:
1102
 
            file_list = [f for f in file_list if f != '']
 
1108
            file_list = [f for f in file_list]
1103
1109
        elif not new:
1104
1110
            raise errors.BzrCommandError('Specify one or more files to'
1105
1111
            ' remove, or use --new.')
1243
1249
    If there is already a branch at the location but it has no working tree,
1244
1250
    the tree can be populated with 'bzr checkout'.
1245
1251
 
1246
 
    Recipe for importing a tree of files:
 
1252
    Recipe for importing a tree of files::
 
1253
 
1247
1254
        cd ~/project
1248
1255
        bzr init
1249
1256
        bzr add .
1251
1258
        bzr commit -m 'imported project'
1252
1259
    """
1253
1260
 
1254
 
    _see_also = ['init-repo', 'branch', 'checkout']
 
1261
    _see_also = ['init-repository', 'branch', 'checkout']
1255
1262
    takes_args = ['location?']
1256
1263
    takes_options = [
1257
1264
        Option('create-prefix',
1295
1302
            _create_prefix(to_transport)
1296
1303
 
1297
1304
        try:
1298
 
            existing_bzrdir = bzrdir.BzrDir.open(location)
 
1305
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1299
1306
        except errors.NotBranchError:
1300
1307
            # really a NotBzrDir error...
1301
 
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
1302
 
                                                             format=format)
 
1308
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1309
            branch = create_branch(to_transport.base, format=format,
 
1310
                                   possible_transports=[to_transport])
1303
1311
        else:
1304
1312
            from bzrlib.transport.local import LocalTransport
1305
1313
            if existing_bzrdir.has_branch():
1327
1335
    If the --no-trees option is used then the branches in the repository
1328
1336
    will not have working trees by default.
1329
1337
 
1330
 
    example:
1331
 
        bzr init-repo --no-trees repo
1332
 
        bzr init repo/trunk
1333
 
        bzr checkout --lightweight repo/trunk trunk-checkout
1334
 
        cd trunk-checkout
1335
 
        (add files here)
1336
 
 
1337
 
    See 'bzr help repositories' for more information.
 
1338
    :Examples:
 
1339
        Create a shared repositories holding just branches::
 
1340
 
 
1341
            bzr init-repo --no-trees repo
 
1342
            bzr init repo/trunk
 
1343
 
 
1344
        Make a lightweight checkout elsewhere::
 
1345
 
 
1346
            bzr checkout --lightweight repo/trunk trunk-checkout
 
1347
            cd trunk-checkout
 
1348
            (add files here)
1338
1349
    """
1339
1350
 
1340
 
    _see_also = ['init', 'branch', 'checkout']
 
1351
    _see_also = ['init', 'branch', 'checkout', 'repositories']
1341
1352
    takes_args = ["location"]
1342
1353
    takes_options = [RegistryOption('format',
1343
1354
                            help='Specify a format for this repository. See'
1375
1386
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1376
1387
    produces patches suitable for "patch -p1".
1377
1388
 
1378
 
    examples:
1379
 
        bzr diff
1380
 
            Shows the difference in the working tree versus the last commit
1381
 
        bzr diff -r1
1382
 
            Difference between the working tree and revision 1
1383
 
        bzr diff -r1..2
1384
 
            Difference between revision 2 and revision 1
1385
 
        bzr diff --prefix old/:new/
1386
 
            Same as 'bzr diff' but prefix paths with old/ and new/
1387
 
        bzr diff bzr.mine bzr.dev
1388
 
            Show the differences between the two working trees
1389
 
        bzr diff foo.c
1390
 
            Show just the differences for 'foo.c'
 
1389
    :Examples:
 
1390
        Shows the difference in the working tree versus the last commit::
 
1391
 
 
1392
            bzr diff
 
1393
 
 
1394
        Difference between the working tree and revision 1::
 
1395
 
 
1396
            bzr diff -r1
 
1397
 
 
1398
        Difference between revision 2 and revision 1::
 
1399
 
 
1400
            bzr diff -r1..2
 
1401
 
 
1402
        Same as 'bzr diff' but prefix paths with old/ and new/::
 
1403
 
 
1404
            bzr diff --prefix old/:new/
 
1405
 
 
1406
        Show the differences between the two working trees::
 
1407
 
 
1408
            bzr diff bzr.mine bzr.dev
 
1409
 
 
1410
        Show just the differences for 'foo.c'::
 
1411
 
 
1412
            bzr diff foo.c
1391
1413
    """
1392
1414
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1393
1415
    #       or a graphical diff.
1410
1432
               help='Set prefixes to added to old and new filenames, as '
1411
1433
                    'two values separated by a colon. (eg "old/:new/").'),
1412
1434
        'revision',
 
1435
        'change',
1413
1436
        ]
1414
1437
    aliases = ['di', 'dif']
1415
1438
    encoding_type = 'exact'
1591
1614
    -r revision requests a specific revision, -r ..end or -r begin.. are
1592
1615
    also valid.
1593
1616
 
1594
 
    examples:
1595
 
        bzr log
1596
 
        bzr log foo.c
1597
 
        bzr log -r -10.. http://server/branch
 
1617
    :Examples:
 
1618
        Log the current branch::
 
1619
 
 
1620
            bzr log
 
1621
 
 
1622
        Log a file::
 
1623
 
 
1624
            bzr log foo.c
 
1625
 
 
1626
        Log the last 10 revisions of a branch::
 
1627
 
 
1628
            bzr log -r -10.. http://server/branch
1598
1629
    """
1599
1630
 
1600
1631
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1606
1637
            Option('timezone',
1607
1638
                   type=str,
1608
1639
                   help='Display timezone as local, original, or utc.'),
1609
 
            Option('verbose',
1610
 
                   short_name='v',
 
1640
            custom_help('verbose',
1611
1641
                   help='Show files changed in each revision.'),
1612
1642
            'show-ids',
1613
1643
            'revision',
1857
1887
 
1858
1888
    Ignore patterns specifying absolute paths are not allowed.
1859
1889
 
1860
 
    Ignore patterns may include globbing wildcards such as:
 
1890
    Ignore patterns may include globbing wildcards such as::
 
1891
 
1861
1892
      ? - Matches any single character except '/'
1862
1893
      * - Matches 0 or more characters except '/'
1863
1894
      /**/ - Matches 0 or more directories in a path
1871
1902
    Note: ignore patterns containing shell wildcards must be quoted from 
1872
1903
    the shell on Unix.
1873
1904
 
1874
 
    examples:
1875
 
        bzr ignore ./Makefile
1876
 
        bzr ignore '*.class'
1877
 
        bzr ignore 'lib/**/*.o'
1878
 
        bzr ignore 'RE:lib/.*\.o'
 
1905
    :Examples:
 
1906
        Ignore the top level Makefile::
 
1907
 
 
1908
            bzr ignore ./Makefile
 
1909
 
 
1910
        Ignore class files in all directories::
 
1911
 
 
1912
            bzr ignore '*.class'
 
1913
 
 
1914
        Ignore .o files under the lib directory::
 
1915
 
 
1916
            bzr ignore 'lib/**/*.o'
 
1917
 
 
1918
        Ignore .o files under the lib directory::
 
1919
 
 
1920
            bzr ignore 'RE:lib/.*\.o'
1879
1921
    """
1880
1922
 
1881
1923
    _see_also = ['status', 'ignored']
1931
1973
        if not tree.path2id('.bzrignore'):
1932
1974
            tree.add(['.bzrignore'])
1933
1975
 
 
1976
        ignored = globbing.Globster(name_pattern_list)
 
1977
        matches = []
 
1978
        tree.lock_read()
 
1979
        for entry in tree.list_files():
 
1980
            id = entry[3]
 
1981
            if id is not None:
 
1982
                filename = entry[0]
 
1983
                if ignored.match(filename):
 
1984
                    matches.append(filename.encode('utf-8'))
 
1985
        tree.unlock()
 
1986
        if len(matches) > 0:
 
1987
            print "Warning: the following files are version controlled and" \
 
1988
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
1934
1989
 
1935
1990
class cmd_ignored(Command):
1936
1991
    """List ignored files and the patterns that matched them.
1955
2010
class cmd_lookup_revision(Command):
1956
2011
    """Lookup the revision-id from a revision-number
1957
2012
 
1958
 
    example:
 
2013
    :Examples:
1959
2014
        bzr lookup-revision 33
1960
2015
    """
1961
2016
    hidden = True
1989
2044
 
1990
2045
    Note: Export of tree with non-ASCII filenames to zip is not supported.
1991
2046
 
1992
 
     Supported formats       Autodetected by extension
1993
 
     -----------------       -------------------------
1994
 
         dir                            -
 
2047
      =================       =========================
 
2048
      Supported formats       Autodetected by extension
 
2049
      =================       =========================
 
2050
         dir                         (none)
1995
2051
         tar                          .tar
1996
2052
         tbz2                    .tar.bz2, .tbz2
1997
2053
         tgz                      .tar.gz, .tgz
1998
2054
         zip                          .zip
 
2055
      =================       =========================
1999
2056
    """
2000
2057
    takes_args = ['dest', 'branch?']
2001
2058
    takes_options = [
2106
2163
    committed.  If a directory is specified then the directory and everything 
2107
2164
    within it is committed.
2108
2165
 
 
2166
    If author of the change is not the same person as the committer, you can
 
2167
    specify the author's name using the --author option. The name should be
 
2168
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
 
2169
 
2109
2170
    A selected-file commit may fail in some cases where the committed
2110
2171
    tree would be invalid. Consider::
2111
2172
 
2152
2213
                    "files in the working tree."),
2153
2214
             ListOption('fixes', type=str,
2154
2215
                    help="Mark a bug as being fixed by this revision."),
 
2216
             Option('author', type=str,
 
2217
                    help="Set the author's name, if it's different "
 
2218
                         "from the committer."),
2155
2219
             Option('local',
2156
2220
                    help="Perform a local commit in a bound "
2157
2221
                         "branch.  Local commits are not pushed to "
2158
2222
                         "the master branch until a normal commit "
2159
2223
                         "is performed."
2160
2224
                    ),
 
2225
              Option('show-diff',
 
2226
                     help='When no message is supplied, show the diff along'
 
2227
                     ' with the status summary in the message editor.'),
2161
2228
             ]
2162
2229
    aliases = ['ci', 'checkin']
2163
2230
 
2183
2250
            properties.append('%s fixed' % bug_url)
2184
2251
        return '\n'.join(properties)
2185
2252
 
2186
 
    def run(self, message=None, file=None, verbose=True, selected_list=None,
2187
 
            unchanged=False, strict=False, local=False, fixes=None):
2188
 
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
2189
 
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
2190
 
                StrictCommitFailed)
2191
 
        from bzrlib.msgeditor import edit_commit_message, \
2192
 
                make_commit_message_template
 
2253
    def run(self, message=None, file=None, verbose=False, selected_list=None,
 
2254
            unchanged=False, strict=False, local=False, fixes=None,
 
2255
            author=None, show_diff=False):
 
2256
        from bzrlib.commit import (
 
2257
            NullCommitReporter,
 
2258
            ReportCommitToLog
 
2259
        )
 
2260
        from bzrlib.errors import (
 
2261
            PointlessCommit,
 
2262
            ConflictsInTree,
 
2263
            StrictCommitFailed
 
2264
        )
 
2265
        from bzrlib.msgeditor import (
 
2266
            edit_commit_message_encoded,
 
2267
            make_commit_message_template_encoded
 
2268
        )
2193
2269
 
2194
2270
        # TODO: Need a blackbox test for invoking the external editor; may be
2195
2271
        # slightly problematic to run this cross-platform.
2217
2293
            """Callback to get commit message"""
2218
2294
            my_message = message
2219
2295
            if my_message is None and not file:
2220
 
                template = make_commit_message_template(tree, selected_list)
2221
 
                my_message = edit_commit_message(template)
 
2296
                t = make_commit_message_template_encoded(tree,
 
2297
                        selected_list, diff=show_diff,
 
2298
                        output_encoding=bzrlib.user_encoding)
 
2299
                my_message = edit_commit_message_encoded(t)
2222
2300
                if my_message is None:
2223
2301
                    raise errors.BzrCommandError("please specify a commit"
2224
2302
                        " message with either --message or --file")
2232
2310
                raise errors.BzrCommandError("empty commit message specified")
2233
2311
            return my_message
2234
2312
 
2235
 
        if verbose:
2236
 
            reporter = ReportCommitToLog()
2237
 
        else:
2238
 
            reporter = NullCommitReporter()
2239
 
 
2240
2313
        try:
2241
2314
            tree.commit(message_callback=get_message,
2242
2315
                        specific_files=selected_list,
2243
2316
                        allow_pointless=unchanged, strict=strict, local=local,
2244
 
                        reporter=reporter, revprops=properties)
 
2317
                        reporter=None, verbose=verbose, revprops=properties,
 
2318
                        author=author)
2245
2319
        except PointlessCommit:
2246
2320
            # FIXME: This should really happen before the file is read in;
2247
2321
            # perhaps prepare the commit; get the message; then actually commit
2311
2385
class cmd_whoami(Command):
2312
2386
    """Show or set bzr user id.
2313
2387
    
2314
 
    examples:
2315
 
        bzr whoami --email
2316
 
        bzr whoami 'Frank Chu <fchu@example.com>'
 
2388
    :Examples:
 
2389
        Show the email of the current user::
 
2390
 
 
2391
            bzr whoami --email
 
2392
 
 
2393
        Set the current user::
 
2394
 
 
2395
            bzr whoami 'Frank Chu <fchu@example.com>'
2317
2396
    """
2318
2397
    takes_options = [ Option('email',
2319
2398
                             help='Display email address only.'),
2408
2487
    Tests that need working space on disk use a common temporary directory, 
2409
2488
    typically inside $TMPDIR or /tmp.
2410
2489
 
2411
 
    examples::
2412
 
        bzr selftest ignore
2413
 
            run only tests relating to 'ignore'
2414
 
        bzr --no-plugins selftest -v
2415
 
            disable plugins and list tests as they're run
 
2490
    :Examples:
 
2491
        Run only tests relating to 'ignore'::
 
2492
 
 
2493
            bzr selftest ignore
 
2494
 
 
2495
        Disable plugins and list tests as they're run::
 
2496
 
 
2497
            bzr --no-plugins selftest -v
2416
2498
    """
2417
2499
    # NB: this is used from the class without creating an instance, which is
2418
2500
    # why it does not have a self parameter.
2463
2545
                            short_name='x',
2464
2546
                            help='Exclude tests that match this regular'
2465
2547
                                 ' expression.'),
 
2548
                     Option('strict', help='Fail on missing dependencies or '
 
2549
                            'known failures.'),
2466
2550
                     ]
2467
2551
    encoding_type = 'replace'
2468
2552
 
2469
 
    def run(self, testspecs_list=None, verbose=None, one=False,
 
2553
    def run(self, testspecs_list=None, verbose=False, one=False,
2470
2554
            transport=None, benchmark=None,
2471
2555
            lsprof_timed=None, cache_dir=None,
2472
2556
            first=False, list_only=False,
2473
 
            randomize=None, exclude=None):
 
2557
            randomize=None, exclude=None, strict=False):
2474
2558
        import bzrlib.ui
2475
2559
        from bzrlib.tests import selftest
2476
2560
        import bzrlib.benchmarks as benchmarks
2477
2561
        from bzrlib.benchmarks import tree_creator
2478
 
        from bzrlib.version import show_version
2479
2562
 
2480
2563
        if cache_dir is not None:
2481
2564
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2482
2565
        if not list_only:
2483
 
            show_version(show_config=False, show_copyright=False)
 
2566
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
 
2567
            print '   %s (%s python%s)' % (
 
2568
                    bzrlib.__path__[0],
 
2569
                    bzrlib.version_string,
 
2570
                    '.'.join(map(str, sys.version_info)),
 
2571
                    )
2484
2572
        print
2485
2573
        if testspecs_list is not None:
2486
2574
            pattern = '|'.join(testspecs_list)
2488
2576
            pattern = ".*"
2489
2577
        if benchmark:
2490
2578
            test_suite_factory = benchmarks.test_suite
2491
 
            if verbose is None:
2492
 
                verbose = True
 
2579
            # Unless user explicitly asks for quiet, be verbose in benchmarks
 
2580
            verbose = not is_quiet()
2493
2581
            # TODO: should possibly lock the history file...
2494
2582
            benchfile = open(".perf_history", "at", buffering=1)
2495
2583
        else:
2496
2584
            test_suite_factory = None
2497
 
            if verbose is None:
2498
 
                verbose = False
2499
2585
            benchfile = None
2500
2586
        try:
2501
2587
            result = selftest(verbose=verbose,
2508
2594
                              matching_tests_first=first,
2509
2595
                              list_only=list_only,
2510
2596
                              random_seed=randomize,
2511
 
                              exclude_pattern=exclude
 
2597
                              exclude_pattern=exclude,
 
2598
                              strict=strict,
2512
2599
                              )
2513
2600
        finally:
2514
2601
            if benchfile is not None:
2523
2610
class cmd_version(Command):
2524
2611
    """Show version of bzr."""
2525
2612
 
 
2613
    encoding_type = 'replace'
 
2614
 
2526
2615
    @display_command
2527
2616
    def run(self):
2528
2617
        from bzrlib.version import show_version
2529
 
        show_version()
 
2618
        show_version(to_file=self.outf)
2530
2619
 
2531
2620
 
2532
2621
class cmd_rocks(Command):
2590
2679
    The results of the merge are placed into the destination working
2591
2680
    directory, where they can be reviewed (with bzr diff), tested, and then
2592
2681
    committed to record the result of the merge.
2593
 
 
2594
 
    Examples:
2595
 
 
2596
 
    To merge the latest revision from bzr.dev:
2597
 
        bzr merge ../bzr.dev
2598
 
 
2599
 
    To merge changes up to and including revision 82 from bzr.dev:
2600
 
        bzr merge -r 82 ../bzr.dev
2601
 
 
2602
 
    To merge the changes introduced by 82, without previous changes:
2603
 
        bzr merge -r 81..82 ../bzr.dev
2604
2682
    
2605
2683
    merge refuses to run if there are any uncommitted changes, unless
2606
2684
    --force is given.
 
2685
 
 
2686
    :Examples:
 
2687
        To merge the latest revision from bzr.dev::
 
2688
 
 
2689
            bzr merge ../bzr.dev
 
2690
 
 
2691
        To merge changes up to and including revision 82 from bzr.dev::
 
2692
 
 
2693
            bzr merge -r 82 ../bzr.dev
 
2694
 
 
2695
        To merge the changes introduced by 82, without previous changes::
 
2696
 
 
2697
            bzr merge -r 81..82 ../bzr.dev
2607
2698
    """
2608
2699
 
2609
2700
    _see_also = ['update', 'remerge', 'status-flags']
2637
2728
            directory=None,
2638
2729
            ):
2639
2730
        from bzrlib.tag import _merge_tags_if_possible
2640
 
        other_revision_id = None
 
2731
        # This is actually a branch (or merge-directive) *location*.
 
2732
        location = branch
 
2733
        del branch
 
2734
 
2641
2735
        if merge_type is None:
2642
2736
            merge_type = _mod_merge.Merge3Merger
2643
2737
 
2644
2738
        if directory is None: directory = u'.'
2645
 
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
2646
 
        #      inventory. Because merge is a mutating operation, it really
2647
 
        #      should be a lock_write() for the whole cmd_merge operation.
2648
 
        #      However, cmd_merge open's its own tree in _merge_helper, which
2649
 
        #      means if we lock here, the later lock_write() will always block.
2650
 
        #      Either the merge helper code should be updated to take a tree,
2651
 
        #      (What about tree.merge_from_branch?)
 
2739
        possible_transports = []
 
2740
        merger = None
 
2741
        allow_pending = True
 
2742
        verified = 'inapplicable'
2652
2743
        tree = WorkingTree.open_containing(directory)[0]
2653
2744
        change_reporter = delta._ChangeReporter(
2654
2745
            unversioned_filter=tree.is_ignored)
2655
 
 
2656
 
        if branch is not None:
2657
 
            try:
2658
 
                mergeable = bundle.read_mergeable_from_url(
2659
 
                    branch)
2660
 
            except errors.NotABundle:
2661
 
                pass # Continue on considering this url a Branch
2662
 
            else:
2663
 
                if revision is not None:
2664
 
                    raise errors.BzrCommandError(
2665
 
                        'Cannot use -r with merge directives or bundles')
2666
 
                other_revision_id = mergeable.install_revisions(
2667
 
                    tree.branch.repository)
2668
 
                revision = [RevisionSpec.from_string(
2669
 
                    'revid:' + other_revision_id)]
2670
 
 
2671
 
        if revision is None \
2672
 
                or len(revision) < 1 or revision[0].needs_branch():
2673
 
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2674
 
 
2675
 
        if revision is None or len(revision) < 1:
2676
 
            if uncommitted:
2677
 
                base = [branch, -1]
2678
 
                other = [branch, None]
2679
 
            else:
2680
 
                base = [None, None]
2681
 
                other = [branch, -1]
2682
 
            other_branch, path = Branch.open_containing(branch)
2683
 
        else:
2684
 
            if uncommitted:
2685
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
2686
 
                                             ' --revision at the same time.')
2687
 
            branch = revision[0].get_branch() or branch
2688
 
            if len(revision) == 1:
2689
 
                base = [None, None]
2690
 
                if other_revision_id is not None:
2691
 
                    other_branch = None
2692
 
                    path = ""
2693
 
                    other = None
2694
 
                else:
2695
 
                    other_branch, path = Branch.open_containing(branch)
2696
 
                    revno = revision[0].in_history(other_branch).revno
2697
 
                    other = [branch, revno]
2698
 
            else:
2699
 
                assert len(revision) == 2
2700
 
                if None in revision:
2701
 
                    raise errors.BzrCommandError(
2702
 
                        "Merge doesn't permit empty revision specifier.")
2703
 
                base_branch, path = Branch.open_containing(branch)
2704
 
                branch1 = revision[1].get_branch() or branch
2705
 
                other_branch, path1 = Branch.open_containing(branch1)
2706
 
                if revision[0].get_branch() is not None:
2707
 
                    # then path was obtained from it, and is None.
2708
 
                    path = path1
2709
 
 
2710
 
                base = [branch, revision[0].in_history(base_branch).revno]
2711
 
                other = [branch1, revision[1].in_history(other_branch).revno]
2712
 
 
 
2746
        cleanups = []
 
2747
        try:
 
2748
            pb = ui.ui_factory.nested_progress_bar()
 
2749
            cleanups.append(pb.finished)
 
2750
            tree.lock_write()
 
2751
            cleanups.append(tree.unlock)
 
2752
            if location is not None:
 
2753
                mergeable, other_transport = _get_mergeable_helper(location)
 
2754
                if mergeable:
 
2755
                    if uncommitted:
 
2756
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
2757
                            ' with bundles or merge directives.')
 
2758
 
 
2759
                    if revision is not None:
 
2760
                        raise errors.BzrCommandError(
 
2761
                            'Cannot use -r with merge directives or bundles')
 
2762
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
2763
                       mergeable, pb)
 
2764
                possible_transports.append(other_transport)
 
2765
 
 
2766
            if merger is None and uncommitted:
 
2767
                if revision is not None and len(revision) > 0:
 
2768
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2769
                        ' --revision at the same time.')
 
2770
                location = self._select_branch_location(tree, location)[0]
 
2771
                other_tree, other_path = WorkingTree.open_containing(location)
 
2772
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
 
2773
                    pb)
 
2774
                allow_pending = False
 
2775
 
 
2776
            if merger is None:
 
2777
                merger, allow_pending = self._get_merger_from_branch(tree,
 
2778
                    location, revision, remember, possible_transports, pb)
 
2779
 
 
2780
            merger.merge_type = merge_type
 
2781
            merger.reprocess = reprocess
 
2782
            merger.show_base = show_base
 
2783
            merger.change_reporter = change_reporter
 
2784
            self.sanity_check_merger(merger)
 
2785
            if (merger.base_rev_id == merger.other_rev_id and
 
2786
                merger.other_rev_id != None):
 
2787
                note('Nothing to do.')
 
2788
                return 0
 
2789
            if pull:
 
2790
                if merger.interesting_files is not None:
 
2791
                    raise BzrCommandError('Cannot pull individual files')
 
2792
                if (merger.base_rev_id == tree.last_revision()):
 
2793
                    result = tree.pull(merger.other_branch, False,
 
2794
                                       merger.other_rev_id)
 
2795
                    result.report(self.outf)
 
2796
                    return 0
 
2797
            merger.check_basis(not force)
 
2798
            conflict_count = merger.do_merge()
 
2799
            if allow_pending:
 
2800
                merger.set_pending()
 
2801
            if verified == 'failed':
 
2802
                warning('Preview patch does not match changes')
 
2803
            if conflict_count != 0:
 
2804
                return 1
 
2805
            else:
 
2806
                return 0
 
2807
        finally:
 
2808
            for cleanup in reversed(cleanups):
 
2809
                cleanup()
 
2810
 
 
2811
    def sanity_check_merger(self, merger):
 
2812
        if (merger.show_base and
 
2813
            not merger.merge_type is _mod_merge.Merge3Merger):
 
2814
            raise errors.BzrCommandError("Show-base is not supported for this"
 
2815
                                         " merge type. %s" % merger.merge_type)
 
2816
        if merger.reprocess and not merger.merge_type.supports_reprocess:
 
2817
            raise errors.BzrCommandError("Conflict reduction is not supported"
 
2818
                                         " for merge type %s." %
 
2819
                                         merger.merge_type)
 
2820
        if merger.reprocess and merger.show_base:
 
2821
            raise errors.BzrCommandError("Cannot do conflict reduction and"
 
2822
                                         " show base.")
 
2823
 
 
2824
    def _get_merger_from_branch(self, tree, location, revision, remember,
 
2825
                                possible_transports, pb):
 
2826
        """Produce a merger from a location, assuming it refers to a branch."""
 
2827
        from bzrlib.tag import _merge_tags_if_possible
 
2828
        assert revision is None or len(revision) < 3
 
2829
        # find the branch locations
 
2830
        other_loc, location = self._select_branch_location(tree, location,
 
2831
            revision, -1)
 
2832
        if revision is not None and len(revision) == 2:
 
2833
            base_loc, location = self._select_branch_location(tree, location,
 
2834
                                                              revision, 0)
 
2835
        else:
 
2836
            base_loc = other_loc
 
2837
        # Open the branches
 
2838
        other_branch, other_path = Branch.open_containing(other_loc,
 
2839
            possible_transports)
 
2840
        if base_loc == other_loc:
 
2841
            base_branch = other_branch
 
2842
        else:
 
2843
            base_branch, base_path = Branch.open_containing(base_loc,
 
2844
                possible_transports)
 
2845
        # Find the revision ids
 
2846
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
2847
            other_revision_id = _mod_revision.ensure_null(
 
2848
                other_branch.last_revision())
 
2849
        else:
 
2850
            other_revision_id = \
 
2851
                _mod_revision.ensure_null(
 
2852
                    revision[-1].in_history(other_branch).rev_id)
 
2853
        if (revision is not None and len(revision) == 2
 
2854
            and revision[0] is not None):
 
2855
            base_revision_id = \
 
2856
                _mod_revision.ensure_null(
 
2857
                    revision[0].in_history(base_branch).rev_id)
 
2858
        else:
 
2859
            base_revision_id = None
 
2860
        # Remember where we merge from
2713
2861
        if ((tree.branch.get_parent() is None or remember) and
2714
2862
            other_branch is not None):
2715
2863
            tree.branch.set_parent(other_branch.base)
2716
 
 
2717
 
        # pull tags now... it's a bit inconsistent to do it ahead of copying
2718
 
        # the history but that's done inside the merge code
2719
 
        if other_branch is not None:
2720
 
            _merge_tags_if_possible(other_branch, tree.branch)
2721
 
 
2722
 
        if path != "":
2723
 
            interesting_files = [path]
 
2864
        _merge_tags_if_possible(other_branch, tree.branch)
 
2865
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
 
2866
            other_revision_id, base_revision_id, other_branch, base_branch)
 
2867
        if other_path != '':
 
2868
            allow_pending = False
 
2869
            merger.interesting_files = [other_path]
2724
2870
        else:
2725
 
            interesting_files = None
2726
 
        pb = ui.ui_factory.nested_progress_bar()
2727
 
        try:
2728
 
            try:
2729
 
                conflict_count = _merge_helper(
2730
 
                    other, base, other_rev_id=other_revision_id,
2731
 
                    check_clean=(not force),
2732
 
                    merge_type=merge_type,
2733
 
                    reprocess=reprocess,
2734
 
                    show_base=show_base,
2735
 
                    pull=pull,
2736
 
                    this_dir=directory,
2737
 
                    pb=pb, file_list=interesting_files,
2738
 
                    change_reporter=change_reporter)
2739
 
            finally:
2740
 
                pb.finished()
2741
 
            if conflict_count != 0:
2742
 
                return 1
2743
 
            else:
2744
 
                return 0
2745
 
        except errors.AmbiguousBase, e:
2746
 
            m = ("sorry, bzr can't determine the right merge base yet\n"
2747
 
                 "candidates are:\n  "
2748
 
                 + "\n  ".join(e.bases)
2749
 
                 + "\n"
2750
 
                 "please specify an explicit base with -r,\n"
2751
 
                 "and (if you want) report this to the bzr developers\n")
2752
 
            log_error(m)
 
2871
            allow_pending = True
 
2872
        return merger, allow_pending
 
2873
 
 
2874
    def _select_branch_location(self, tree, location, revision=None,
 
2875
                                index=None):
 
2876
        """Select a branch location, according to possible inputs.
 
2877
 
 
2878
        If provided, branches from ``revision`` are preferred.  (Both
 
2879
        ``revision`` and ``index`` must be supplied.)
 
2880
 
 
2881
        Otherwise, the ``location`` parameter is used.  If it is None, then the
 
2882
        ``parent`` location is used, and a note is printed.
 
2883
 
 
2884
        :param tree: The working tree to select a branch for merging into
 
2885
        :param location: The location entered by the user
 
2886
        :param revision: The revision parameter to the command
 
2887
        :param index: The index to use for the revision parameter.  Negative
 
2888
            indices are permitted.
 
2889
        :return: (selected_location, default_location).  The default location
 
2890
            will be the user-entered location, if any, or else the remembered
 
2891
            location.
 
2892
        """
 
2893
        if (revision is not None and index is not None
 
2894
            and revision[index] is not None):
 
2895
            branch = revision[index].get_branch()
 
2896
            if branch is not None:
 
2897
                return branch, location
 
2898
        location = self._get_remembered_parent(tree, location, 'Merging from')
 
2899
        return location, location
2753
2900
 
2754
2901
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2755
2902
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
2763
2910
        mutter("%s", stored_location)
2764
2911
        if stored_location is None:
2765
2912
            raise errors.BzrCommandError("No location specified or remembered")
2766
 
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2767
 
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2913
        display_url = urlutils.unescape_for_display(stored_location,
 
2914
            self.outf.encoding)
 
2915
        self.outf.write("%s remembered location %s\n" % (verb_string,
 
2916
            display_url))
2768
2917
        return stored_location
2769
2918
 
2770
2919
 
2779
2928
    merge.  The difference is that remerge can (only) be run when there is a
2780
2929
    pending merge, and it lets you specify particular files.
2781
2930
 
2782
 
    Examples:
2783
 
 
2784
 
    $ bzr remerge --show-base
 
2931
    :Examples:
2785
2932
        Re-do the merge of all conflicted files, and show the base text in
2786
 
        conflict regions, in addition to the usual THIS and OTHER texts.
 
2933
        conflict regions, in addition to the usual THIS and OTHER texts::
 
2934
      
 
2935
            bzr remerge --show-base
2787
2936
 
2788
 
    $ bzr remerge --merge-type weave --reprocess foobar
2789
2937
        Re-do the merge of "foobar", using the weave merge algorithm, with
2790
 
        additional processing to reduce the size of conflict regions.
 
2938
        additional processing to reduce the size of conflict regions::
 
2939
      
 
2940
            bzr remerge --merge-type weave --reprocess foobar
2791
2941
    """
2792
2942
    takes_args = ['file*']
2793
2943
    takes_options = [
2844
2994
                    restore(tree.abspath(filename))
2845
2995
                except errors.NotConflicted:
2846
2996
                    pass
2847
 
            conflicts = _mod_merge.merge_inner(
2848
 
                                      tree.branch, other_tree, base_tree,
2849
 
                                      this_tree=tree,
2850
 
                                      interesting_ids=interesting_ids,
2851
 
                                      other_rev_id=parents[1],
2852
 
                                      merge_type=merge_type,
2853
 
                                      show_base=show_base,
2854
 
                                      reprocess=reprocess)
 
2997
            # Disable pending merges, because the file texts we are remerging
 
2998
            # have not had those merges performed.  If we use the wrong parents
 
2999
            # list, we imply that the working tree text has seen and rejected
 
3000
            # all the changes from the other tree, when in fact those changes
 
3001
            # have not yet been seen.
 
3002
            tree.set_parent_ids(parents[:1])
 
3003
            try:
 
3004
                conflicts = _mod_merge.merge_inner(
 
3005
                                          tree.branch, other_tree, base_tree,
 
3006
                                          this_tree=tree,
 
3007
                                          interesting_ids=interesting_ids,
 
3008
                                          other_rev_id=parents[1],
 
3009
                                          merge_type=merge_type,
 
3010
                                          show_base=show_base,
 
3011
                                          reprocess=reprocess)
 
3012
            finally:
 
3013
                tree.set_parent_ids(parents)
2855
3014
        finally:
2856
3015
            tree.unlock()
2857
3016
        if conflicts > 0:
2880
3039
    from the target revision.  So you can use revert to "undelete" a file by
2881
3040
    name.  If you name a directory, all the contents of that directory will be
2882
3041
    reverted.
 
3042
 
 
3043
    Any files that have been newly added since that revision will be deleted,
 
3044
    with a backup kept if appropriate.  Directories containing unknown files
 
3045
    will not be deleted.
2883
3046
    """
2884
3047
 
2885
3048
    _see_also = ['cat', 'export']
2893
3056
        if file_list is not None:
2894
3057
            if len(file_list) == 0:
2895
3058
                raise errors.BzrCommandError("No files specified")
2896
 
        else:
2897
 
            file_list = []
2898
3059
        
2899
3060
        tree, file_list = tree_files(file_list)
2900
3061
        if revision is None:
3010
3171
        if other_branch is None:
3011
3172
            other_branch = parent
3012
3173
            if other_branch is None:
3013
 
                raise errors.BzrCommandError("No peer location known or specified.")
 
3174
                raise errors.BzrCommandError("No peer location known"
 
3175
                                             " or specified.")
3014
3176
            display_url = urlutils.unescape_for_display(parent,
3015
3177
                                                        self.outf.encoding)
3016
 
            print "Using last location: " + display_url
 
3178
            self.outf.write("Using last location: " + display_url + "\n")
3017
3179
 
3018
3180
        remote_branch = Branch.open(other_branch)
3019
3181
        if remote_branch.base == local_branch.base:
3022
3184
        try:
3023
3185
            remote_branch.lock_read()
3024
3186
            try:
3025
 
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
3026
 
                if (log_format is None):
3027
 
                    log_format = log.log_formatter_registry.get_default(
3028
 
                        local_branch)
 
3187
                local_extra, remote_extra = find_unmerged(local_branch,
 
3188
                                                          remote_branch)
 
3189
                if log_format is None:
 
3190
                    registry = log.log_formatter_registry
 
3191
                    log_format = registry.get_default(local_branch)
3029
3192
                lf = log_format(to_file=self.outf,
3030
3193
                                show_ids=show_ids,
3031
3194
                                show_timezone='original')
3033
3196
                    local_extra.reverse()
3034
3197
                    remote_extra.reverse()
3035
3198
                if local_extra and not theirs_only:
3036
 
                    print "You have %d extra revision(s):" % len(local_extra)
3037
 
                    for revision in iter_log_revisions(local_extra, 
 
3199
                    self.outf.write("You have %d extra revision(s):\n" %
 
3200
                                    len(local_extra))
 
3201
                    for revision in iter_log_revisions(local_extra,
3038
3202
                                        local_branch.repository,
3039
3203
                                        verbose):
3040
3204
                        lf.log_revision(revision)
3043
3207
                    printed_local = False
3044
3208
                if remote_extra and not mine_only:
3045
3209
                    if printed_local is True:
3046
 
                        print "\n\n"
3047
 
                    print "You are missing %d revision(s):" % len(remote_extra)
3048
 
                    for revision in iter_log_revisions(remote_extra, 
3049
 
                                        remote_branch.repository, 
 
3210
                        self.outf.write("\n\n\n")
 
3211
                    self.outf.write("You are missing %d revision(s):\n" %
 
3212
                                    len(remote_extra))
 
3213
                    for revision in iter_log_revisions(remote_extra,
 
3214
                                        remote_branch.repository,
3050
3215
                                        verbose):
3051
3216
                        lf.log_revision(revision)
3052
3217
                if not remote_extra and not local_extra:
3053
3218
                    status_code = 0
3054
 
                    print "Branches are up to date."
 
3219
                    self.outf.write("Branches are up to date.\n")
3055
3220
                else:
3056
3221
                    status_code = 1
3057
3222
            finally:
3086
3251
 
3087
3252
 
3088
3253
class cmd_plugins(Command):
3089
 
    """List plugins"""
3090
 
    hidden = True
 
3254
    """List the installed plugins.
 
3255
    
 
3256
    This command displays the list of installed plugins including the
 
3257
    path where each one is located and a short description of each.
 
3258
 
 
3259
    A plugin is an external component for Bazaar that extends the
 
3260
    revision control system, by adding or replacing code in Bazaar.
 
3261
    Plugins can do a variety of things, including overriding commands,
 
3262
    adding new commands, providing additional network transports and
 
3263
    customizing log output.
 
3264
 
 
3265
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
3266
    information on plugins including where to find them and how to
 
3267
    install them. Instructions are also provided there on how to
 
3268
    write new plugins using the Python programming language.
 
3269
    """
 
3270
 
3091
3271
    @display_command
3092
3272
    def run(self):
3093
3273
        import bzrlib.plugin
3094
3274
        from inspect import getdoc
3095
 
        for name, plugin in bzrlib.plugin.all_plugins().items():
3096
 
            if getattr(plugin, '__path__', None) is not None:
3097
 
                print plugin.__path__[0]
3098
 
            elif getattr(plugin, '__file__', None) is not None:
3099
 
                print plugin.__file__
3100
 
            else:
3101
 
                print repr(plugin)
3102
 
                
3103
 
            d = getdoc(plugin)
 
3275
        for name, plugin in bzrlib.plugin.plugins().items():
 
3276
            print plugin.path(), "[%s]" % plugin.__version__
 
3277
            d = getdoc(plugin.module)
3104
3278
            if d:
3105
3279
                print '\t', d.split('\n')[0]
3106
3280
 
3276
3450
    --verbose will print out what is being removed.
3277
3451
    --dry-run will go through all the motions, but not actually
3278
3452
    remove anything.
3279
 
    
 
3453
 
 
3454
    If --revision is specified, uncommit revisions to leave the branch at the
 
3455
    specified revision.  For example, "bzr uncommit -r 15" will leave the
 
3456
    branch at revision 15.
 
3457
 
3280
3458
    In the future, uncommit will create a revision bundle, which can then
3281
3459
    be re-applied.
3282
3460
    """
3361
3539
 
3362
3540
    You can get information on what locks are open via the 'bzr info' command.
3363
3541
    
3364
 
    example:
 
3542
    :Examples:
3365
3543
        bzr break-lock
3366
3544
    """
3367
3545
    takes_args = ['location?']
3556
3734
 
3557
3735
    takes_args = ['submit_branch?', 'public_branch?']
3558
3736
 
 
3737
    hidden = True
 
3738
 
 
3739
    _see_also = ['send']
 
3740
 
3559
3741
    takes_options = [
3560
3742
        RegistryOption.from_kwargs('patch-type',
3561
 
            'The type of patch to include in the directive',
 
3743
            'The type of patch to include in the directive.',
3562
3744
            title='Patch type',
3563
3745
            value_switches=True,
3564
3746
            enum_switch=False,
3577
3759
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3578
3760
            sign=False, revision=None, mail_to=None, message=None):
3579
3761
        from bzrlib.revision import ensure_null, NULL_REVISION
3580
 
        if patch_type == 'plain':
3581
 
            patch_type = None
 
3762
        include_patch, include_bundle = {
 
3763
            'plain': (False, False),
 
3764
            'diff': (True, False),
 
3765
            'bundle': (True, True),
 
3766
            }[patch_type]
3582
3767
        branch = Branch.open('.')
3583
3768
        stored_submit_branch = branch.get_submit_branch()
3584
3769
        if submit_branch is None:
3596
3781
            public_branch = stored_public_branch
3597
3782
        elif stored_public_branch is None:
3598
3783
            branch.set_public_branch(public_branch)
3599
 
        if patch_type != "bundle" and public_branch is None:
 
3784
        if not include_bundle and public_branch is None:
3600
3785
            raise errors.BzrCommandError('No public branch specified or'
3601
3786
                                         ' known')
 
3787
        base_revision_id = None
3602
3788
        if revision is not None:
3603
 
            if len(revision) != 1:
 
3789
            if len(revision) > 2:
3604
3790
                raise errors.BzrCommandError('bzr merge-directive takes '
3605
 
                    'exactly one revision identifier')
3606
 
            else:
3607
 
                revision_id = revision[0].in_history(branch).rev_id
 
3791
                    'at most two one revision identifiers')
 
3792
            revision_id = revision[-1].in_history(branch).rev_id
 
3793
            if len(revision) == 2:
 
3794
                base_revision_id = revision[0].in_history(branch).rev_id
 
3795
                base_revision_id = ensure_null(base_revision_id)
3608
3796
        else:
3609
3797
            revision_id = branch.last_revision()
3610
3798
        revision_id = ensure_null(revision_id)
3611
3799
        if revision_id == NULL_REVISION:
3612
3800
            raise errors.BzrCommandError('No revisions to bundle.')
3613
 
        directive = merge_directive.MergeDirective.from_objects(
 
3801
        directive = merge_directive.MergeDirective2.from_objects(
3614
3802
            branch.repository, revision_id, time.time(),
3615
3803
            osutils.local_time_offset(), submit_branch,
3616
 
            public_branch=public_branch, patch_type=patch_type,
3617
 
            message=message)
 
3804
            public_branch=public_branch, include_patch=include_patch,
 
3805
            include_bundle=include_bundle, message=message,
 
3806
            base_revision_id=base_revision_id)
3618
3807
        if mail_to is None:
3619
3808
            if sign:
3620
3809
                self.outf.write(directive.to_signed(branch))
3626
3815
            s.send_email(message)
3627
3816
 
3628
3817
 
 
3818
class cmd_send(Command):
 
3819
    """Mail or create a merge-directive for submiting changes.
 
3820
 
 
3821
    A merge directive provides many things needed for requesting merges:
 
3822
 
 
3823
    * A machine-readable description of the merge to perform
 
3824
 
 
3825
    * An optional patch that is a preview of the changes requested
 
3826
 
 
3827
    * An optional bundle of revision data, so that the changes can be applied
 
3828
      directly from the merge directive, without retrieving data from a
 
3829
      branch.
 
3830
 
 
3831
    If --no-bundle is specified, then public_branch is needed (and must be
 
3832
    up-to-date), so that the receiver can perform the merge using the
 
3833
    public_branch.  The public_branch is always included if known, so that
 
3834
    people can check it later.
 
3835
 
 
3836
    The submit branch defaults to the parent, but can be overridden.  Both
 
3837
    submit branch and public branch will be remembered if supplied.
 
3838
 
 
3839
    If a public_branch is known for the submit_branch, that public submit
 
3840
    branch is used in the merge instructions.  This means that a local mirror
 
3841
    can be used as your actual submit branch, once you have set public_branch
 
3842
    for that mirror.
 
3843
 
 
3844
    Mail is sent using your preferred mail program.  This should be transparent
 
3845
    on Windows (it uses MAPI).  On *nix, it requires the xdg-email utility.  If
 
3846
    the preferred client can't be found (or used), your editor will be used.
 
3847
    
 
3848
    To use a specific mail program, set the mail_client configuration option.
 
3849
    (For Thunderbird 1.5, this works around some bugs.)  Supported values are
 
3850
    "thunderbird", "evolution", "editor", "xdg-email", "mapi", "kmail" and
 
3851
    "default".
 
3852
 
 
3853
    If mail is being sent, a to address is required.  This can be supplied
 
3854
    either on the commandline, or by setting the submit_to configuration
 
3855
    option.
 
3856
 
 
3857
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
3858
    merge directive format 2.  It is significantly faster and smaller than
 
3859
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
3860
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
3861
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
3862
    """
 
3863
 
 
3864
    encoding_type = 'exact'
 
3865
 
 
3866
    _see_also = ['merge']
 
3867
 
 
3868
    takes_args = ['submit_branch?', 'public_branch?']
 
3869
 
 
3870
    takes_options = [
 
3871
        Option('no-bundle',
 
3872
               help='Do not include a bundle in the merge directive.'),
 
3873
        Option('no-patch', help='Do not include a preview patch in the merge'
 
3874
               ' directive.'),
 
3875
        Option('remember',
 
3876
               help='Remember submit and public branch.'),
 
3877
        Option('from',
 
3878
               help='Branch to generate the submission from, '
 
3879
               'rather than the one containing the working directory.',
 
3880
               short_name='f',
 
3881
               type=unicode),
 
3882
        Option('output', short_name='o', help='Write directive to this file.',
 
3883
               type=unicode),
 
3884
        Option('mail-to', help='Mail the request to this address.',
 
3885
               type=unicode),
 
3886
        'revision',
 
3887
        'message',
 
3888
        RegistryOption.from_kwargs('format',
 
3889
        'Use the specified output format.',
 
3890
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
3891
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
3892
        ]
 
3893
 
 
3894
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
3895
            no_patch=False, revision=None, remember=False, output=None,
 
3896
            format='4', mail_to=None, message=None, **kwargs):
 
3897
        return self._run(submit_branch, revision, public_branch, remember,
 
3898
                         format, no_bundle, no_patch, output,
 
3899
                         kwargs.get('from', '.'), mail_to, message)
 
3900
 
 
3901
    def _run(self, submit_branch, revision, public_branch, remember, format,
 
3902
             no_bundle, no_patch, output, from_, mail_to, message):
 
3903
        from bzrlib.revision import ensure_null, NULL_REVISION
 
3904
        if output is None:
 
3905
            outfile = StringIO()
 
3906
        elif output == '-':
 
3907
            outfile = self.outf
 
3908
        else:
 
3909
            outfile = open(output, 'wb')
 
3910
        try:
 
3911
            branch = Branch.open_containing(from_)[0]
 
3912
            if output is None:
 
3913
                config = branch.get_config()
 
3914
                if mail_to is None:
 
3915
                    mail_to = config.get_user_option('submit_to')
 
3916
                if mail_to is None:
 
3917
                    raise errors.BzrCommandError('No mail-to address'
 
3918
                                                 ' specified')
 
3919
                mail_client = config.get_mail_client()
 
3920
            if remember and submit_branch is None:
 
3921
                raise errors.BzrCommandError(
 
3922
                    '--remember requires a branch to be specified.')
 
3923
            stored_submit_branch = branch.get_submit_branch()
 
3924
            remembered_submit_branch = False
 
3925
            if submit_branch is None:
 
3926
                submit_branch = stored_submit_branch
 
3927
                remembered_submit_branch = True
 
3928
            else:
 
3929
                if stored_submit_branch is None or remember:
 
3930
                    branch.set_submit_branch(submit_branch)
 
3931
            if submit_branch is None:
 
3932
                submit_branch = branch.get_parent()
 
3933
                remembered_submit_branch = True
 
3934
            if submit_branch is None:
 
3935
                raise errors.BzrCommandError('No submit branch known or'
 
3936
                                             ' specified')
 
3937
            if remembered_submit_branch:
 
3938
                note('Using saved location: %s', submit_branch)
 
3939
 
 
3940
            stored_public_branch = branch.get_public_branch()
 
3941
            if public_branch is None:
 
3942
                public_branch = stored_public_branch
 
3943
            elif stored_public_branch is None or remember:
 
3944
                branch.set_public_branch(public_branch)
 
3945
            if no_bundle and public_branch is None:
 
3946
                raise errors.BzrCommandError('No public branch specified or'
 
3947
                                             ' known')
 
3948
            base_revision_id = None
 
3949
            revision_id = None
 
3950
            if revision is not None:
 
3951
                if len(revision) > 2:
 
3952
                    raise errors.BzrCommandError('bzr send takes '
 
3953
                        'at most two one revision identifiers')
 
3954
                revision_id = revision[-1].in_history(branch).rev_id
 
3955
                if len(revision) == 2:
 
3956
                    base_revision_id = revision[0].in_history(branch).rev_id
 
3957
            if revision_id is None:
 
3958
                revision_id = branch.last_revision()
 
3959
            if revision_id == NULL_REVISION:
 
3960
                raise errors.BzrCommandError('No revisions to submit.')
 
3961
            if format == '4':
 
3962
                directive = merge_directive.MergeDirective2.from_objects(
 
3963
                    branch.repository, revision_id, time.time(),
 
3964
                    osutils.local_time_offset(), submit_branch,
 
3965
                    public_branch=public_branch, include_patch=not no_patch,
 
3966
                    include_bundle=not no_bundle, message=message,
 
3967
                    base_revision_id=base_revision_id)
 
3968
            elif format == '0.9':
 
3969
                if not no_bundle:
 
3970
                    if not no_patch:
 
3971
                        patch_type = 'bundle'
 
3972
                    else:
 
3973
                        raise errors.BzrCommandError('Format 0.9 does not'
 
3974
                            ' permit bundle with no patch')
 
3975
                else:
 
3976
                    if not no_patch:
 
3977
                        patch_type = 'diff'
 
3978
                    else:
 
3979
                        patch_type = None
 
3980
                directive = merge_directive.MergeDirective.from_objects(
 
3981
                    branch.repository, revision_id, time.time(),
 
3982
                    osutils.local_time_offset(), submit_branch,
 
3983
                    public_branch=public_branch, patch_type=patch_type,
 
3984
                    message=message)
 
3985
 
 
3986
            outfile.writelines(directive.to_lines())
 
3987
            if output is None:
 
3988
                subject = '[MERGE] '
 
3989
                if message is not None:
 
3990
                    subject += message
 
3991
                else:
 
3992
                    revision = branch.repository.get_revision(revision_id)
 
3993
                    subject += revision.get_summary()
 
3994
                mail_client.compose_merge_request(mail_to, subject,
 
3995
                                                  outfile.getvalue())
 
3996
        finally:
 
3997
            if output != '-':
 
3998
                outfile.close()
 
3999
 
 
4000
 
 
4001
class cmd_bundle_revisions(cmd_send):
 
4002
 
 
4003
    """Create a merge-directive for submiting changes.
 
4004
 
 
4005
    A merge directive provides many things needed for requesting merges:
 
4006
 
 
4007
    * A machine-readable description of the merge to perform
 
4008
 
 
4009
    * An optional patch that is a preview of the changes requested
 
4010
 
 
4011
    * An optional bundle of revision data, so that the changes can be applied
 
4012
      directly from the merge directive, without retrieving data from a
 
4013
      branch.
 
4014
 
 
4015
    If --no-bundle is specified, then public_branch is needed (and must be
 
4016
    up-to-date), so that the receiver can perform the merge using the
 
4017
    public_branch.  The public_branch is always included if known, so that
 
4018
    people can check it later.
 
4019
 
 
4020
    The submit branch defaults to the parent, but can be overridden.  Both
 
4021
    submit branch and public branch will be remembered if supplied.
 
4022
 
 
4023
    If a public_branch is known for the submit_branch, that public submit
 
4024
    branch is used in the merge instructions.  This means that a local mirror
 
4025
    can be used as your actual submit branch, once you have set public_branch
 
4026
    for that mirror.
 
4027
 
 
4028
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
4029
    merge directive format 2.  It is significantly faster and smaller than
 
4030
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
4031
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
4032
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
4033
    """
 
4034
 
 
4035
    takes_options = [
 
4036
        Option('no-bundle',
 
4037
               help='Do not include a bundle in the merge directive.'),
 
4038
        Option('no-patch', help='Do not include a preview patch in the merge'
 
4039
               ' directive.'),
 
4040
        Option('remember',
 
4041
               help='Remember submit and public branch.'),
 
4042
        Option('from',
 
4043
               help='Branch to generate the submission from, '
 
4044
               'rather than the one containing the working directory.',
 
4045
               short_name='f',
 
4046
               type=unicode),
 
4047
        Option('output', short_name='o', help='Write directive to this file.',
 
4048
               type=unicode),
 
4049
        'revision',
 
4050
        RegistryOption.from_kwargs('format',
 
4051
        'Use the specified output format.',
 
4052
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
4053
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
4054
        ]
 
4055
    aliases = ['bundle']
 
4056
 
 
4057
    _see_also = ['send', 'merge']
 
4058
 
 
4059
    hidden = True
 
4060
 
 
4061
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
4062
            no_patch=False, revision=None, remember=False, output=None,
 
4063
            format='4', **kwargs):
 
4064
        if output is None:
 
4065
            output = '-'
 
4066
        return self._run(submit_branch, revision, public_branch, remember,
 
4067
                         format, no_bundle, no_patch, output,
 
4068
                         kwargs.get('from', '.'), None, None)
 
4069
 
 
4070
 
3629
4071
class cmd_tag(Command):
3630
 
    """Create a tag naming a revision.
 
4072
    """Create, remove or modify a tag naming a revision.
3631
4073
    
3632
4074
    Tags give human-meaningful names to revisions.  Commands that take a -r
3633
4075
    (--revision) option can be given -rtag:X, where X is any previously
3710
4152
            self.outf.write('%-20s %s\n' % (tag_name, target))
3711
4153
 
3712
4154
 
3713
 
# command-line interpretation helper for merge-related commands
3714
 
def _merge_helper(other_revision, base_revision,
3715
 
                  check_clean=True, ignore_zero=False,
3716
 
                  this_dir=None, backup_files=False,
3717
 
                  merge_type=None,
3718
 
                  file_list=None, show_base=False, reprocess=False,
3719
 
                  pull=False,
3720
 
                  pb=DummyProgress(),
3721
 
                  change_reporter=None,
3722
 
                  other_rev_id=None):
3723
 
    """Merge changes into a tree.
3724
 
 
3725
 
    base_revision
3726
 
        list(path, revno) Base for three-way merge.  
3727
 
        If [None, None] then a base will be automatically determined.
3728
 
    other_revision
3729
 
        list(path, revno) Other revision for three-way merge.
3730
 
    this_dir
3731
 
        Directory to merge changes into; '.' by default.
3732
 
    check_clean
3733
 
        If true, this_dir must have no uncommitted changes before the
3734
 
        merge begins.
3735
 
    ignore_zero - If true, suppress the "zero conflicts" message when 
3736
 
        there are no conflicts; should be set when doing something we expect
3737
 
        to complete perfectly.
3738
 
    file_list - If supplied, merge only changes to selected files.
3739
 
 
3740
 
    All available ancestors of other_revision and base_revision are
3741
 
    automatically pulled into the branch.
3742
 
 
3743
 
    The revno may be -1 to indicate the last revision on the branch, which is
3744
 
    the typical case.
3745
 
 
3746
 
    This function is intended for use from the command line; programmatic
3747
 
    clients might prefer to call merge.merge_inner(), which has less magic 
3748
 
    behavior.
3749
 
    """
3750
 
    # Loading it late, so that we don't always have to import bzrlib.merge
3751
 
    if merge_type is None:
3752
 
        merge_type = _mod_merge.Merge3Merger
3753
 
    if this_dir is None:
3754
 
        this_dir = u'.'
3755
 
    this_tree = WorkingTree.open_containing(this_dir)[0]
3756
 
    if show_base and not merge_type is _mod_merge.Merge3Merger:
3757
 
        raise errors.BzrCommandError("Show-base is not supported for this merge"
3758
 
                                     " type. %s" % merge_type)
3759
 
    if reprocess and not merge_type.supports_reprocess:
3760
 
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3761
 
                                     " type %s." % merge_type)
3762
 
    if reprocess and show_base:
3763
 
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3764
 
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
3765
 
    #       only want to take out a lock_tree_write() if we don't have to pull
3766
 
    #       any ancestry. But merge might fetch ancestry in the middle, in
3767
 
    #       which case we would need a lock_write().
3768
 
    #       Because we cannot upgrade locks, for now we live with the fact that
3769
 
    #       the tree will be locked multiple times during a merge. (Maybe
3770
 
    #       read-only some of the time, but it means things will get read
3771
 
    #       multiple times.)
3772
 
    try:
3773
 
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3774
 
                                   pb=pb, change_reporter=change_reporter)
3775
 
        merger.pp = ProgressPhase("Merge phase", 5, pb)
3776
 
        merger.pp.next_phase()
3777
 
        merger.check_basis(check_clean)
3778
 
        if other_rev_id is not None:
3779
 
            merger.set_other_revision(other_rev_id, this_tree.branch)
3780
 
        else:
3781
 
            merger.set_other(other_revision)
3782
 
        merger.pp.next_phase()
3783
 
        merger.set_base(base_revision)
3784
 
        if merger.base_rev_id == merger.other_rev_id:
3785
 
            note('Nothing to do.')
3786
 
            return 0
3787
 
        if file_list is None:
3788
 
            if pull and merger.base_rev_id == merger.this_rev_id:
3789
 
                # FIXME: deduplicate with pull
3790
 
                result = merger.this_tree.pull(merger.this_branch,
3791
 
                        False, merger.other_rev_id)
3792
 
                if result.old_revid == result.new_revid:
3793
 
                    note('No revisions to pull.')
3794
 
                else:
3795
 
                    note('Now on revision %d.' % result.new_revno)
3796
 
                return 0
3797
 
        merger.backup_files = backup_files
3798
 
        merger.merge_type = merge_type 
3799
 
        merger.set_interesting_files(file_list)
3800
 
        merger.show_base = show_base 
3801
 
        merger.reprocess = reprocess
3802
 
        conflicts = merger.do_merge()
3803
 
        if file_list is None:
3804
 
            merger.set_pending()
3805
 
    finally:
3806
 
        pb.clear()
3807
 
    return conflicts
3808
 
 
3809
 
 
3810
4155
def _create_prefix(cur_transport):
3811
4156
    needed = [cur_transport]
3812
4157
    # Recurse upwards until we can create a directory successfully
3829
4174
        cur_transport.ensure_base()
3830
4175
 
3831
4176
 
3832
 
# Compatibility
3833
 
merge = _merge_helper
 
4177
def _get_mergeable_helper(location):
 
4178
    """Get a merge directive or bundle if 'location' points to one.
 
4179
 
 
4180
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
4181
    we return the tried transport anyway so that it can reused to access the
 
4182
    branch
 
4183
 
 
4184
    :param location: can point to a bundle or a branch.
 
4185
 
 
4186
    :return: mergeable, transport
 
4187
    """
 
4188
    mergeable = None
 
4189
    url = urlutils.normalize_url(location)
 
4190
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
4191
    location_transport = transport.get_transport(url)
 
4192
    if filename:
 
4193
        try:
 
4194
            # There may be redirections but we ignore the intermediate
 
4195
            # and final transports used
 
4196
            read = bundle.read_mergeable_from_transport
 
4197
            mergeable, t = read(location_transport, filename)
 
4198
        except errors.NotABundle:
 
4199
            # Continue on considering this url a Branch but adjust the
 
4200
            # location_transport
 
4201
            location_transport = location_transport.clone(filename)
 
4202
    return mergeable, location_transport
3834
4203
 
3835
4204
 
3836
4205
# these get imported and then picked up by the scan for cmd_*
3840
4209
# details were needed.
3841
4210
from bzrlib.cmd_version_info import cmd_version_info
3842
4211
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3843
 
from bzrlib.bundle.commands import cmd_bundle_revisions
 
4212
from bzrlib.bundle.commands import (
 
4213
    cmd_bundle_info,
 
4214
    )
3844
4215
from bzrlib.sign_my_commits import cmd_sign_my_commits
3845
4216
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
3846
4217
        cmd_weave_plan_merge, cmd_weave_merge_text