~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2005-08-22 16:31:16 UTC
  • Revision ID: mbp@sourcefrog.net-20050822163116-935a433f338e7d5b
- new shell-complete command to help zsh completion

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
 
 
19
 
import sys, os
 
18
# TODO: Split the command framework away from the actual commands.
 
19
 
 
20
# TODO: probably should say which arguments are candidates for glob
 
21
# expansion on windows and do that at the command level.
 
22
 
 
23
import sys
 
24
import os
20
25
 
21
26
import bzrlib
22
27
from bzrlib.trace import mutter, note, log_error, warning
136
141
        raise BzrCommandError(msg)
137
142
    
138
143
 
 
144
def get_merge_type(typestring):
 
145
    """Attempt to find the merge class/factory associated with a string."""
 
146
    from merge import merge_types
 
147
    try:
 
148
        return merge_types[typestring][0]
 
149
    except KeyError:
 
150
        templ = '%s%%7s: %%s' % (' '*12)
 
151
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
 
152
        type_list = '\n'.join(lines)
 
153
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
154
            (typestring, type_list)
 
155
        raise BzrCommandError(msg)
 
156
    
 
157
 
139
158
 
140
159
def _get_cmd_dict(plugins_override=True):
141
160
    d = {}
237
256
class ExternalCommand(Command):
238
257
    """Class to wrap external commands.
239
258
 
240
 
    We cheat a little here, when get_cmd_class() calls us we actually give it back
241
 
    an object we construct that has the appropriate path, help, options etc for the
242
 
    specified command.
243
 
 
244
 
    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
245
 
    method, which we override to call the Command.__init__ method. That then calls
246
 
    our run method which is pretty straight forward.
247
 
 
248
 
    The only wrinkle is that we have to map bzr's dictionary of options and arguments
249
 
    back into command line options and arguments for the script.
 
259
    We cheat a little here, when get_cmd_class() calls us we actually
 
260
    give it back an object we construct that has the appropriate path,
 
261
    help, options etc for the specified command.
 
262
 
 
263
    When run_bzr() tries to instantiate that 'class' it gets caught by
 
264
    the __call__ method, which we override to call the Command.__init__
 
265
    method. That then calls our run method which is pretty straight
 
266
    forward.
 
267
 
 
268
    The only wrinkle is that we have to map bzr's dictionary of options
 
269
    and arguments back into command line options and arguments for the
 
270
    script.
250
271
    """
251
272
 
252
273
    def find_command(cls, cmd):
503
524
    def run(self, source_list, dest):
504
525
        b = find_branch('.')
505
526
 
 
527
        # TODO: glob expansion on windows?
506
528
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
507
529
 
508
530
 
528
550
 
529
551
 
530
552
 
 
553
class cmd_mv(Command):
 
554
    """Move or rename a file.
 
555
 
 
556
    usage:
 
557
        bzr mv OLDNAME NEWNAME
 
558
        bzr mv SOURCE... DESTINATION
 
559
 
 
560
    If the last argument is a versioned directory, all the other names
 
561
    are moved into it.  Otherwise, there must be exactly two arguments
 
562
    and the file is changed to a new name, which must not already exist.
 
563
 
 
564
    Files cannot be moved between branches.
 
565
    """
 
566
    takes_args = ['names*']
 
567
    def run(self, names_list):
 
568
        if len(names_list) < 2:
 
569
            raise BzrCommandError("missing file argument")
 
570
        b = find_branch(names_list[0])
 
571
 
 
572
        rel_names = [b.relpath(x) for x in names_list]
 
573
        
 
574
        if os.path.isdir(names_list[-1]):
 
575
            # move into existing directory
 
576
            b.move(rel_names[:-1], rel_names[-1])
 
577
        else:
 
578
            if len(names_list) != 2:
 
579
                raise BzrCommandError('to mv multiple files the destination '
 
580
                                      'must be a versioned directory')
 
581
            b.move(rel_names[0], rel_names[1])
 
582
            
 
583
    
531
584
 
532
585
 
