24
24
# Those objects can specify the expected type of the argument, which
25
25
# would help with validation and shell completion.
27
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
28
# the profile output behind so it can be interactively examined?
31
32
from warnings import warn
32
33
from inspect import getdoc
35
37
import bzrlib.trace
36
38
from bzrlib.trace import mutter, note, log_error, warning
37
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
38
from bzrlib.branch import find_branch
39
from bzrlib.errors import (BzrError,
44
from bzrlib.revisionspec import RevisionSpec
39
45
from bzrlib import BZRDIR
46
from bzrlib.option import Option
44
def register_command(cmd):
51
def register_command(cmd, decorate=False):
45
52
"Utility function to help register a command"
66
79
return cmd[4:].replace('_','-')
69
def _parse_revision_str(revstr):
70
"""This handles a revision string -> revno.
72
This always returns a list. The list will have one element for
74
It supports integers directly, but everything else it
75
defers for passing to Branch.get_revision_info()
77
>>> _parse_revision_str('234')
79
>>> _parse_revision_str('234..567')
81
>>> _parse_revision_str('..')
83
>>> _parse_revision_str('..234')
85
>>> _parse_revision_str('234..')
87
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
89
>>> _parse_revision_str('234....789') # Error?
91
>>> _parse_revision_str('revid:test@other.com-234234')
92
['revid:test@other.com-234234']
93
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
94
['revid:test@other.com-234234', 'revid:test@other.com-234235']
95
>>> _parse_revision_str('revid:test@other.com-234234..23')
96
['revid:test@other.com-234234', 23]
97
>>> _parse_revision_str('date:2005-04-12')
99
>>> _parse_revision_str('date:2005-04-12 12:24:33')
100
['date:2005-04-12 12:24:33']
101
>>> _parse_revision_str('date:2005-04-12T12:24:33')
102
['date:2005-04-12T12:24:33']
103
>>> _parse_revision_str('date:2005-04-12,12:24:33')
104
['date:2005-04-12,12:24:33']
105
>>> _parse_revision_str('-5..23')
107
>>> _parse_revision_str('-5')
109
>>> _parse_revision_str('123a')
111
>>> _parse_revision_str('abc')
115
old_format_re = re.compile('\d*:\d*')
116
m = old_format_re.match(revstr)
118
warning('Colon separator for revision numbers is deprecated.'
121
for rev in revstr.split(':'):
123
revs.append(int(rev))
128
for x in revstr.split('..'):
139
def get_merge_type(typestring):
140
"""Attempt to find the merge class/factory associated with a string."""
141
from merge import merge_types
143
return merge_types[typestring][0]
145
templ = '%s%%7s: %%s' % (' '*12)
146
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
147
type_list = '\n'.join(lines)
148
msg = "No known merge type %s. Supported types are:\n%s" %\
149
(typestring, type_list)
150
raise BzrCommandError(msg)
153
82
def _builtin_commands():
154
83
import bzrlib.builtins
239
168
List of argument forms, marked with whether they are optional,
173
['to_location', 'from_branch?', 'file*']
175
'to_location' is required
176
'from_branch' is optional
177
'file' can be specified 0 or more times
243
List of options that may be given for this command.
180
List of options that may be given for this command. These can
181
be either strings, referring to globally-defined options,
182
or option objects. Retrieve through options().
246
185
If true, this command isn't advertised. This is typically
247
186
for commands intended for expert users.
252
190
takes_options = []
258
196
if self.__doc__ == Command.__doc__:
259
197
warn("No help message set for %r" % self)
200
"""Return dict of valid options for this command.
202
Maps from long option name to option object."""
204
r['help'] = Option.OPTIONS['help']
205
for o in self.takes_options:
206
if not isinstance(o, Option):
207
o = Option.OPTIONS[o]
262
211
def run_argv(self, argv):
263
212
"""Parse command line and run."""
264
args, opts = parse_args(argv)
213
args, opts = parse_args(self, argv)
266
214
if 'help' in opts: # e.g. bzr add --help
267
215
from bzrlib.help import help_on_command
268
216
help_on_command(self.name())
271
# check options are reasonable
272
allowed = self.takes_options
218
# XXX: This should be handled by the parser
219
allowed_names = self.options().keys()
273
220
for oname in opts:
274
if oname not in allowed:
221
if oname not in allowed_names:
275
222
raise BzrCommandError("option '--%s' is not allowed for command %r"
276
223
% (oname, self.name()))
278
224
# mix arguments and options into one dictionary
279
225
cmdargs = _match_argform(self.name(), self.takes_args, args)
341
286
parsed = [spec, None]
347
# list of all available options; the rhs can be either None for an
348
# option that takes no argument, or a constructor function that checks
361
'revision': _parse_revision_str,
373
'merge-type': get_merge_type,
387
def parse_args(argv):
289
def parse_args(command, argv):
388
290
"""Parse command line.
390
292
Arguments and options are parsed at this level before being passed
391
293
down to specific command handlers. This routine knows, from a
392
294
lookup table, something about the available options, what optargs
393
295
they take, and which commands will accept them.
395
>>> parse_args('--help'.split())
397
>>> parse_args('help -- --invalidcmd'.split())
398
(['help', '--invalidcmd'], {})
399
>>> parse_args('--version'.split())
400
([], {'version': True})
401
>>> parse_args('status --all'.split())
402
(['status'], {'all': True})
403
>>> parse_args('commit --message=biter'.split())
404
(['commit'], {'message': u'biter'})
405
>>> parse_args('log -r 500'.split())
406
(['log'], {'revision': [500]})
407
>>> parse_args('log -r500..600'.split())
408
(['log'], {'revision': [500, 600]})
409
>>> parse_args('log -vr500..600'.split())
410
(['log'], {'verbose': True, 'revision': [500, 600]})
411
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
412
(['log'], {'revision': ['v500', 600]})
297
# TODO: chop up this beast; make it a method of the Command
301
cmd_options = command.options()
420
if not argsover and a[0] == '-':
309
# We've received a standalone -- No more flags
421
313
# option names must not be unicode
426
# We've received a standalone -- No more flags
429
mutter(" got option %r" % a)
317
mutter(" got option %r", a)
431
319
optname, optarg = a[2:].split('=', 1)
434
if optname not in OPTIONS:
435
raise BzrError('unknown long option %r' % a)
322
if optname not in cmd_options:
323
raise BzrOptionError('unknown long option %r for command %s'
324
% (a, command.name()))
438
if shortopt in SHORT_OPTIONS:
327
if shortopt in Option.SHORT_OPTIONS:
439
328
# Multi-character options must have a space to delimit
441
optname = SHORT_OPTIONS[shortopt]
330
# ^^^ what does this mean? mbp 20051014
331
optname = Option.SHORT_OPTIONS[shortopt].name
443
333
# Single character short options, can be chained,
444
334
# and have their value appended to their name
445
335
shortopt = a[1:2]
446
if shortopt not in SHORT_OPTIONS:
336
if shortopt not in Option.SHORT_OPTIONS:
447
337
# We didn't find the multi-character name, and we
448
338
# didn't find the single char name
449
339
raise BzrError('unknown short option %r' % a)
450
optname = SHORT_OPTIONS[shortopt]
340
optname = Option.SHORT_OPTIONS[shortopt].name
453
343
# There are extra things on this option
454
344
# see if it is the value, or if it is another
456
optargfn = OPTIONS[optname]
346
optargfn = Option.OPTIONS[optname].type
457
347
if optargfn is None:
458
348
# This option does not take an argument, so the
459
349
# next entry is another short option, pack it back
629
517
ret = cmd_obj.run_argv(argv)
520
def display_command(func):
521
"""Decorator that suppresses pipe/interrupt errors."""
522
def ignore_pipe(*args, **kwargs):
524
result = func(*args, **kwargs)
528
if not hasattr(e, 'errno'):
530
if e.errno != errno.EPIPE:
533
except KeyboardInterrupt:
635
539
bzrlib.trace.log_startup(argv)
636
540
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
542
return run_bzr_catch_errors(argv[1:])
545
def run_bzr_catch_errors(argv):
640
return run_bzr(argv[1:])
642
550
# do this here inside the exception wrappers to catch EPIPE
643
551
sys.stdout.flush()
644
except BzrCommandError, e:
645
# command line syntax error, etc
649
bzrlib.trace.log_exception()
651
except AssertionError, e:
652
bzrlib.trace.log_exception('assertion failed: ' + str(e))
654
except KeyboardInterrupt, e:
655
bzrlib.trace.note('interrupted')
657
552
except Exception, e:
553
# used to handle AssertionError and KeyboardInterrupt
554
# specially here, but hopefully they're handled ok by the logger now
659
556
if (isinstance(e, IOError)
660
557
and hasattr(e, 'errno')
661
558
and e.errno == errno.EPIPE):
662
559
bzrlib.trace.note('broken pipe')
665
562
bzrlib.trace.log_exception()
563
if os.environ.get('BZR_PDB'):
564
print '**** entering debugger'
566
pdb.post_mortem(sys.exc_traceback)
669
569
if __name__ == '__main__':
670
570
sys.exit(main(sys.argv))