126
138
If true, plugin commands can override builtins.
141
return _get_cmd_object(cmd_name, plugins_override)
143
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
146
def _get_cmd_object(cmd_name, plugins_override=True):
147
"""Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
128
148
from bzrlib.externalcommand import ExternalCommand
130
cmd_name = str(cmd_name) # not unicode
150
# We want only 'ascii' command names, but the user may have typed
151
# in a Unicode name. In that case, they should just get a
152
# 'command not found' error later.
153
# In the future, we may actually support Unicode command names.
132
155
# first look up this command under the specified name
133
156
cmds = _get_cmd_dict(plugins_override=plugins_override)
201
240
if self.__doc__ == Command.__doc__:
202
241
warn("No help message set for %r" % self)
244
"""Return single-line grammar for this command.
246
Only describes arguments, not options.
248
s = 'bzr ' + self.name() + ' '
249
for aname in self.takes_args:
250
aname = aname.upper()
251
if aname[-1] in ['$', '+']:
252
aname = aname[:-1] + '...'
253
elif aname[-1] == '?':
254
aname = '[' + aname[:-1] + ']'
255
elif aname[-1] == '*':
256
aname = '[' + aname[:-1] + '...]'
263
def get_help_text(self, additional_see_also=None):
264
"""Return a text string with help for this command.
266
:param additional_see_also: Additional help topics to be
271
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
274
result += 'usage: %s\n' % self._usage()
277
result += 'aliases:\n'
278
result += ', '.join(self.aliases) + '\n'
282
plugin_name = self.plugin_name()
283
if plugin_name is not None:
284
result += '(From plugin "%s")' % plugin_name
288
if result[-1] != '\n':
291
result += option.get_optparser(self.options()).format_option_help()
292
see_also = self.get_see_also(additional_see_also)
294
result += '\nSee also: '
295
result += ', '.join(see_also)
299
def get_help_topic(self):
300
"""Return the commands help topic - its name."""
303
def get_see_also(self, additional_terms=None):
304
"""Return a list of help topics that are related to this ommand.
306
The list is derived from the content of the _see_also attribute. Any
307
duplicates are removed and the result is in lexical order.
308
:param additional_terms: Additional help topics to cross-reference.
309
:return: A list of help topics.
311
see_also = set(getattr(self, '_see_also', []))
313
see_also.update(additional_terms)
314
return sorted(see_also)
204
316
def options(self):
205
317
"""Return dict of valid options for this command.
207
319
Maps from long option name to option object."""
209
r['help'] = Option.OPTIONS['help']
321
r['help'] = option.Option.OPTIONS['help']
210
322
for o in self.takes_options:
211
if not isinstance(o, Option):
212
o = Option.OPTIONS[o]
323
if isinstance(o, basestring):
324
o = option.Option.OPTIONS[o]
216
@deprecated_method(zero_eight)
217
def run_argv(self, argv):
218
"""Parse command line and run.
220
See run_argv_aliases for the 0.8 and beyond api.
222
return self.run_argv_aliases(argv)
328
def _setup_outf(self):
329
"""Return a file linked to stdout, which has proper encoding."""
330
assert self.encoding_type in ['strict', 'exact', 'replace']
332
# Originally I was using self.stdout, but that looks
333
# *way* too much like sys.stdout
334
if self.encoding_type == 'exact':
335
# force sys.stdout to be binary stream on win32
336
if sys.platform == 'win32':
337
fileno = getattr(sys.stdout, 'fileno', None)
340
msvcrt.setmode(fileno(), os.O_BINARY)
341
self.outf = sys.stdout
344
output_encoding = osutils.get_terminal_encoding()
346
# use 'replace' so that we don't abort if trying to write out
347
# in e.g. the default C locale.
348
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
349
# For whatever reason codecs.getwriter() does not advertise its encoding
350
# it just returns the encoding of the wrapped file, which is completely
351
# bogus. So set the attribute, so we can find the correct encoding later.
352
self.outf.encoding = output_encoding
224
354
def run_argv_aliases(self, argv, alias_argv=None):
225
355
"""Parse the command line and run with extra aliases in alias_argv."""
357
warn("Passing None for [] is deprecated from bzrlib 0.10",
358
DeprecationWarning, stacklevel=2)
226
360
args, opts = parse_args(self, argv, alias_argv)
227
361
if 'help' in opts: # e.g. bzr add --help
228
from bzrlib.help import help_on_command
229
help_on_command(self.name())
362
sys.stdout.write(self.get_help_text())
231
# XXX: This should be handled by the parser
232
allowed_names = self.options().keys()
234
if oname not in allowed_names:
235
raise BzrCommandError("option '--%s' is not allowed for"
236
" command %r" % (oname, self.name()))
237
364
# mix arguments and options into one dictionary
238
365
cmdargs = _match_argform(self.name(), self.takes_args, args)
308
451
lookup table, something about the available options, what optargs
309
452
they take, and which commands will accept them.
311
# TODO: chop up this beast; make it a method of the Command
316
cmd_options = command.options()
318
proc_aliasarg = True # Are we processing alias_argv now?
319
for proc_argv in alias_argv, argv:
326
# We've received a standalone -- No more flags
330
# option names must not be unicode
334
mutter(" got option %r", a)
336
optname, optarg = a[2:].split('=', 1)
339
if optname not in cmd_options:
340
raise BzrOptionError('unknown long option %r for'
345
if shortopt in Option.SHORT_OPTIONS:
346
# Multi-character options must have a space to delimit
348
# ^^^ what does this mean? mbp 20051014
349
optname = Option.SHORT_OPTIONS[shortopt].name
351
# Single character short options, can be chained,
352
# and have their value appended to their name
354
if shortopt not in Option.SHORT_OPTIONS:
355
# We didn't find the multi-character name, and we
356
# didn't find the single char name
357
raise BzrError('unknown short option %r' % a)
358
optname = Option.SHORT_OPTIONS[shortopt].name
361
# There are extra things on this option
362
# see if it is the value, or if it is another
364
optargfn = Option.OPTIONS[optname].type
366
# This option does not take an argument, so the
367
# next entry is another short option, pack it
369
proc_argv.insert(0, '-' + a[2:])
371
# This option takes an argument, so pack it
375
if optname not in cmd_options:
376
raise BzrOptionError('unknown short option %r for'
378
(shortopt, command.name()))
380
# XXX: Do we ever want to support this, e.g. for -r?
382
raise BzrError('repeated option %r' % a)
383
elif optname in alias_opts:
384
# Replace what's in the alias with what's in the real
386
del alias_opts[optname]
388
proc_argv.insert(0, a)
391
raise BzrError('repeated option %r' % a)
393
option_obj = cmd_options[optname]
394
optargfn = option_obj.type
398
raise BzrError('option %r needs an argument' % a)
400
optarg = proc_argv.pop(0)
401
opts[optname] = optargfn(optarg)
403
alias_opts[optname] = optargfn(optarg)
406
raise BzrError('option %r takes no argument' % optname)
409
alias_opts[optname] = True
412
proc_aliasarg = False # Done with alias argv
454
# TODO: make it a method of the Command?
455
parser = option.get_optparser(command.options())
456
if alias_argv is not None:
457
args = alias_argv + argv
461
options, args = parser.parse_args(args)
462
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
463
v is not option.OptionParser.DEFAULT_VALUE])
413
464
return args, opts
430
481
argdict[argname + '_list'] = None
431
482
elif ap[-1] == '+':
433
raise BzrCommandError("command %r needs one or more %s"
434
% (cmd, argname.upper()))
484
raise errors.BzrCommandError("command %r needs one or more %s"
485
% (cmd, argname.upper()))
436
487
argdict[argname + '_list'] = args[:]
438
489
elif ap[-1] == '$': # all but one
439
490
if len(args) < 2:
440
raise BzrCommandError("command %r needs one or more %s"
441
% (cmd, argname.upper()))
491
raise errors.BzrCommandError("command %r needs one or more %s"
492
% (cmd, argname.upper()))
442
493
argdict[argname + '_list'] = args[:-1]
445
496
# just a plain arg
448
raise BzrCommandError("command %r requires argument %s"
449
% (cmd, argname.upper()))
499
raise errors.BzrCommandError("command %r requires argument %s"
500
% (cmd, argname.upper()))
451
502
argdict[argname] = args.pop(0)
454
raise BzrCommandError("extra argument to command %s: %s"
505
raise errors.BzrCommandError("extra argument to command %s: %s"
652
720
# do this here inside the exception wrappers to catch EPIPE
653
721
sys.stdout.flush()
722
except (KeyboardInterrupt, Exception), e:
655
723
# used to handle AssertionError and KeyboardInterrupt
656
724
# specially here, but hopefully they're handled ok by the logger now
658
if (isinstance(e, IOError)
659
and hasattr(e, 'errno')
660
and e.errno == errno.EPIPE):
661
bzrlib.trace.note('broken pipe')
725
trace.report_exception(sys.exc_info(), sys.stderr)
726
if os.environ.get('BZR_PDB'):
727
print '**** entering debugger'
729
pdb.post_mortem(sys.exc_traceback)
733
class HelpCommandIndex(object):
734
"""A index for bzr help that returns commands."""
737
self.prefix = 'commands/'
739
def get_topics(self, topic):
740
"""Search for topic amongst commands.
742
:param topic: A topic to search for.
743
:return: A list which is either empty or contains a single
746
if topic and topic.startswith(self.prefix):
747
topic = topic[len(self.prefix):]
749
cmd = _get_cmd_object(topic)
664
bzrlib.trace.log_exception()
665
if os.environ.get('BZR_PDB'):
666
print '**** entering debugger'
668
pdb.post_mortem(sys.exc_traceback)
671
756
if __name__ == '__main__':
672
757
sys.exit(main(sys.argv))