533
586
class cmd_pull(Command):
600
653
    """
601
654
    takes_args = ['from_location', 'to_location?']
602
655
    takes_options = ['revision']
 
656
    aliases = ['get', 'clone']
603
657
 
604
658
    def run(self, from_location, to_location=None, revision=None):
605
659
        import errno
606
660
        from bzrlib.merge import merge
607
 
        from bzrlib.branch import DivergedBranches, NoSuchRevision, \
 
661
        from bzrlib.branch import DivergedBranches, \
608
662
             find_cached_branch, Branch
609
663
        from shutil import rmtree
610
664
        from meta_store import CachedStore
651
705
                    revno, rev_id = br_from.get_revision_info(revision[0])
652
706
                try:
653
707
                    br_to.update_revisions(br_from, stop_revision=revno)
654
 
                except NoSuchRevision:
 
708
                except bzrlib.errors.NoSuchRevision:
655
709
                    rmtree(to_location)
656
710
                    msg = "The branch %s has no revision %d." % (from_location,
657
711
                                                                 revno)
797
851
    If files are listed, only the changes in those files are listed.
798
852
    Otherwise, all changes for the tree are listed.
799
853
 
800
 
    TODO: Given two revision arguments, show the difference between them.
801
 
 
802
854
    TODO: Allow diff across branches.
803
855
 
804
856
    TODO: Option to use external diff command; could be GNU diff, wdiff,
813
865
          deleted files.
814
866
 
815
867
    TODO: This probably handles non-Unix newlines poorly.
 
868
 
 
869
    examples:
 
870
        bzr diff
 
871
        bzr diff -r1
 
872
        bzr diff -r1:2
816
873
    """
817
874
    
818
875
    takes_args = ['file*']
831
888
        else:
832
889
            b = find_branch('.')
833
890
 
834
 
        # TODO: Make show_diff support taking 2 arguments
835
 
        base_rev = None
836
891
        if revision is not None:
837
 
            if len(revision) != 1:
838
 
                raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
839
 
            base_rev = revision[0]
840
 
    
841
 
        show_diff(b, base_rev, specific_files=file_list,
842
 
                  external_diff_options=diff_options)
843
 
 
 
892
            if len(revision) == 1:
 
893
                show_diff(b, revision[0], specific_files=file_list,
 
894
                          external_diff_options=diff_options)
 
895
            elif len(revision) == 2:
 
896
                show_diff(b, revision[0], specific_files=file_list,
 
897
                          external_diff_options=diff_options,
 
898
                          revision2=revision[1])
 
899
            else:
 
900
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
901
        else:
 
902
            show_diff(b, None, specific_files=file_list,
 
903
                      external_diff_options=diff_options)
844
904
 
845
905
        
846
906
 
872
932
    """List files modified in working tree."""
873
933
    hidden = True
874
934
    def run(self):
875
 
        from bzrlib.diff import compare_trees
 
935
        from bzrlib.delta import compare_trees
876
936
 
877
937
        b = find_branch('.')
878
938
        td = compare_trees(b.basis_tree(), b.working_tree())
927
987
    """
928
988
 
929
989
    takes_args = ['filename?']
930
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
 
990
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
 
991
                     'long', 'message', 'short',]
931
992
    
932
993
    def run(self, filename=None, timezone='original',
933
994
            verbose=False,
935
996
            forward=False,
936
997
            revision=None,
937
998
            message=None,
938
 
            long=False):
 
999
            long=False,
 
1000
            short=False):
939
1001
        from bzrlib.branch import find_branch
940
1002
        from bzrlib.log import log_formatter, show_log
941
1003
        import codecs
975
1037
        # in e.g. the default C locale.
976
1038
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
977
1039
 
978
 
        if long:
 
1040
        if not short:
979
1041
            log_format = 'long'
980
1042
        else:
981
1043
            log_format = 'short'
1198
1260
 
1199
1261
class cmd_commit(Command):
1200
1262
    """Commit changes into a new revision.
 
1263
    
 
1264
    If no arguments are given, the entire tree is committed.
