/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/commands.py

  • Committer: Martin Pool
  • Date: 2005-07-23 14:06:37 UTC
  • Revision ID: mbp@sourcefrog.net-20050723140637-c9bf049e0e11ea05
- start adding tests for commit in subdir
- change _parse_master_args to not strip off argv[0] 
  so that it's easier to call these from white-box
  tests

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
 
# 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
 
18
 
 
19
import sys, os
25
20
 
26
21
import bzrlib
27
22
from bzrlib.trace import mutter, note, log_error, warning
127
122
    return revs
128
123
 
129
124
 
130
 
def get_merge_type(typestring):
131
 
    """Attempt to find the merge class/factory associated with a string."""
132
 
    from merge import merge_types
133
 
    try:
134
 
        return merge_types[typestring][0]
135
 
    except KeyError:
136
 
        templ = '%s%%7s: %%s' % (' '*12)
137
 
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
138
 
        type_list = '\n'.join(lines)
139
 
        msg = "No known merge type %s. Supported types are:\n%s" %\
140
 
            (typestring, type_list)
141
 
        raise BzrCommandError(msg)
142
 
    
143
 
 
144
125
 
145
126
def _get_cmd_dict(plugins_override=True):
146
127
    d = {}
242
223
class ExternalCommand(Command):
243
224
    """Class to wrap external commands.
244
225
 
245
 
    We cheat a little here, when get_cmd_class() calls us we actually
246
 
    give it back an object we construct that has the appropriate path,
247
 
    help, options etc for the specified command.
248
 
 
249
 
    When run_bzr() tries to instantiate that 'class' it gets caught by
250
 
    the __call__ method, which we override to call the Command.__init__
251
 
    method. That then calls our run method which is pretty straight
252
 
    forward.
253
 
 
254
 
    The only wrinkle is that we have to map bzr's dictionary of options
255
 
    and arguments back into command line options and arguments for the
256
 
    script.
 
226
    We cheat a little here, when get_cmd_class() calls us we actually give it back
 
227
    an object we construct that has the appropriate path, help, options etc for the
 
228
    specified command.
 
229
 
 
230
    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
 
231
    method, which we override to call the Command.__init__ method. That then calls
 
232
    our run method which is pretty straight forward.
 
233
 
 
234
    The only wrinkle is that we have to map bzr's dictionary of options and arguments
 
235
    back into command line options and arguments for the script.
257
236
    """
258
237
 
259
238
    def find_command(cls, cmd):
510
489
    def run(self, source_list, dest):
511
490
        b = find_branch('.')
512
491
 
513
 
        # TODO: glob expansion on windows?
514
492
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
515
493
 
516
494
 
536
514
 
537
515
 
538
516
 
539
 
class cmd_mv(Command):
540
 
    """Move or rename a file.
541
 
 
542
 
    usage:
543
 
        bzr mv OLDNAME NEWNAME
544
 
        bzr mv SOURCE... DESTINATION
545
 
 
546
 
    If the last argument is a versioned directory, all the other names
547
 
    are moved into it.  Otherwise, there must be exactly two arguments
548
 
    and the file is changed to a new name, which must not already exist.
549
 
 
550
 
    Files cannot be moved between branches.
551
 
    """
552
 
    takes_args = ['names*']
553
 
    def run(self, names_list):
554
 
        if len(names_list) < 2:
555
 
            raise BzrCommandError("missing file argument")
556
 
        b = find_branch(names_list[0])
557
 
 
558
 
        rel_names = [b.relpath(x) for x in names_list]
559
 
        
560
 
        if os.path.isdir(names_list[-1]):
561
 
            # move into existing directory
562
 
            b.move(rel_names[:-1], rel_names[-1])
563
 
        else:
564
 
            if len(names_list) != 2:
565
 
                raise BzrCommandError('to mv multiple files the destination '
566
 
                                      'must be a versioned directory')
567
 
            b.move(rel_names[0], rel_names[1])
568
 
            
569
 
    
570
517
 
571
518
 
