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
from bzrlib.trace import mutter, note, log_error, warning
37
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
38
from bzrlib.branch import find_branch
38
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
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
def get_merge_type(typestring):
154
"""Attempt to find the merge class/factory associated with a string."""
155
from merge import merge_types
157
return merge_types[typestring][0]
159
templ = '%s%%7s: %%s' % (' '*12)
160
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
161
type_list = '\n'.join(lines)
162
msg = "No known merge type %s. Supported types are:\n%s" %\
163
(typestring, type_list)
164
raise BzrCommandError(msg)
167
82
def _builtin_commands():
168
83
import bzrlib.builtins
253
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
257
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().
260
185
If true, this command isn't advertised. This is typically
261
186
for commands intended for expert users.
266
190
takes_options = []
272
196
if self.__doc__ == Command.__doc__:
273
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]
276
211
def run_argv(self, argv):
277
212
"""Parse command line and run."""
278
args, opts = parse_args(argv)
213
args, opts = parse_args(self, argv)
280
214
if 'help' in opts: # e.g. bzr add --help
281
215
from bzrlib.help import help_on_command
282
216
help_on_command(self.name())
285
# check options are reasonable
286
allowed = self.takes_options
218
# XXX: This should be handled by the parser
219
allowed_names = self.options().keys()
287
220
for oname in opts:
288
if oname not in allowed:
221
if oname not in allowed_names:
289
222
raise BzrCommandError("option '--%s' is not allowed for command %r"
290
223
% (oname, self.name()))
292
224
# mix arguments and options into one dictionary
293
225
cmdargs = _match_argform(self.name(), self.takes_args, args)
355
286
parsed = [spec, None]
361
# list of all available options; the rhs can be either None for an
362
# option that takes no argument, or a constructor function that checks
375
'revision': _parse_revision_str,
387
'merge-type': get_merge_type,
401
def parse_args(argv):
289
def parse_args(command, argv):
402
290
"""Parse command line.
404
292
Arguments and options are parsed at this level before being passed
405
293
down to specific command handlers. This routine knows, from a
406
294
lookup table, something about the available options, what optargs
407
295
they take, and which commands will accept them.
409
>>> parse_args('--help'.split())
411
>>> parse_args('help -- --invalidcmd'.split())
412
(['help', '--invalidcmd'], {})
413
>>> parse_args('--version'.split())
414
([], {'version': True})
415
>>> parse_args('status --all'.split())
416
(['status'], {'all': True})
417
>>> parse_args('commit --message=biter'.split())
418
(['commit'], {'message': u'biter'})
419
>>> parse_args('log -r 500'.split())
420
(['log'], {'revision': [500]})
421
>>> parse_args('log -r500..600'.split())
422
(['log'], {'revision': [500, 600]})
423
>>> parse_args('log -vr500..600'.split())
424
(['log'], {'verbose': True, 'revision': [500, 600]})
425
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
426
(['log'], {'revision': ['v500', 600]})
297
# TODO: chop up this beast; make it a method of the Command
301
cmd_options = command.options()
434
if not argsover and a[0] == '-':
309
# We've received a standalone -- No more flags
435
313
# option names must not be unicode
440
# We've received a standalone -- No more flags
443
mutter(" got option %r" % a)
317
mutter(" got option %r", a)
445
319
optname, optarg = a[2:].split('=', 1)
448
if optname not in OPTIONS:
449
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()))
452
if shortopt in SHORT_OPTIONS:
327
if shortopt in Option.SHORT_OPTIONS:
453
328
# Multi-character options must have a space to delimit
455
optname = SHORT_OPTIONS[shortopt]
330
# ^^^ what does this mean? mbp 20051014
331
optname = Option.SHORT_OPTIONS[shortopt].name
457
333
# Single character short options, can be chained,
458
334
# and have their value appended to their name
459
335
shortopt = a[1:2]
460
if shortopt not in SHORT_OPTIONS:
336
if shortopt not in Option.SHORT_OPTIONS:
461
337
# We didn't find the multi-character name, and we
462
338
# didn't find the single char name
463
339
raise BzrError('unknown short option %r' % a)
464
optname = SHORT_OPTIONS[shortopt]
340
optname = Option.SHORT_OPTIONS[shortopt].name
467
343
# There are extra things on this option
468
344
# see if it is the value, or if it is another
470
optargfn = OPTIONS[optname]
346
optargfn = Option.OPTIONS[optname].type
471
347
if optargfn is None:
472
348
# This option does not take an argument, so the
473
349
# next entry is another short option, pack it back
557
435
ret = prof.runcall(the_callable, *args, **kwargs) or 0
562
438
stats = hotshot.stats.load(pfname)
564
stats.sort_stats('time')
440
stats.sort_stats('cum') # 'time'
565
441
## XXX: Might like to write to stderr or the trace file instead but
566
442
## print_stats seems hardcoded to stdout
567
443
stats.print_stats(20)
571
446
os.close(pffileno)
572
447
os.remove(pfname)
450
def apply_lsprofiled(the_callable, *args, **kwargs):
451
from bzrlib.lsprof import profile
452
ret,stats = profile(the_callable,*args,**kwargs)
575
457
def run_bzr(argv):
576
458
"""Execute a command.
638
526
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
641
ret = apply_profiled(cmd_obj.run_argv, argv)
643
ret = cmd_obj.run_argv(argv)
530
ret = apply_lsprofiled(cmd_obj.run_argv, argv)
532
ret = apply_profiled(cmd_obj.run_argv, argv)
534
ret = cmd_obj.run_argv(argv)
537
# reset, in case we may do other commands later within the same process
540
def display_command(func):
541
"""Decorator that suppresses pipe/interrupt errors."""
542
def ignore_pipe(*args, **kwargs):
544
result = func(*args, **kwargs)
548
if not hasattr(e, 'errno'):
550
if e.errno != errno.EPIPE:
553
except KeyboardInterrupt:
560
from bzrlib.ui.text import TextUIFactory
561
## bzrlib.trace.enable_default_logging()
649
562
bzrlib.trace.log_startup(argv)
650
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
563
bzrlib.ui.ui_factory = TextUIFactory()
564
ret = run_bzr_catch_errors(argv[1:])
565
mutter("return code %d", ret)
569
def run_bzr_catch_errors(argv):
654
return run_bzr(argv[1:])
656
574
# do this here inside the exception wrappers to catch EPIPE
657
575
sys.stdout.flush()
658
except BzrCommandError, e:
659
# command line syntax error, etc
663
bzrlib.trace.log_exception()
665
except AssertionError, e:
666
bzrlib.trace.log_exception('assertion failed: ' + str(e))
668
except KeyboardInterrupt, e:
669
bzrlib.trace.note('interrupted')
671
576
except Exception, e:
577
# used to handle AssertionError and KeyboardInterrupt
578
# specially here, but hopefully they're handled ok by the logger now
673
580
if (isinstance(e, IOError)
674
581
and hasattr(e, 'errno')
675
582
and e.errno == errno.EPIPE):
676
583
bzrlib.trace.note('broken pipe')
679
586
bzrlib.trace.log_exception()
587
if os.environ.get('BZR_PDB'):
588
print '**** entering debugger'
590
pdb.post_mortem(sys.exc_traceback)
683
593
if __name__ == '__main__':
684
594
sys.exit(main(sys.argv))