1201
1265
 
1202
1266
    If selected files are specified, only changes to those files are
1203
 
    committed.  If a directory is specified then its contents are also
1204
 
    committed.
 
1267
    committed.  If a directory is specified then the directory and everything 
 
1268
    within it is committed.
1205
1269
 
1206
1270
    A selected-file commit may fail in some cases where the committed
1207
1271
    tree would be invalid, such as trying to commit a file in a
1215
1279
    takes_options = ['message', 'file', 'verbose', 'unchanged']
1216
1280
    aliases = ['ci', 'checkin']
1217
1281
 
 
1282
    # TODO: Give better message for -s, --summary, used by tla people
 
1283
    
1218
1284
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1219
1285
            unchanged=False):
1220
1286
        from bzrlib.errors import PointlessCommit
1222
1288
 
1223
1289
        ## Warning: shadows builtin file()
1224
1290
        if not message and not file:
 
1291
            # FIXME: Ugly; change status code to send to a provided function?
 
1292
            
1225
1293
            import cStringIO
1226
1294
            stdout = sys.stdout
1227
1295
            catcher = cStringIO.StringIO()
1242
1310
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1243
1311
 
1244
1312
        b = find_branch('.')
1245
 
 
 
1313
        if selected_list:
 
1314
            selected_list = [b.relpath(s) for s in selected_list]
 
1315
            
1246
1316
        try:
