/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-25 21:54:01 UTC
  • Revision ID: mbp@sourcefrog.net-20050725215401-0bed2682b7fee8b5
- fix bugs and add tests for doing commit of selected directories

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())
1290
1236
        b = find_branch('.')
1291
1237
        if selected_list:
1292
1238
            selected_list = [b.relpath(s) for s in selected_list]
1293
 
            
 
1239
        else:
 
1240
            selected_list = [b.relpath('.')]
 
1241
        if selected_list == ['.']:
 
1242
            selected_list = None
 
1243
 
1294
1244
        try:
1295
1245
            b.commit(message, verbose=verbose,
1296
1246
                     specific_files=selected_list,
1455
1405
    --force is given.
1456
1406
    """
1457
1407
    takes_args = ['other_spec', 'base_spec?']
1458
 
    takes_options = ['force', 'merge-type']
 
1408
    takes_options = ['force']
1459
1409
 
1460
 
    def run(self, other_spec, base_spec=None, force=False, merge_type=None):
 
1410
    def run(self, other_spec, base_spec=None, force=False):
1461
1411
        from bzrlib.merge import merge
1462
 
        from bzrlib.merge_core import ApplyMerge3
1463
 
        if merge_type is None:
1464
 
            merge_type = ApplyMerge3
1465
1412
        merge(parse_spec(other_spec), parse_spec(base_spec),
1466
 
              check_clean=(not force), merge_type=merge_type)
 
1413
              check_clean=(not force))
 
1414
 
1467
1415
 
1468
1416
 
1469
1417
class cmd_revert(Command):
 
1418
    """Restore selected files from a previous revision.
 
1419
    """
 
1420
    takes_args = ['file+']
 
1421
    def run(self, file_list):
 
1422
        from bzrlib.branch import find_branch
 
1423
        
 
1424
        if not file_list:
 
1425
            file_list = ['.']
 
1426
            
 
1427
        b = find_branch(file_list[0])
 
1428
 
 
1429
        b.revert([b.relpath(f) for f in file_list])
 
1430
 
 
1431
 
 
1432
class cmd_merge_revert(Command):
1470
1433
    """Reverse all changes since the last commit.
1471
1434
 
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.
 
1435
    Only versioned files are affected.
 
1436
 
 
1437
    TODO: Store backups of any files that will be reverted, so
 
1438
          that the revert can be undone.          
1475
1439
    """
1476
 
    takes_options = ['revision', 'no-backup']
1477
 
    takes_args = ['file*']
1478
 
    aliases = ['merge-revert']
 
1440
    takes_options = ['revision']
1479
1441
 
1480
 
    def run(self, revision=None, no_backup=False, file_list=None):
 
1442
    def run(self, revision=None):
1481
1443
        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
1444
        if revision is None:
1486
1445
            revision = [-1]
1487
1446
        elif len(revision) != 1:
1488
 
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
1447
            raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1489
1448
        merge(('.', revision[0]), parse_spec('.'),
1490
1449
              check_clean=False,
1491
 
              ignore_zero=True,
1492
 
              backup_files=not no_backup,
1493
 
              file_list=file_list)
 
1450
              ignore_zero=True)
1494
1451
 
1495
1452
 
1496
1453
class cmd_assert_fail(Command):
1555
1512
    'update':                 None,
1556
1513
    'long':                   None,
1557
1514
    'root':                   str,
1558
 
    'no-backup':              None,
1559
 
    'merge-type':             get_merge_type,
1560
1515
    }
1561
1516
 
1562
1517
SHORT_OPTIONS = {
1712
1667
    return argdict
1713
1668
 
1714
1669
 
 
1670
def _parse_master_args(argv):
 
1671
    """Parse the arguments that always go with the original command.
 
1672
    These are things like bzr --no-plugins, etc.
 
1673
 
 
1674
    There are now 2 types of option flags. Ones that come *before* the command,
 
1675
    and ones that come *after* the command.
 
1676
    Ones coming *before* the command are applied against all possible commands.
 
1677
    And are generally applied before plugins are loaded.
 
1678
 
 
1679
    The current list are:
 
1680
        --builtin   Allow plugins to load, but don't let them override builtin commands,
 
1681
                    they will still be allowed if they do not override a builtin.
 
1682
        --no-plugins    Don't load any plugins. This lets you get back to official source
 
1683
                        behavior.
 
1684
        --profile   Enable the hotspot profile before running the command.
 
1685
                    For backwards compatibility, this is also a non-master option.
 
1686
        --version   Spit out the version of bzr that is running and exit.
 
1687
                    This is also a non-master option.
 
1688
        --help      Run help and exit, also a non-master option (I think that should stay, though)
 
1689
 
 
1690
    >>> argv, opts = _parse_master_args(['--test'])
 
1691
    Traceback (most recent call last):
 
1692
    ...
 
1693
    BzrCommandError: Invalid master option: 'test'
 
1694
    >>> argv, opts = _parse_master_args(['--version', 'command'])
 
1695
    >>> print argv
 
1696
    ['command']
 
1697
    >>> print opts['version']
 
1698
    True
 
1699
    >>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
 
1700
    >>> print argv
 
1701
    ['command', '--more-options']
 
1702
    >>> print opts['profile']
 
1703
    True
 
1704
    >>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
 
1705
    >>> print argv
 
1706
    ['command']
 
1707
    >>> print opts['no-plugins']
 
1708
    True
 
1709
    >>> print opts['profile']
 
1710
    False
 
1711
    >>> argv, opts = _parse_master_args(['command', '--profile'])
 
1712
    >>> print argv
 
1713
    ['command', '--profile']
 
1714
    >>> print opts['profile']
 
1715
    False
 
1716
    """
 
1717
    master_opts = {'builtin':False,
 
1718
        'no-plugins':False,
 
1719
        'version':False,
 
1720
        'profile':False,
 
1721
        'help':False
 
1722
    }
 
1723
 
 
1724
    for arg in argv[:]:
 
1725
        if arg[:2] != '--': # at the first non-option, we return the rest
 
1726
            break
 
1727
        arg = arg[2:] # Remove '--'
 
1728
        if arg not in master_opts:
 
1729
            # We could say that this is not an error, that we should
 
1730
            # just let it be handled by the main section instead
 
1731
            raise BzrCommandError('Invalid master option: %r' % arg)
 
1732
        argv.pop(0) # We are consuming this entry
 
1733
        master_opts[arg] = True
 
1734
    return argv, master_opts
 
1735
 
 
1736
 
1715
1737
 
1716
1738
def run_bzr(argv):
1717
1739
    """Execute a command.
1720
1742
    logging and error handling.  
1721
1743
    
1722
1744
    argv
1723
 
       The command-line arguments, without the program name from argv[0]
 
1745
       The command-line arguments, without the program name.
1724
1746
    
1725
1747
    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
1748
    """
1740
 
    
1741
1749
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
1742
1750
 
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:
 
1751
    # some options like --builtin and --no-plugins have special effects
 
1752
    argv, master_opts = _parse_master_args(argv)
 
1753
    if not master_opts['no-plugins']:
1761
1754
        from bzrlib.plugin import load_plugins
1762
1755
        load_plugins()
1763
1756
 
1764
1757
    args, opts = parse_args(argv)
1765
1758
 
1766
 
    if 'help' in opts:
 
1759
    if master_opts.get('help') or 'help' in opts:
1767
1760
        from bzrlib.help import help
1768
 
        if args:
1769
 
            help(args[0])
 
1761
        if argv:
 
1762
            help(argv[0])
1770
1763
        else:
1771
1764
            help()
1772
1765
        return 0            
1775
1768
        show_version()
1776
1769
        return 0
1777
1770
    
1778
 
    if not args:
 
1771
    if args and args[0] == 'builtin':
 
1772
        include_plugins=False
 
1773
        args = args[1:]
 
1774
    
 
1775
    try:
 
1776
        cmd = str(args.pop(0))
 
1777
    except IndexError:
1779
1778
        print >>sys.stderr, "please try 'bzr help' for help"
1780
1779
        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)
 
1780
 
 
1781
    plugins_override = not (master_opts['builtin'])
 
1782
    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
 
1783
 
 
1784
    profile = master_opts['profile']
 
1785
    # For backwards compatibility, I would rather stick with --profile being a
 
1786
    # master/global option
 
1787
    if 'profile' in opts:
 
1788
        profile = True
 
1789
        del opts['profile']
1786
1790
 
1787
1791
    # check options are reasonable
1788
1792
    allowed = cmd_class.takes_options
1797
1801
    for k, v in opts.items():
1798
1802
        cmdopts[k.replace('-', '_')] = v
1799
1803
 
1800
 
    if opt_profile:
 
1804
    if profile:
1801
1805
        import hotshot, tempfile
1802
1806
        pffileno, pfname = tempfile.mkstemp()
1803
1807
        try:
1824
1828
 
1825
1829
def _report_exception(summary, quiet=False):
1826
1830
    import traceback
1827
 
    
1828
1831
    log_error('bzr: ' + summary)
1829
1832
    bzrlib.trace.log_exception()
1830
1833
 
1831
 
    if os.environ.get('BZR_DEBUG'):
1832
 
        traceback.print_exc()
1833
 
 
1834
1834
    if not quiet:
1835
 
        sys.stderr.write('\n')
1836
1835
        tb = sys.exc_info()[2]
1837
1836
        exinfo = traceback.extract_tb(tb)
1838
1837
        if exinfo:
1854
1853
                sys.stdout.flush()
1855
1854
        except BzrError, e:
1856
1855
            quiet = isinstance(e, (BzrCommandError))
1857
 
            _report_exception('error: ' + str(e), quiet=quiet)
 
1856
            _report_exception('error: ' + e.args[0], quiet=quiet)
1858
1857
            if len(e.args) > 1:
1859
1858
                for h in e.args[1]:
1860
1859
                    # some explanation or hints