572
519
class cmd_pull(Command):
639
586
    """
640
587
    takes_args = ['from_location', 'to_location?']
641
588
    takes_options = ['revision']
642
 
    aliases = ['get', 'clone']
643
589
 
644
590
    def run(self, from_location, to_location=None, revision=None):
645
591
        import errno
646
592
        from bzrlib.merge import merge
647
 
        from bzrlib.branch import DivergedBranches, \
 
593
        from bzrlib.branch import DivergedBranches, NoSuchRevision, \
648
594
             find_cached_branch, Branch
649
595
        from shutil import rmtree
650
596
        from meta_store import CachedStore
691
637
                    revno, rev_id = br_from.get_revision_info(revision[0])
692
638
                try:
693
639
                    br_to.update_revisions(br_from, stop_revision=revno)
694
 
                except bzrlib.errors.NoSuchRevision:
 
640
                except NoSuchRevision:
695
641
                    rmtree(to_location)
696
642
                    msg = "The branch %s has no revision %d." % (from_location,
697
643
                                                                 revno)
912
858
    """List files modified in working tree."""
913
859
    hidden = True
914
860
    def run(self):
915
 
        from bzrlib.delta import compare_trees
 
861
        from bzrlib.diff import compare_trees
916
862
 
917
863
        b = find_branch('.')
918
864
        td = compare_trees(b.basis_tree(), b.working_tree())
1238
1184
 
1239
1185
class cmd_commit(Command):
1240
1186
    """Commit changes into a new revision.
1241
 
    
1242
 
    If no arguments are given, the entire tree is committed.
1243
1187
 
1244
1188
    If selected files are specified, only changes to those files are
1245
 
    committed.  If a directory is specified then the directory and everything 
1246
 
    within it is committed.
 
1189
    committed.  If a directory is specified then its contents are also
 
1190
    committed.
1247
1191
 
1248
1192
    A selected-file commit may fail in some cases where the committed
1249
1193
    tree would be invalid, such as trying to commit a file in a
1257
1201
    takes_options = ['message', 'file', 'verbose', 'unchanged']
1258
1202
    aliases = ['ci', 'checkin']
1259
1203
 
1260
 
    # TODO: Give better message for -s, --summary, used by tla people
1261
 
    
1262
1204
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1263
1205
            unchanged=False):
1264
1206
        from bzrlib.errors import PointlessCommit
1266
1208
 
1267
1209
        ## Warning: shadows builtin file()
1268
1210
        if not message and not file:
1269
 
            # FIXME: Ugly; change status code to send to a provided function?
1270
 
            
1271
1211
            import cStringIO
1272
1212
            stdout = sys.stdout
1273
1213
            catcher = cStringIO.StringIO()
1288
1228
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1289
1229
 
1290
1230
        b = find_branch('.')
1291
 
        if selected_list:
1292
 
            selected_list = [b.relpath(s) for s in selected_list]
1293
 
            
 
1231
 
1294
1232
        try:
1295
1233
            b.commit(message, verbose=verbose,
1296
1234
                     specific_files=selected_list,
1455
1393
    --force is given.
1456
1394
    """
1457
1395
    takes_args = ['other_spec', 'base_spec?']
1458
 
    takes_options = ['force', 'merge-type']
 
1396
    takes_options = ['force']
1459
1397
 
1460
 
    def run(self, other_spec, base_spec=None, force=False, merge_type=None):
 
1398
    def run(self, other_spec, base_spec=None, force=False):
1461
1399
        from bzrlib.merge import merge
1462
 
        from bzrlib.merge_core import ApplyMerge3
1463
 
        if merge_type is None:
1464
 
            merge_type = ApplyMerge3
1465
1400
        merge(parse_spec(other_spec), parse_spec(base_spec),
1466
 
              check_clean=(not force), merge_type=merge_type)
 
1401
              check_clean=(not force))
 
1402
 
1467
1403
 
1468
1404
 
1469
1405
class cmd_revert(Command):
 
1406
    """Restore selected files from a previous revision.
 
1407
    """
 
1408
    takes_args = ['file+']
 
1409
    def run(self, file_list):
 
1410
        from bzrlib.branch import find_branch
 
1411
        
 
1412
        if not file_list:
 
1413
            file_list = ['.']
 
1414
            
 
1415
        b = find_branch(file_list[0])
 
1416
 
 
1417
        b.revert([b.relpath(f) for f in file_list])
 
1418
 
 
1419
 
 
1420
class cmd_merge_revert(Command):
1470
1421
    """Reverse all changes since the last commit.
1471
1422
 
1472
 
    Only versioned files are affected.  Specify filenames to revert only 
1473
 
    those files.  By default, any files that are changed will be backed up
1474
 
    first.  Backup files have a '~' appended to their name.
 
1423
    Only versioned files are affected.
 
1424
 
 
1425
    TODO: Store backups of any files that will be reverted, so
 
1426
          that the revert can be undone.          
1475
1427
    """
1476
 
    takes_options = ['revision', 'no-backup']
1477
 
    takes_args = ['file*']
1478
 
    aliases = ['merge-revert']
 
1428
    takes_options = ['revision']
1479
1429
 
1480
 
    def run(self, revision=None, no_backup=False, file_list=None):
 
1430
    def run(self, revision=None):
1481
1431
        from bzrlib.merge import merge
1482
 
        if file_list is not None:
1483
 
            if len(file_list) == 0:
1484
 
                raise BzrCommandError("No files specified")
1485
1432
        if revision is None:
1486
1433
            revision = [-1]
1487
1434
        elif len(revision) != 1:
1488
 
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
1435
            raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1489
1436
        merge(('.', revision[0]), parse_spec('.'),
1490
1437
              check_clean=False,
1491
 
              ignore_zero=True,
1492
 
              backup_files=not no_backup,
1493
 
              file_list=file_list)
 
1438
              ignore_zero=True)
1494
1439
 
1495
1440
 
1496
1441
class cmd_assert_fail(Command):
1555
1500
    'update':                 None,
1556
1501
    'long':                   None,
1557
1502
    'root':                   str,
1558
 
    'no-backup':              None,
1559
 
    'merge-type':             get_merge_type,
1560
1503
    }
1561
1504
 
1562
1505
SHORT_OPTIONS = {
1712
1655
    return argdict
1713
1656
 
1714
1657
 
 
1658
def _parse_master_args(argv):
 
1659
    """Parse the arguments that always go with the original command.
 
1660
    These are things like bzr --no-plugins, etc.
 
1661
 
 
1662
    There are now 2 types of option flags. Ones that come *before* the command,
 
1663
    and ones that come *after* the command.
 
1664
    Ones coming *before* the command are applied against all possible commands.
 
1665
    And are generally applied before plugins are loaded.
 
1666
 
 
1667
    The current list are:
 
1668
        --builtin   Allow plugins to load, but don't let them override builtin commands,
 
1669
                    they will still be allowed if they do not override a builtin.
 
1670
        --no-plugins    Don't load any plugins. This lets you get back to official source
 
1671
                        behavior.
 
1672
        --profile   Enable the hotspot profile before running the command.
 
1673
                    For backwards compatibility, this is also a non-master option.
 
1674
        --version   Spit out the version of bzr that is running and exit.
 
1675
                    This is also a non-master option.
 
1676
        --help      Run help and exit, also a non-master option (I think that should stay, though)
 
1677
 
 
1678
    >>> argv, opts = _parse_master_args(['--test'])
 
1679
    Traceback (most recent call last):
 
1680
    ...
 
1681
    BzrCommandError: Invalid master option: 'test'
 
1682
    >>> argv, opts = _parse_master_args(['--version', 'command'])
 
1683
    >>> print argv
 
1684
    ['command']
 
1685
    >>> print opts['version']
 
1686
    True
 
1687
    >>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
 
1688
    >>> print argv
 
1689
    ['command', '--more-options']
 
1690
    >>> print opts['profile']
 
1691
    True
 
1692
    >>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
 
1693
    >>> print argv
 
1694
    ['command']
 
1695
    >>> print opts['no-plugins']
 
1696
    True
 
1697
    >>> print opts['profile']
 
1698
    False
 
1699
    >>> argv, opts = _parse_master_args(['command', '--profile'])
 
1700
    >>> print argv
 
1701
    ['command', '--profile']
 
1702
    >>> print opts['profile']
 
1703
    False
 
1704
    """
 
1705
    master_opts = {'builtin':False,
 
1706
        'no-plugins':False,
 
1707
        'version':False,
 
1708
        'profile':False,
 
1709
        'help':False
 
1710
    }
 
1711
 
 
1712
    for arg in argv[:]:
 
1713
        if arg[:2] != '--': # at the first non-option, we return the rest
 
1714
            break
 
1715
        arg = arg[2:] # Remove '--'
 
1716
        if arg not in master_opts:
 
1717
            # We could say that this is not an error, that we should
 
1718
            # just let it be handled by the main section instead
 
1719
            raise BzrCommandError('Invalid master option: %r' % arg)
 
1720
        argv.pop(0) # We are consuming this entry
 
1721
        master_opts[arg] = True
 
1722
    return argv, master_opts
 
1723
 
 
1724
 
1715
1725
 
1716
1726
def run_bzr(argv):
1717
1727
    """Execute a command.
1720
1730
    logging and error handling.  
1721
1731
    
1722
1732
    argv
1723
 
       The command-line arguments, without the program name from argv[0]
 
1733
       The command-line arguments, without the program name.
1724
1734
    
1725
1735
    Returns a command status or raises an exception.
1726
 
 
1727
 
    Special master options: these must come before the command because
1728
 
    they control how the command is interpreted.
1729
 
 
1730
 
    --no-plugins
1731
 
        Do not load plugin modules at all
1732
 
 
1733
 
    --builtin
1734
 
        Only use builtin commands.  (Plugins are still allowed to change
1735
 
        other behaviour.)
1736
 
 
1737
 
    --profile
1738
 
        Run under the Python profiler.
1739
1736
    """
1740
 
    
1741
1737
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
1742
1738
 
1743
 
    opt_profile = opt_no_plugins = opt_builtin = False
1744
 
 
1745
 
    # --no-plugins is handled specially at a very early stage. We need
1746
 
    # to load plugins before doing other command parsing so that they
1747
 
    # can override commands, but this needs to happen first.
1748
 
 
1749
 
    for a in argv[:]:
1750
 
        if a == '--profile':
1751
 
            opt_profile = True
1752
 
        elif a == '--no-plugins':
1753
 
            opt_no_plugins = True
1754
 
        elif a == '--builtin':
1755
 
            opt_builtin = True
1756
 
        else:
1757
 
            break
1758
 
        argv.remove(a)
1759
 
 
1760
 
    if not opt_no_plugins:
 
1739
    # some options like --builtin and --no-plugins have special effects
 
1740
    argv, master_opts = _parse_master_args(argv)
 
1741
    if not master_opts['no-plugins']:
1761
1742
        from bzrlib.plugin import load_plugins
1762
1743
        load_plugins()
1763
1744
 
1764
1745
    args, opts = parse_args(argv)
1765
1746
 
1766
 
    if 'help' in opts:
 
1747
    if master_opts.get('help') or 'help' in opts:
1767
1748
        from bzrlib.help import help
1768
 
        if args:
1769
 
            help(args[0])
 
1749
        if argv:
 
1750
            help(argv[0])
1770
1751
        else:
1771
1752
            help()
1772
1753
        return 0            
1775
1756
        show_version()
1776
1757
        return 0
1777
1758
    
1778
 
    if not args:
 
1759
    if args and args[0] == 'builtin':
 
1760
        include_plugins=False
 
1761
        args = args[1:]
 
1762
    
 
1763
    try:
 
1764
        cmd = str(args.pop(0))
 
1765
    except IndexError:
1779
1766
        print >>sys.stderr, "please try 'bzr help' for help"
1780
1767
        return 1
1781
 
    
1782
 
    cmd = str(args.pop(0))
1783
 
 
1784
 
    canonical_cmd, cmd_class = \
1785
 
                   get_cmd_class(cmd, plugins_override=not opt_builtin)
 
1768
 
 
1769
    plugins_override = not (master_opts['builtin'])
 
1770
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
 
1771
 
 
1772
    profile = master_opts['profile']
 
1773
    # For backwards compatibility, I would rather stick with --profile being a
 
1774
    # master/global option
 
1775
    if 'profile' in opts:
 
1776
        profile = True
 
1777
        del opts['profile']
1786
1778
 
1787
1779
    # check options are reasonable
1788
1780
    allowed = cmd_class.takes_options
1797
1789
    for k, v in opts.items():
1798
1790
        cmdopts[k.replace('-', '_')] = v
1799
1791
 
1800
 
    if opt_profile:
 
1792
    if profile:
1801
1793
        import hotshot, tempfile
1802
1794
        pffileno, pfname = tempfile.mkstemp()
1803
1795
        try:
1824
1816
 
1825
1817
def _report_exception(summary, quiet=False):
1826
1818
    import traceback
1827
 
    
1828
1819
    log_error('bzr: ' + summary)
1829
1820
    bzrlib.trace.log_exception()
1830
1821
 
1831
 
    if os.environ.get('BZR_DEBUG'):
1832
 
        traceback.print_exc()
1833
 
 
1834
1822
    if not quiet:
1835
 
        sys.stderr.write('\n')
1836
1823
        tb = sys.exc_info()[2]
1837
1824
        exinfo = traceback.extract_tb(tb)
1838
1825
        if exinfo:
1854
1841
                sys.stdout.flush()
1855
1842
        except BzrError, e:
1856
1843
            quiet = isinstance(e, (BzrCommandError))
1857
 
            _report_exception('error: ' + str(e), quiet=quiet)
 
1844
            _report_exception('error: ' + e.args[0], quiet=quiet)
1858
1845
            if len(e.args) > 1:
1859
1846
                for h in e.args[1]:
1860
1847
                    # some explanation or hints