1247
1317
            b.commit(message, verbose=verbose,
1248
1318
                     specific_files=selected_list,
1311
1381
    takes_options = ['email']
1312
1382
    
1313
1383
    def run(self, email=False):
 
1384
        try:
 
1385
            b = bzrlib.branch.find_branch('.')
 
1386
        except:
 
1387
            b = None
 
1388
        
1314
1389
        if email:
1315
 
            print bzrlib.osutils.user_email()
 
1390
            print bzrlib.osutils.user_email(b)
1316
1391
        else:
1317
 
            print bzrlib.osutils.username()
 
1392
            print bzrlib.osutils.username(b)
1318
1393
 
1319
1394
 
1320
1395
class cmd_selftest(Command):
1385
1460
 
1386
1461
 
1387
1462
class cmd_merge(Command):
1388
 
    """Perform a three-way merge of trees.
1389
 
    
1390
 
    The SPEC parameters are working tree or revision specifiers.  Working trees
1391
 
    are specified using standard paths or urls.  No component of a directory
1392
 
    path may begin with '@'.
1393
 
    
1394
 
    Working tree examples: '.', '..', 'foo@', but NOT 'foo/@bar'
1395
 
 
1396
 
    Revisions are specified using a dirname/@revno pair, where dirname is the
1397
 
    branch directory and revno is the revision within that branch.  If no revno
1398
 
    is specified, the latest revision is used.
1399
 
 
1400
 
    Revision examples: './@127', 'foo/@', '../@1'
1401
 
 
1402
 
    The OTHER_SPEC parameter is required.  If the BASE_SPEC parameter is
1403
 
    not supplied, the common ancestor of OTHER_SPEC the current branch is used
1404
 
    as the BASE.
1405
 
 
 
1463
    """Perform a three-way merge.
 
1464
    
 
1465
    The branch is the branch you will merge from.  By default, it will merge
 
1466
    the latest revision.  If you specify a revision, that revision will be
 
1467
    merged.  If you specify two revisions, the first will be used as a BASE, 
 
1468
    and the second one as OTHER.  Revision numbers are always relative to the
 
1469
    specified branch.
 
1470
    
 
1471
    Examples:
 
1472
 
 
1473
    To merge the latest revision from bzr.dev
 
1474
    bzr merge ../bzr.dev
 
1475
 
 
1476
    To merge changes up to and including revision 82 from bzr.dev
 
1477
    bzr merge -r 82 ../bzr.dev
 
1478
 
 
1479
    To merge the changes introduced by 82, without previous changes:
 
1480
    bzr merge -r 81..82 ../bzr.dev
 
1481
    
1406
1482
    merge refuses to run if there are any uncommitted changes, unless
1407
1483
    --force is given.
1408
1484
    """
1409
 
    takes_args = ['other_spec', 'base_spec?']
1410
 
    takes_options = ['force', 'merge-type']
 
1485
    takes_args = ['branch?']
 
1486
    takes_options = ['revision', 'force', 'merge-type']
1411
1487
 
1412
 
    def run(self, other_spec, base_spec=None, force=False, merge_type=None):
 
1488
    def run(self, branch='.', revision=None, force=False, 
 
1489
            merge_type=None):
1413
1490
        from bzrlib.merge import merge
1414
1491
        from bzrlib.merge_core import ApplyMerge3
1415
1492
        if merge_type is None:
1416
1493
            merge_type = ApplyMerge3
1417
 
        merge(parse_spec(other_spec), parse_spec(base_spec),
1418
 
              check_clean=(not force), merge_type=merge_type)
 
1494
 
 
1495
        if revision is None or len(revision) < 1:
 
1496
            base = (None, None)
 
1497
            other = (branch, -1)
 
1498
        else:
 
1499
            if len(revision) == 1:
 
1500
                other = (branch, revision[0])
 
1501
                base = (None, None)
 
1502
            else:
 
1503
                assert len(revision) == 2
 
1504
                if None in revision:
 
1505
                    raise BzrCommandError(
 
1506
                        "Merge doesn't permit that revision specifier.")
 
1507
                base = (branch, revision[0])
 
1508
                other = (branch, revision[1])
 
1509
            
 
1510
        merge(other, base, check_clean=(not force), merge_type=merge_type)
1419
1511
 
1420
1512
 
1421
1513
class cmd_revert(Command):
1464
1556
        help.help(topic)
1465
1557
 
1466
1558
 
 
1559
class cmd_shell_complete(Command):
 
1560
    """Show appropriate completions for context.
 
1561
 
 
1562
    For a list of all available commands, say 'bzr shell-complete'."""
 
1563
    takes_args = ['context?']
 
1564
    aliases = ['s-c']
 
1565
    hidden = True
 
1566
    
 
1567
    def run(self, context=None):
 
1568
        import shellcomplete
 
1569
        shellcomplete.shellcomplete(context)
 
1570
 
 
1571
 
 
1572
class cmd_missing(Command):
 
1573
    """What is missing in this branch relative to other branch.
 
1574
    """
 
1575
    takes_args = ['remote?']
 
1576
    aliases = ['mis', 'miss']
 
1577
    # We don't have to add quiet to the list, because 
 
1578
    # unknown options are parsed as booleans
 
1579
    takes_options = ['verbose', 'quiet']
 
1580
 
 
1581
    def run(self, remote=None, verbose=False, quiet=False):
 
1582
        from bzrlib.branch import find_branch, DivergedBranches
 
1583
        from bzrlib.errors import BzrCommandError
 
1584
        from bzrlib.missing import get_parent, show_missing
 
1585
 
 
1586
        if verbose and quiet:
 
1587
            raise BzrCommandError('Cannot pass both quiet and verbose')
 
1588
 
 
1589
        b = find_branch('.')
 
1590
        parent = get_parent(b)
 
1591
        if remote is None:
 
1592
            if parent is None:
 
1593
                raise BzrCommandError("No missing location known or specified.")
 
1594
            else:
 
1595
                if not quiet:
 
1596
                    print "Using last location: %s" % parent
 
1597
                remote = parent
 
1598
        elif parent is None:
 
1599
            # We only update x-pull if it did not exist, missing should not change the parent
 
1600
            b.controlfile('x-pull', 'wb').write(remote + '\n')
 
1601
        br_remote = find_branch(remote)
 
1602
 
 
1603
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1467
1604
 
1468
1605
 
1469
1606
class cmd_plugins(Command):
1498
1635
    'no-recurse':             None,
1499
1636
    'profile':                None,
1500
1637
    'revision':               _parse_revision_str,
 
1638
    'short':                  None,
1501
1639
    'show-ids':               None,
1502
1640
    'timezone':               str,
1503
1641
    'verbose':                None,
1664
1802
    return argdict
1665
1803
 
1666
1804
 
1667
 
def _parse_master_args(argv):
1668
 
    """Parse the arguments that always go with the original command.
1669
 
    These are things like bzr --no-plugins, etc.
1670
 
 
1671
 
    There are now 2 types of option flags. Ones that come *before* the command,
1672
 
    and ones that come *after* the command.
1673
 
    Ones coming *before* the command are applied against all possible commands.
1674
 
    And are generally applied before plugins are loaded.
1675
 
 
1676
 
    The current list are:
1677
 
        --builtin   Allow plugins to load, but don't let them override builtin commands,
1678
 
                    they will still be allowed if they do not override a builtin.
1679
 
        --no-plugins    Don't load any plugins. This lets you get back to official source
1680
 
                        behavior.
1681
 
        --profile   Enable the hotspot profile before running the command.
1682
 
                    For backwards compatibility, this is also a non-master option.
1683
 
        --version   Spit out the version of bzr that is running and exit.
1684
 
                    This is also a non-master option.
1685
 
        --help      Run help and exit, also a non-master option (I think that should stay, though)
1686
 
 
1687
 
    >>> argv, opts = _parse_master_args(['--test'])
1688
 
    Traceback (most recent call last):
1689
 
    ...
1690
 
    BzrCommandError: Invalid master option: 'test'
1691
 
    >>> argv, opts = _parse_master_args(['--version', 'command'])
1692
 
    >>> print argv
1693
 
    ['command']
1694
 
    >>> print opts['version']
1695
 
    True
1696
 
    >>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1697
 
    >>> print argv
1698
 
    ['command', '--more-options']
1699
 
    >>> print opts['profile']
1700
 
    True
1701
 
    >>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1702
 
    >>> print argv
1703
 
    ['command']
1704
 
    >>> print opts['no-plugins']
1705
 
    True
1706
 
    >>> print opts['profile']
1707
 
    False
1708
 
    >>> argv, opts = _parse_master_args(['command', '--profile'])
1709
 
    >>> print argv
1710
 
    ['command', '--profile']
1711
 
    >>> print opts['profile']
1712
 
    False
1713
 
    """
1714
 
    master_opts = {'builtin':False,
1715
 
        'no-plugins':False,
1716
 
        'version':False,
1717
 
        'profile':False,
1718
 
        'help':False
1719
 
    }
1720
 
 
1721
 
    for arg in argv[:]:
1722
 
        if arg[:2] != '--': # at the first non-option, we return the rest
1723
 
            break
1724
 
        arg = arg[2:] # Remove '--'
1725
 
        if arg not in master_opts:
1726
 
            # We could say that this is not an error, that we should
1727
 
            # just let it be handled by the main section instead
1728
 
            raise BzrCommandError('Invalid master option: %r' % arg)
1729
 
        argv.pop(0) # We are consuming this entry
1730
 
        master_opts[arg] = True
1731
 
    return argv, master_opts
1732
 
 
1733
 
 
1734
1805
 
1735
1806
def run_bzr(argv):
1736
1807
    """Execute a command.
1739
1810
    logging and error handling.  
1740
1811
    
1741
1812
    argv
1742
 
       The command-line arguments, without the program name.
 
1813
       The command-line arguments, without the program name from argv[0]
1743
1814
    
1744
1815
    Returns a command status or raises an exception.
 
1816
 
 
1817
    Special master options: these must come before the command because
 
1818
    they control how the command is interpreted.
 
1819
 
 
1820
    --no-plugins
 
1821
        Do not load plugin modules at all
 
1822
 
 
1823
    --builtin
 
1824
        Only use builtin commands.  (Plugins are still allowed to change
 
1825
        other behaviour.)
 
1826
 
 
1827
    --profile
 
1828
        Run under the Python profiler.
1745
1829
    """
 
1830
    
1746
1831
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
1747
1832
 
1748
 
    # some options like --builtin and --no-plugins have special effects
1749
 
    argv, master_opts = _parse_master_args(argv)
1750
 
    if not master_opts['no-plugins']:
 
1833
    opt_profile = opt_no_plugins = opt_builtin = False
 
1834
 
 
1835
    # --no-plugins is handled specially at a very early stage. We need
 
1836
    # to load plugins before doing other command parsing so that they
 
1837
    # can override commands, but this needs to happen first.
 
1838
 
 
1839
    for a in argv[:]:
 
1840
        if a == '--profile':
 
1841
            opt_profile = True
 
1842
        elif a == '--no-plugins':
 
1843
            opt_no_plugins = True
 
1844
        elif a == '--builtin':
 
1845
            opt_builtin = True
 
1846
        else:
 
1847
            break
 
1848
        argv.remove(a)
 
1849
 
 
1850
    if not opt_no_plugins:
1751
1851
        from bzrlib.plugin import load_plugins
1752
1852
        load_plugins()
1753
1853
 
1754
1854
    args, opts = parse_args(argv)
1755
1855
 
1756
 
    if master_opts.get('help') or 'help' in opts:
 
1856
    if 'help' in opts:
1757
1857
        from bzrlib.help import help
1758
 
        if argv:
1759
 
            help(argv[0])
 
1858
        if args:
 
1859
            help(args[0])
1760
1860
        else:
1761
1861
            help()
1762
1862
        return 0            
1765
1865
        show_version()
1766
1866
        return 0
1767
1867
    
1768
 
    if args and args[0] == 'builtin':
1769
 
        include_plugins=False
1770
 
        args = args[1:]
1771
 
    
1772
 
    try:
1773
 
        cmd = str(args.pop(0))
1774
 
    except IndexError:
 
1868
    if not args:
1775
1869
        print >>sys.stderr, "please try 'bzr help' for help"
1776
1870
        return 1
1777
 
 
1778
 
    plugins_override = not (master_opts['builtin'])
1779
 
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1780
 
 
1781
 
    profile = master_opts['profile']
1782
 
    # For backwards compatibility, I would rather stick with --profile being a
1783
 
    # master/global option
1784
 
    if 'profile' in opts:
1785
 
        profile = True
1786
 
        del opts['profile']
 
1871
    
 
1872
    cmd = str(args.pop(0))
 
1873
 
 
1874
    canonical_cmd, cmd_class = \
 
1875
                   get_cmd_class(cmd, plugins_override=not opt_builtin)
1787
1876
 
1788
1877
    # check options are reasonable
1789
1878
    allowed = cmd_class.takes_options
1798
1887
    for k, v in opts.items():
1799
1888
        cmdopts[k.replace('-', '_')] = v
1800
1889
 
1801
 
    if profile:
 
1890
    if opt_profile:
1802
1891
        import hotshot, tempfile
1803
1892
        pffileno, pfname = tempfile.mkstemp()
1804
1893
        try:
1825
1914
 
1826
1915
def _report_exception(summary, quiet=False):
1827
1916
    import traceback
 
1917
    
1828
1918
    log_error('bzr: ' + summary)
1829
1919
    bzrlib.trace.log_exception()
1830
1920
 
 
1921
    if os.environ.get('BZR_DEBUG'):
 
1922
        traceback.print_exc()
 
1923
 
1831
1924
    if not quiet:
 
1925
        sys.stderr.write('\n')
1832
1926
        tb = sys.exc_info()[2]
1833
1927
        exinfo = traceback.extract_tb(tb)
1834
1928
        if exinfo:
1850
1944
                sys.stdout.flush()
1851
1945
        except BzrError, e:
1852
1946
            quiet = isinstance(e, (BzrCommandError))
1853
 
            _report_exception('error: ' + e.args[0], quiet=quiet)
 
1947
            _report_exception('error: ' + str(e), quiet=quiet)
1854
1948
            if len(e.args) > 1:
1855
1949
                for h in e.args[1]:
1856
1950
                    # some explanation or hints