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
37
from bzrlib.config import GlobalConfig
35
38
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
39
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
40
from bzrlib.errors import (BzrError,
47
from bzrlib.revisionspec import RevisionSpec
39
48
from bzrlib import BZRDIR
49
from bzrlib.option import Option
44
def register_command(cmd):
54
def register_command(cmd, decorate=False):
45
55
"Utility function to help register a command"
66
82
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
85
def _builtin_commands():
154
86
import bzrlib.builtins
239
171
List of argument forms, marked with whether they are optional,
176
['to_location', 'from_branch?', 'file*']
178
'to_location' is required
179
'from_branch' is optional
180
'file' can be specified 0 or more times
243
List of options that may be given for this command.
183
List of options that may be given for this command. These can
184
be either strings, referring to globally-defined options,
185
or option objects. Retrieve through options().
246
188
If true, this command isn't advertised. This is typically
247
189
for commands intended for expert users.
252
193
takes_options = []
258
199
if self.__doc__ == Command.__doc__:
259
200
warn("No help message set for %r" % self)
262
def run_argv(self, argv):
203
"""Return dict of valid options for this command.
205
Maps from long option name to option object."""
207
r['help'] = Option.OPTIONS['help']
208
for o in self.takes_options:
209
if not isinstance(o, Option):
210
o = Option.OPTIONS[o]
214
def run_argv(self, argv, defaults=None):
263
215
"""Parse command line and run."""
264
args, opts = parse_args(argv)
216
if defaults is not None:
217
args, opts = parse_args(self, defaults)
221
cmd_args, cmd_opts = parse_args(self, argv)
222
args.extend(cmd_args)
223
opts.update(cmd_opts)
266
224
if 'help' in opts: # e.g. bzr add --help
267
225
from bzrlib.help import help_on_command
268
226
help_on_command(self.name())
271
# check options are reasonable
272
allowed = self.takes_options
228
# XXX: This should be handled by the parser
229
allowed_names = self.options().keys()
273
230
for oname in opts:
274
if oname not in allowed:
231
if oname not in allowed_names:
275
232
raise BzrCommandError("option '--%s' is not allowed for command %r"
276
233
% (oname, self.name()))
278
234
# mix arguments and options into one dictionary
279
235
cmdargs = _match_argform(self.name(), self.takes_args, args)
341
296
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):
299
def parse_args(command, argv):
388
300
"""Parse command line.
390
302
Arguments and options are parsed at this level before being passed
391
303
down to specific command handlers. This routine knows, from a
392
304
lookup table, something about the available options, what optargs
393
305
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]})
307
# TODO: chop up this beast; make it a method of the Command
311
cmd_options = command.options()
420
if not argsover and a[0] == '-':
319
# We've received a standalone -- No more flags
421
323
# option names must not be unicode
426
# We've received a standalone -- No more flags
429
mutter(" got option %r" % a)
327
mutter(" got option %r", a)
431
329
optname, optarg = a[2:].split('=', 1)
434
if optname not in OPTIONS:
435
raise BzrError('unknown long option %r' % a)
332
if optname not in cmd_options:
333
raise BzrOptionError('unknown long option %r for command %s'
334
% (a, command.name()))
438
if shortopt in SHORT_OPTIONS:
337
if shortopt in Option.SHORT_OPTIONS:
439
338
# Multi-character options must have a space to delimit
441
optname = SHORT_OPTIONS[shortopt]
340
# ^^^ what does this mean? mbp 20051014
341
optname = Option.SHORT_OPTIONS[shortopt].name
443
343
# Single character short options, can be chained,
444
344
# and have their value appended to their name
445
345
shortopt = a[1:2]
446
if shortopt not in SHORT_OPTIONS:
346
if shortopt not in Option.SHORT_OPTIONS:
447
347
# We didn't find the multi-character name, and we
448
348
# didn't find the single char name
449
349
raise BzrError('unknown short option %r' % a)
450
optname = SHORT_OPTIONS[shortopt]
350
optname = Option.SHORT_OPTIONS[shortopt].name
453
353
# There are extra things on this option
454
354
# see if it is the value, or if it is another
456
optargfn = OPTIONS[optname]
356
optargfn = Option.OPTIONS[optname].type
457
357
if optargfn is None:
458
358
# This option does not take an argument, so the
459
359
# next entry is another short option, pack it back
543
445
ret = prof.runcall(the_callable, *args, **kwargs) or 0
548
448
stats = hotshot.stats.load(pfname)
550
stats.sort_stats('time')
450
stats.sort_stats('cum') # 'time'
551
451
## XXX: Might like to write to stderr or the trace file instead but
552
452
## print_stats seems hardcoded to stdout
553
453
stats.print_stats(20)
557
456
os.close(pffileno)
558
457
os.remove(pfname)
460
def apply_lsprofiled(the_callable, *args, **kwargs):
461
from bzrlib.lsprof import profile
462
ret,stats = profile(the_callable,*args,**kwargs)
561
467
def run_bzr(argv):
562
468
"""Execute a command.
580
486
other behaviour.)
583
Run under the Python profiler.
489
Run under the Python hotshot profiler.
492
Run under the Python lsprof profiler.
586
494
argv = [a.decode(bzrlib.user_encoding) for a in argv]
588
opt_profile = opt_no_plugins = opt_builtin = False
496
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = False
497
opt_no_defaults = False
590
499
# --no-plugins is handled specially at a very early stage. We need
591
500
# to load plugins before doing other command parsing so that they
592
501
# can override commands, but this needs to happen first.
595
504
if a == '--profile':
596
505
opt_profile = True
506
elif a == '--lsprof':
597
508
elif a == '--no-plugins':
598
509
opt_no_plugins = True
599
510
elif a == '--builtin':
600
511
opt_builtin = True
512
elif a in ('--quiet', '-q'):
514
elif a in ('--no-defaults',):
515
opt_no_defaults = True
605
520
if (not argv) or (argv[0] == '--help'):
618
533
if not opt_no_plugins:
619
534
from bzrlib.plugin import load_plugins
537
from bzrlib.plugin import disable_plugins
622
540
cmd = str(argv.pop(0))
624
542
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
627
ret = apply_profiled(cmd_obj.run_argv, argv)
543
if opt_no_defaults is True:
629
ret = cmd_obj.run_argv(argv)
546
cmd_defaults = GlobalConfig().get_command_defaults(cmd_obj.name())
549
ret = apply_lsprofiled(cmd_obj.run_argv, argv, cmd_defaults)
551
ret = apply_profiled(cmd_obj.run_argv, argv, cmd_defaults)
553
ret = cmd_obj.run_argv(argv, cmd_defaults)
556
# reset, in case we may do other commands later within the same process
559
def display_command(func):
560
"""Decorator that suppresses pipe/interrupt errors."""
561
def ignore_pipe(*args, **kwargs):
563
result = func(*args, **kwargs)
567
if not hasattr(e, 'errno'):
569
if e.errno != errno.EPIPE:
572
except KeyboardInterrupt:
579
from bzrlib.ui.text import TextUIFactory
580
## bzrlib.trace.enable_default_logging()
635
581
bzrlib.trace.log_startup(argv)
636
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
582
bzrlib.ui.ui_factory = TextUIFactory()
583
ret = run_bzr_catch_errors(argv[1:])
584
mutter("return code %d", ret)
588
def run_bzr_catch_errors(argv):
640
return run_bzr(argv[1:])
642
593
# do this here inside the exception wrappers to catch EPIPE
643
594
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
595
except Exception, e:
596
# used to handle AssertionError and KeyboardInterrupt
597
# specially here, but hopefully they're handled ok by the logger now
659
599
if (isinstance(e, IOError)
660
600
and hasattr(e, 'errno')
661
601
and e.errno == errno.EPIPE):
662
602
bzrlib.trace.note('broken pipe')
665
605
bzrlib.trace.log_exception()
606
if os.environ.get('BZR_PDB'):
607
print '**** entering debugger'
609
pdb.post_mortem(sys.exc_traceback)
669
612
if __name__ == '__main__':
670
613
sys.exit(main(sys.argv))