1
# Copyright (C) 2004, 2005 by Canonical Ltd
 
 
3
# This program is free software; you can redistribute it and/or modify
 
 
4
# it under the terms of the GNU General Public License as published by
 
 
5
# the Free Software Foundation; either version 2 of the License, or
 
 
6
# (at your option) any later version.
 
 
8
# This program is distributed in the hope that it will be useful,
 
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
11
# GNU General Public License for more details.
 
 
13
# You should have received a copy of the GNU General Public License
 
 
14
# along with this program; if not, write to the Free Software
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
18
# TODO: probably should say which arguments are candidates for glob
 
 
19
# expansion on windows and do that at the command level.
 
 
21
# TODO: Help messages for options.
 
 
23
# TODO: Define arguments by objects, rather than just using names.
 
 
24
# Those objects can specify the expected type of the argument, which
 
 
25
# would help with validation and shell completion.
 
 
28
# TODO: Help messages for options.
 
 
30
# TODO: Define arguments by objects, rather than just using names.
 
 
31
# Those objects can specify the expected type of the argument, which
 
 
32
# would help with validation and shell completion.
 
 
38
from warnings import warn
 
 
39
from inspect import getdoc
 
 
43
from bzrlib.trace import mutter, note, log_error, warning
 
 
44
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
 
45
from bzrlib.revisionspec import RevisionSpec
 
 
46
from bzrlib import BZRDIR
 
 
51
def register_command(cmd):
 
 
52
    "Utility function to help register a command"
 
 
55
    if k.startswith("cmd_"):
 
 
56
        k_unsquished = _unsquish_command_name(k)
 
 
59
    if not plugin_cmds.has_key(k_unsquished):
 
 
60
        plugin_cmds[k_unsquished] = cmd
 
 
61
        mutter('registered plugin command %s', k_unsquished)      
 
 
63
        log_error('Two plugins defined the same command: %r' % k)
 
 
64
        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
 
 
67
def _squish_command_name(cmd):
 
 
68
    return 'cmd_' + cmd.replace('-', '_')
 
 
71
def _unsquish_command_name(cmd):
 
 
72
    assert cmd.startswith("cmd_")
 
 
73
    return cmd[4:].replace('_','-')
 
 
76
def _parse_revision_str(revstr):
 
 
77
    """This handles a revision string -> revno.
 
 
79
    This always returns a list.  The list will have one element for
 
 
82
    >>> _parse_revision_str('234')
 
 
83
    [<RevisionSpec_int 234>]
 
 
84
    >>> _parse_revision_str('234..567')
 
 
85
    [<RevisionSpec_int 234>, <RevisionSpec_int 567>]
 
 
86
    >>> _parse_revision_str('..')
 
 
87
    [<RevisionSpec None>, <RevisionSpec None>]
 
 
88
    >>> _parse_revision_str('..234')
 
 
89
    [<RevisionSpec None>, <RevisionSpec_int 234>]
 
 
90
    >>> _parse_revision_str('234..')
 
 
91
    [<RevisionSpec_int 234>, <RevisionSpec None>]
 
 
92
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
 
 
93
    [<RevisionSpec_int 234>, <RevisionSpec_int 456>, <RevisionSpec_int 789>]
 
 
94
    >>> _parse_revision_str('234....789') # Error?
 
 
95
    [<RevisionSpec_int 234>, <RevisionSpec None>, <RevisionSpec_int 789>]
 
 
96
    >>> _parse_revision_str('revid:test@other.com-234234')
 
 
97
    [<RevisionSpec_revid revid:test@other.com-234234>]
 
 
98
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
 
 
99
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
 
 
100
    >>> _parse_revision_str('revid:test@other.com-234234..23')
 
 
101
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_int 23>]
 
 
102
    >>> _parse_revision_str('date:2005-04-12')
 
 
103
    [<RevisionSpec_date date:2005-04-12>]
 
 
104
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
 
 
105
    [<RevisionSpec_date date:2005-04-12 12:24:33>]
 
 
106
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
 
 
107
    [<RevisionSpec_date date:2005-04-12T12:24:33>]
 
 
108
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
 
 
109
    [<RevisionSpec_date date:2005-04-12,12:24:33>]
 
 
110
    >>> _parse_revision_str('-5..23')
 
 
111
    [<RevisionSpec_int -5>, <RevisionSpec_int 23>]
 
 
112
    >>> _parse_revision_str('-5')
 
 
113
    [<RevisionSpec_int -5>]
 
 
114
    >>> _parse_revision_str('123a')
 
 
115
    Traceback (most recent call last):
 
 
117
    BzrError: No namespace registered for string: '123a'
 
 
118
    >>> _parse_revision_str('abc')
 
 
119
    Traceback (most recent call last):
 
 
121
    BzrError: No namespace registered for string: 'abc'
 
 
124
    old_format_re = re.compile('\d*:\d*')
 
 
125
    m = old_format_re.match(revstr)
 
 
128
        warning('Colon separator for revision numbers is deprecated.'
 
 
130
        for rev in revstr.split(':'):
 
 
132
                revs.append(RevisionSpec(int(rev)))
 
 
134
                revs.append(RevisionSpec(None))
 
 
136
        for x in revstr.split('..'):
 
 
138
                revs.append(RevisionSpec(None))
 
 
140
                revs.append(RevisionSpec(x))
 
 
144
def get_merge_type(typestring):
 
 
145
    """Attempt to find the merge class/factory associated with a string."""
 
 
146
    from merge import merge_types
 
 
148
        return merge_types[typestring][0]
 
 
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)
 
 
158
def _builtin_commands():
 
 
159
    import bzrlib.builtins
 
 
161
    builtins = bzrlib.builtins.__dict__
 
 
162
    for name in builtins:
 
 
163
        if name.startswith("cmd_"):
 
 
164
            real_name = _unsquish_command_name(name)        
 
 
165
            r[real_name] = builtins[name]
 
 
170
def builtin_command_names():
 
 
171
    """Return list of builtin command names."""
 
 
172
    return _builtin_commands().keys()
 
 
175
def plugin_command_names():
 
 
176
    return plugin_cmds.keys()
 
 
179
def _get_cmd_dict(plugins_override=True):
 
 
180
    """Return name->class mapping for all commands."""
 
 
181
    d = _builtin_commands()
 
 
183
        d.update(plugin_cmds)
 
 
187
def get_all_cmds(plugins_override=True):
 
 
188
    """Return canonical name and class for all registered commands."""
 
 
189
    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
 
 
193
def get_cmd_object(cmd_name, plugins_override=True):
 
 
194
    """Return the canonical name and command class for a command.
 
 
