18
18
# TODO: probably should say which arguments are candidates for glob
19
19
# expansion on windows and do that at the command level.
21
# TODO: Help messages for options.
21
23
# TODO: Define arguments by objects, rather than just using names.
22
24
# Those objects can specify the expected type of the argument, which
23
# would help with validation and shell completion. They could also provide
24
# help/explanation for that argument in a structured way.
26
# TODO: Specific "examples" property on commands for consistent formatting.
28
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
29
# the profile output behind so it can be interactively examined?
25
# would help with validation and shell completion.
33
31
from warnings import warn
32
from inspect import getdoc
38
import bzrlib.errors as errors
39
from bzrlib.errors import (BzrError,
43
from bzrlib.option import Option
45
from bzrlib.revisionspec import RevisionSpec
46
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
47
35
import bzrlib.trace
48
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
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 import BZRDIR
53
def register_command(cmd, decorate=False):
54
"""Utility function to help register a command
56
:param cmd: Command subclass to register
57
:param decorate: If true, allow overriding an existing command
58
of the same name; the old command is returned by this function.
59
Otherwise it is an error to try to override an existing command.
44
def register_command(cmd):
45
"Utility function to help register a command"
63
48
if k.startswith("cmd_"):
87
66
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)
90
153
def _builtin_commands():
91
154
import bzrlib.builtins
93
156
builtins = bzrlib.builtins.__dict__
94
157
for name in builtins:
95
158
if name.startswith("cmd_"):
96
real_name = _unsquish_command_name(name)
159
real_name = _unsquish_command_name(name)
97
160
r[real_name] = builtins[name]
101
165
def builtin_command_names():
175
239
List of argument forms, marked with whether they are optional,
180
['to_location', 'from_branch?', 'file*']
182
'to_location' is required
183
'from_branch' is optional
184
'file' can be specified 0 or more times
187
List of options that may be given for this command. These can
188
be either strings, referring to globally-defined options,
189
or option objects. Retrieve through options().
243
List of options that may be given for this command.
192
246
If true, this command isn't advertised. This is typically
193
247
for commands intended for expert users.
196
Command objects will get a 'outf' attribute, which has been
197
setup to properly handle encoding of unicode strings.
198
encoding_type determines what will happen when characters cannot
200
strict - abort if we cannot decode
201
replace - put in a bogus character (typically '?')
202
exact - do not encode sys.stdout
207
252
takes_options = []
208
encoding_type = 'strict'
214
258
if self.__doc__ == Command.__doc__:
215
259
warn("No help message set for %r" % self)
218
"""Return dict of valid options for this command.
220
Maps from long option name to option object."""
222
r['help'] = Option.OPTIONS['help']
223
for o in self.takes_options:
224
if not isinstance(o, Option):
225
o = Option.OPTIONS[o]
229
def _setup_outf(self):
230
"""Return a file linked to stdout, which has proper encoding."""
231
assert self.encoding_type in ['strict', 'exact', 'replace']
233
# Originally I was using self.stdout, but that looks
234
# *way* too much like sys.stdout
235
if self.encoding_type == 'exact':
236
self.outf = sys.stdout
239
output_encoding = bzrlib.osutils.get_terminal_encoding()
241
# use 'replace' so that we don't abort if trying to write out
242
# in e.g. the default C locale.
243
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
244
# For whatever reason codecs.getwriter() does not advertise its encoding
245
# it just returns the encoding of the wrapped file, which is completely
246
# bogus. So set the attribute, so we can find the correct encoding later.
247
self.outf.encoding = output_encoding
249
@deprecated_method(zero_eight)
250
262
def run_argv(self, argv):
251
"""Parse command line and run.
253
See run_argv_aliases for the 0.8 and beyond api.
255
return self.run_argv_aliases(argv)
263
"""Parse command line and run."""
264
args, opts = parse_args(argv)
257
def run_argv_aliases(self, argv, alias_argv=None):
258
"""Parse the command line and run with extra aliases in alias_argv."""
259
args, opts = parse_args(self, argv, alias_argv)
260
266
if 'help' in opts: # e.g. bzr add --help
261
267
from bzrlib.help import help_on_command
262
268
help_on_command(self.name())
264
# XXX: This should be handled by the parser
265
allowed_names = self.options().keys()
271
# check options are reasonable
272
allowed = self.takes_options
266
273
for oname in opts:
267
if oname not in allowed_names:
268
raise BzrOptionError("option '--%s' is not allowed for"
269
" command %r" % (oname, self.name()))
274
if oname not in allowed:
275
raise BzrCommandError("option '--%s' is not allowed for command %r"
276
% (oname, self.name()))
270
278
# mix arguments and options into one dictionary
271
279
cmdargs = _match_argform(self.name(), self.takes_args, args)
346
341
parsed = [spec, None]
349
def parse_args(command, argv, alias_argv=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):
350
388
"""Parse command line.
352
390
Arguments and options are parsed at this level before being passed
353
391
down to specific command handlers. This routine knows, from a
354
392
lookup table, something about the available options, what optargs
355
393
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]})
357
# TODO: chop up this beast; make it a method of the Command
362
cmd_options = command.options()
364
proc_aliasarg = True # Are we processing alias_argv now?
365
for proc_argv in alias_argv, argv:
375
# We've received a standalone -- No more flags
379
# option names must not be unicode
383
mutter(" got option %r", a)
385
optname, optarg = a[2:].split('=', 1)
388
if optname not in cmd_options:
389
raise BzrCommandError('unknown option "%s"' % a)
392
if shortopt in Option.SHORT_OPTIONS:
393
# Multi-character options must have a space to delimit
395
# ^^^ what does this mean? mbp 20051014
396
optname = Option.SHORT_OPTIONS[shortopt].name
398
# Single character short options, can be chained,
399
# and have their value appended to their name
401
if shortopt not in Option.SHORT_OPTIONS:
402
# We didn't find the multi-character name, and we
403
# didn't find the single char name
404
raise BzrCommandError('unknown option "%s"' % a)
405
optname = Option.SHORT_OPTIONS[shortopt].name
420
if not argsover and a[0] == '-':
421
# option names must not be unicode
426
# We've received a standalone -- No more flags
429
mutter(" got option %r" % a)
431
optname, optarg = a[2:].split('=', 1)
434
if optname not in OPTIONS:
435
raise BzrError('unknown long option %r' % a)
438
if shortopt in SHORT_OPTIONS:
439
# Multi-character options must have a space to delimit
441
optname = SHORT_OPTIONS[shortopt]
443
# Single character short options, can be chained,
444
# and have their value appended to their name
446
if shortopt not in SHORT_OPTIONS:
447
# We didn't find the multi-character name, and we
448
# didn't find the single char name
449
raise BzrError('unknown short option %r' % a)
450
optname = SHORT_OPTIONS[shortopt]
408
# There are extra things on this option
409
# see if it is the value, or if it is another
411
optargfn = Option.OPTIONS[optname].type
413
# This option does not take an argument, so the
414
# next entry is another short option, pack it
416
proc_argv.insert(0, '-' + a[2:])
418
# This option takes an argument, so pack it
421
if optname not in cmd_options:
422
raise BzrCommandError('unknown option "%s"' % shortopt)
424
# XXX: Do we ever want to support this, e.g. for -r?
426
raise BzrCommandError('repeated option %r' % a)
427
elif optname in alias_opts:
428
# Replace what's in the alias with what's in the real
430
del alias_opts[optname]
432
proc_argv.insert(0, a)
435
raise BzrCommandError('repeated option %r' % a)
437
option_obj = cmd_options[optname]
438
optargfn = option_obj.type
442
raise BzrCommandError('option %r needs an argument' % a)
453
# There are extra things on this option
454
# see if it is the value, or if it is another
456
optargfn = OPTIONS[optname]
458
# This option does not take an argument, so the
459
# next entry is another short option, pack it back
461
argv.insert(0, '-' + a[2:])
444
optarg = proc_argv.pop(0)
445
opts[optname] = optargfn(optarg)
447
alias_opts[optname] = optargfn(optarg)
450
raise BzrCommandError('option %r takes no argument' % optname)
453
alias_opts[optname] = True
463
# This option takes an argument, so pack it
468
# XXX: Do we ever want to support this, e.g. for -r?
469
raise BzrError('repeated option %r' % a)
471
optargfn = OPTIONS[optname]
475
raise BzrError('option %r needs an argument' % a)
478
opts[optname] = optargfn(optarg)
456
proc_aliasarg = False # Done with alias argv
481
raise BzrError('option %r takes no argument' % optname)
457
486
return args, opts
460
491
def _match_argform(cmd, takes_args, args):
568
576
Do not load plugin modules at all
574
579
Only use builtin commands. (Plugins are still allowed to change
575
580
other behaviour.)
578
Run under the Python hotshot profiler.
581
Run under the Python lsprof profiler.
583
Run under the Python profiler.
586
argv = [a.decode(bzrlib.user_encoding) for a in argv]
585
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
586
opt_no_aliases = False
587
opt_lsprof_file = None
588
opt_profile = opt_no_plugins = opt_builtin = False
589
590
# --no-plugins is handled specially at a very early stage. We need
590
591
# to load plugins before doing other command parsing so that they
591
592
# can override commands, but this needs to happen first.
597
595
if a == '--profile':
598
596
opt_profile = True
599
elif a == '--lsprof':
601
elif a == '--lsprof-file':
603
opt_lsprof_file = argv[i + 1]
605
597
elif a == '--no-plugins':
606
598
opt_no_plugins = True
607
elif a == '--no-aliases':
608
opt_no_aliases = True
609
599
elif a == '--builtin':
610
600
opt_builtin = True
611
elif a in ('--quiet', '-q'):
619
from bzrlib.builtins import cmd_help
620
cmd_help().run_argv_aliases([])
605
if (not argv) or (argv[0] == '--help'):
606
from bzrlib.help import help
623
613
if argv[0] == '--version':
628
618
if not opt_no_plugins:
629
619
from bzrlib.plugin import load_plugins
632
from bzrlib.plugin import disable_plugins
637
if not opt_no_aliases:
638
alias_argv = get_alias(argv[0])
640
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
641
argv[0] = alias_argv.pop(0)
643
622
cmd = str(argv.pop(0))
645
624
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
646
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
647
run = cmd_obj.run_argv
627
ret = apply_profiled(cmd_obj.run_argv, argv)
650
run = cmd_obj.run_argv_aliases
651
run_argv = [argv, alias_argv]
655
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
657
ret = apply_profiled(run, *run_argv)
662
# reset, in case we may do other commands later within the same process
665
def display_command(func):
666
"""Decorator that suppresses pipe/interrupt errors."""
667
def ignore_pipe(*args, **kwargs):
669
result = func(*args, **kwargs)
673
if not hasattr(e, 'errno'):
675
if e.errno != errno.EPIPE:
676
# Win32 raises IOError with errno=0 on a broken pipe
677
if sys.platform != 'win32' or e.errno != 0:
680
except KeyboardInterrupt:
629
ret = cmd_obj.run_argv(argv)
687
from bzrlib.ui.text import TextUIFactory
688
bzrlib.ui.ui_factory = TextUIFactory()
689
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
690
ret = run_bzr_catch_errors(argv)
691
mutter("return code %d", ret)
695
def run_bzr_catch_errors(argv):
635
bzrlib.trace.log_startup(argv)
636
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
698
# do this here inside the exception wrappers to catch EPIPE
640
return run_bzr(argv[1:])
642
# do this here inside the exception wrappers to catch EPIPE
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')
700
657
except Exception, e:
701
# used to handle AssertionError and KeyboardInterrupt
702
# specially here, but hopefully they're handled ok by the logger now
703
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
704
if os.environ.get('BZR_PDB'):
705
print '**** entering debugger'
707
pdb.post_mortem(sys.exc_traceback)
659
if (isinstance(e, IOError)
660
and hasattr(e, 'errno')
661
and e.errno == errno.EPIPE):
662
bzrlib.trace.note('broken pipe')
665
bzrlib.trace.log_exception()
710
669
if __name__ == '__main__':
711
670
sys.exit(main(sys.argv))