197
        If true, plugin commands can override builtins.
 
 
199
    from bzrlib.externalcommand import ExternalCommand
 
 
201
    cmd_name = str(cmd_name)            # not unicode
 
 
203
    # first look up this command under the specified name
 
 
204
    cmds = _get_cmd_dict(plugins_override=plugins_override)
 
 
206
        return cmds[cmd_name]()
 
 
210
    # look for any command which claims this as an alias
 
 
211
    for real_cmd_name, cmd_class in cmds.iteritems():
 
 
212
        if cmd_name in cmd_class.aliases:
 
 
215
    cmd_obj = ExternalCommand.find_command(cmd_name)
 
 
219
    raise BzrCommandError("unknown command %r" % cmd_name)
 
 
222
class Command(object):
 
 
223
    """Base class for commands.
 
 
225
    Commands are the heart of the command-line bzr interface.
 
 
227
    The command object mostly handles the mapping of command-line
 
 
228
    parameters into one or more bzrlib operations, and of the results
 
 
231
    Commands normally don't have any state.  All their arguments are
 
 
232
    passed in to the run method.  (Subclasses may take a different
 
 
233
    policy if the behaviour of the instance needs to depend on e.g. a
 
 
234
    shell plugin and not just its Python class.)
 
 
236
    The docstring for an actual command should give a single-line
 
 
237
    summary, then a complete description of the command.  A grammar
 
 
238
    description will be inserted.
 
 
241
        Other accepted names for this command.
 
 
244
        List of argument forms, marked with whether they are optional,
 
 
248
        List of options that may be given for this command.
 
 
251
        If true, this command isn't advertised.  This is typically
 
 
252
        for commands intended for expert users.
 
 
262
        """Construct an instance of this command."""
 
 
263
        if self.__doc__ == Command.__doc__:
 
 
264
            warn("No help message set for %r" % self)
 
 
267
    def run_argv(self, argv):
 
 
268
        """Parse command line and run."""
 
 
269
        args, opts = parse_args(argv)
 
 
271
        if 'help' in opts:  # e.g. bzr add --help
 
 
272
            from bzrlib.help import help_on_command
 
 
273
            help_on_command(self.name())
 
 
276
        # check options are reasonable
 
 
277
        allowed = self.takes_options
 
 
279
            if oname not in allowed:
 
 
280
                raise BzrCommandError("option '--%s' is not allowed for command %r"
 
 
281
                                      % (oname, self.name()))
 
 
283
        # mix arguments and options into one dictionary
 
 
284
        cmdargs = _match_argform(self.name(), self.takes_args, args)
 
 
286
        for k, v in opts.items():
 
 
287
            cmdopts[k.replace('-', '_')] = v
 
 
289
        all_cmd_args = cmdargs.copy()
 
 
290
        all_cmd_args.update(cmdopts)
 
 
292
        return self.run(**all_cmd_args)
 
 
296
        """Actually run the command.
 
 
298
        This is invoked with the options and arguments bound to
 
 
301
        Return 0 or None if the command was successful, or a non-zero
 
 
302
        shell error code if not.  It's OK for this method to allow
 
 
303
        an exception to raise up.
 
 
305
        raise NotImplementedError()
 
 
309
        """Return help message for this class."""
 
 
310
        if self.__doc__ is Command.__doc__:
 
 
315
        return _unsquish_command_name(self.__class__.__name__)
 
 
318
def parse_spec(spec):
 
 
324
    >>> parse_spec("../@")
 
 
326
    >>> parse_spec("../f/@35")
 
 
328
    >>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
 
 
329
    ['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
 
 
334
        parsed = spec.split('/@')
 
 
335
        assert len(parsed) == 2
 
 
340
                parsed[1] = int(parsed[1])
 
 
342
                pass # We can allow stuff like ./@revid:blahblahblah
 
 
346
        parsed = [spec, None]
 
 
350
# list of all available options; the rhs can be either None for an
 
 
351
# option that takes no argument, or a constructor function that checks
 
 
364
    'revision':               _parse_revision_str,
 
 
376
    'merge-type':             get_merge_type,
 
 
390
def parse_args(argv):
 
 
391
    """Parse command line.
 
 
393
    Arguments and options are parsed at this level before being passed
 
 
394
    down to specific command handlers.  This routine knows, from a
 
 
395
    lookup table, something about the available options, what optargs
 
 
396
    they take, and which commands will accept them.
 
 
398
    >>> parse_args('--help'.split())
 
 
400
    >>> parse_args('help -- --invalidcmd'.split())
 
 
401
    (['help', '--invalidcmd'], {})
 
 
402
    >>> parse_args('--version'.split())
 
 
403
    ([], {'version': True})
 
 
404
    >>> parse_args('status --all'.split())
 
 
405
    (['status'], {'all': True})
 
 
406
    >>> parse_args('commit --message=biter'.split())
 
 
407
    (['commit'], {'message': u'biter'})
 
 
408
    >>> parse_args('log -r 500'.split())
 
 
409
    (['log'], {'revision': [<RevisionSpec_int 500>]})
 
 
410
    >>> parse_args('log -r500..600'.split())
 
 
411
    (['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
 
412
    >>> parse_args('log -vr500..600'.split())
 
 
413
    (['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
 
414
    >>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
 
 
415
    (['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
 
 
423
        if not argsover and a[0] == '-':
 
 
424
            # option names must not be unicode
 
 
429
                    # We've received a standalone -- No more flags
 
 
432
                mutter("  got option %r" % a)
 
 
434
                    optname, optarg = a[2:].split('=', 1)
 
 
437
                if optname not in OPTIONS:
 
 
438
                    raise BzrError('unknown long option %r' % a)
 
 
441
                if shortopt in SHORT_OPTIONS:
 
 
442
                    # Multi-character options must have a space to delimit
 
 
444
                    optname = SHORT_OPTIONS[shortopt]
 
 
446
                    # Single character short options, can be chained,
 
 
447
                    # and have their value appended to their name
 
 
449
                    if shortopt not in SHORT_OPTIONS:
 
 
450
                        # We didn't find the multi-character name, and we
 
 
451
                        # didn't find the single char name
 
 
452
                        raise BzrError('unknown short option %r' % a)
 
 
453
                    optname = SHORT_OPTIONS[shortopt]
 
 
456
                        # There are extra things on this option
 
 
457
                        # see if it is the value, or if it is another
 
 
459
                        optargfn = OPTIONS[optname]
 
 
461
                            # This option does not take an argument, so the
 
 
462
                            # next entry is another short option, pack it back
 
 
464
                            argv.insert(0, '-' + a[2:])
 
 
466
                            # This option takes an argument, so pack it
 
 
471
                # XXX: Do we ever want to support this, e.g. for -r?
 
 
472
                raise BzrError('repeated option %r' % a)
 
 
474
            optargfn = OPTIONS[optname]
 
 
478
                        raise BzrError('option %r needs an argument' % a)
 
 
481
                opts[optname] = optargfn(optarg)
 
 
484
                    raise BzrError('option %r takes no argument' % optname)
 
 
494
def _match_argform(cmd, takes_args, args):
 
 
497
    # step through args and takes_args, allowing appropriate 0-many matches
 
 
498
    for ap in takes_args:
 
 
502
                argdict[argname] = args.pop(0)
 
 
503
        elif ap[-1] == '*': # all remaining arguments
 
 
505
                argdict[argname + '_list'] = args[:]
 
 
508
                argdict[argname + '_list'] = None
 
 
511
                raise BzrCommandError("command %r needs one or more %s"
 
 
512
                        % (cmd, argname.upper()))
 
 
514
                argdict[argname + '_list'] = args[:]
 
 
516
        elif ap[-1] == '$': # all but one
 
 
518
                raise BzrCommandError("command %r needs one or more %s"
 
 
519
                        % (cmd, argname.upper()))
 
 
520
            argdict[argname + '_list'] = args[:-1]
 
 
526
                raise BzrCommandError("command %r requires argument %s"
 
 
527
                        % (cmd, argname.upper()))
 
 
529
                argdict[argname] = args.pop(0)
 
 
532
        raise BzrCommandError("extra argument to command %s: %s"
 
 
539
def apply_profiled(the_callable, *args, **kwargs):
 
 
542
    pffileno, pfname = tempfile.mkstemp()
 
 
544
        prof = hotshot.Profile(pfname)
 
 
546
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
 
 
551
        stats = hotshot.stats.load(pfname)
 
 
553
        stats.sort_stats('time')
 
 
554
        ## XXX: Might like to write to stderr or the trace file instead but
 
 
555
        ## print_stats seems hardcoded to stdout
 
 
556
        stats.print_stats(20)
 
 
565
    """Execute a command.
 
 
567
    This is similar to main(), but without all the trappings for
 
 
568
    logging and error handling.  
 
 
571
       The command-line arguments, without the program name from argv[0]
 
 
573
    Returns a command status or raises an exception.
 
 
575
    Special master options: these must come before the command because
 
 
576
    they control how the command is interpreted.
 
 
579
        Do not load plugin modules at all
 
 
582
        Only use builtin commands.  (Plugins are still allowed to change
 
 
586
        Run under the Python profiler.
 
 
589
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
 
 
591
    opt_profile = opt_no_plugins = opt_builtin = False
 
 
593
    # --no-plugins is handled specially at a very early stage. We need
 
 
594
    # to load plugins before doing other command parsing so that they
 
 
595
    # can override commands, but this needs to happen first.
 
 
600
        elif a == '--no-plugins':
 
 
601
            opt_no_plugins = True
 
 
602
        elif a == '--builtin':
 
 
608
    if (not argv) or (argv[0] == '--help'):
 
 
609
        from bzrlib.help import help
 
 
616
    if argv[0] == '--version':
 
 
617
        from bzrlib.builtins import show_version
 
 
621
    if not opt_no_plugins:
 
 
622
        from bzrlib.plugin import load_plugins
 
 
625
    cmd = str(argv.pop(0))
 
 
627
    cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
 
 
630
        ret = apply_profiled(cmd_obj.run_argv, argv)
 
 
632
        ret = cmd_obj.run_argv(argv)
 
 
638
    bzrlib.trace.log_startup(argv)
 
 
639
    bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
 
 
641
    return run_bzr_catch_errors(argv[1:])
 
 
644
def run_bzr_catch_errors(argv):
 
 
650
                # do this here inside the exception wrappers to catch EPIPE
 
 
652
        #wrap common errors as CommandErrors.
 
 
653
        except (NotBranchError,), e:
 
 
654
            raise BzrCommandError(str(e))
 
 
655
    except BzrCommandError, e:
 
 
656
        # command line syntax error, etc
 
 
660
        bzrlib.trace.log_exception()
 
 
662
    except AssertionError, e:
 
 
663
        bzrlib.trace.log_exception('assertion failed: ' + str(e))
 
 
665
    except KeyboardInterrupt, e:
 
 
666
        bzrlib.trace.note('interrupted')
 
 
670
        if (isinstance(e, IOError) 
 
 
671
            and hasattr(e, 'errno')
 
 
672
            and e.errno == errno.EPIPE):
 
 
673
            bzrlib.trace.note('broken pipe')
 
 
676
            bzrlib.trace.log_exception()
 
 
680
if __name__ == '__main__':
 
 
681
    sys.exit(main(sys.argv))