28
28
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
29
29
# the profile output behind so it can be interactively examined?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
33
from warnings import warn
38
from warnings import warn
51
from bzrlib.symbol_versioning import (
38
import bzrlib.errors as errors
39
from bzrlib.errors import (BzrError,
58
43
from bzrlib.option import Option
45
from bzrlib.revisionspec import RevisionSpec
46
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
48
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
75
64
k_unsquished = _unsquish_command_name(k)
78
if k_unsquished not in plugin_cmds:
67
if not plugin_cmds.has_key(k_unsquished):
79
68
plugin_cmds[k_unsquished] = cmd
80
## trace.mutter('registered plugin command %s', k_unsquished)
69
mutter('registered plugin command %s', k_unsquished)
81
70
if decorate and k_unsquished in builtin_command_names():
82
71
return _builtin_commands()[k_unsquished]
139
128
If true, plugin commands can override builtins.
142
return _get_cmd_object(cmd_name, plugins_override)
144
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
147
def _get_cmd_object(cmd_name, plugins_override=True):
148
"""Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
149
130
from bzrlib.externalcommand import ExternalCommand
151
# We want only 'ascii' command names, but the user may have typed
152
# in a Unicode name. In that case, they should just get a
153
# 'command not found' error later.
154
# In the future, we may actually support Unicode command names.
132
cmd_name = str(cmd_name) # not unicode
156
134
# first look up this command under the specified name
157
135
cmds = _get_cmd_dict(plugins_override=plugins_override)
241
214
if self.__doc__ == Command.__doc__:
242
215
warn("No help message set for %r" % self)
244
def _maybe_expand_globs(self, file_list):
245
"""Glob expand file_list if the platform does not do that itself.
247
:return: A possibly empty list of unicode paths.
249
Introduced in bzrlib 0.18.
253
if sys.platform == 'win32':
254
file_list = win32utils.glob_expand(file_list)
255
return list(file_list)
258
"""Return single-line grammar for this command.
260
Only describes arguments, not options.
262
s = 'bzr ' + self.name() + ' '
263
for aname in self.takes_args:
264
aname = aname.upper()
265
if aname[-1] in ['$', '+']:
266
aname = aname[:-1] + '...'
267
elif aname[-1] == '?':
268
aname = '[' + aname[:-1] + ']'
269
elif aname[-1] == '*':
270
aname = '[' + aname[:-1] + '...]'
277
def get_help_text(self, additional_see_also=None):
278
"""Return a text string with help for this command.
280
:param additional_see_also: Additional help topics to be
285
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
288
result += 'usage: %s\n' % self._usage()
291
result += 'aliases: '
292
result += ', '.join(self.aliases) + '\n'
296
plugin_name = self.plugin_name()
297
if plugin_name is not None:
298
result += '(From plugin "%s")' % plugin_name
302
if result[-1] != '\n':
305
result += option.get_optparser(self.options()).format_option_help()
306
see_also = self.get_see_also(additional_see_also)
308
result += '\nSee also: '
309
result += ', '.join(see_also)
313
def get_help_topic(self):
314
"""Return the commands help topic - its name."""
317
def get_see_also(self, additional_terms=None):
318
"""Return a list of help topics that are related to this ommand.
320
The list is derived from the content of the _see_also attribute. Any
321
duplicates are removed and the result is in lexical order.
322
:param additional_terms: Additional help topics to cross-reference.
323
:return: A list of help topics.
325
see_also = set(getattr(self, '_see_also', []))
327
see_also.update(additional_terms)
328
return sorted(see_also)
330
217
def options(self):
331
218
"""Return dict of valid options for this command.
333
220
Maps from long option name to option object."""
335
r['help'] = option._help_option
222
r['help'] = Option.OPTIONS['help']
336
223
for o in self.takes_options:
337
if isinstance(o, basestring):
338
o = option.Option.OPTIONS[o]
224
if not isinstance(o, Option):
225
o = Option.OPTIONS[o]
346
233
# Originally I was using self.stdout, but that looks
347
234
# *way* too much like sys.stdout
348
235
if self.encoding_type == 'exact':
349
# force sys.stdout to be binary stream on win32
350
if sys.platform == 'win32':
351
fileno = getattr(sys.stdout, 'fileno', None)
354
msvcrt.setmode(fileno(), os.O_BINARY)
355
236
self.outf = sys.stdout
358
output_encoding = osutils.get_terminal_encoding()
239
output_encoding = bzrlib.osutils.get_terminal_encoding()
360
241
# use 'replace' so that we don't abort if trying to write out
361
242
# in e.g. the default C locale.
365
246
# bogus. So set the attribute, so we can find the correct encoding later.
366
247
self.outf.encoding = output_encoding
249
@deprecated_method(zero_eight)
250
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)
368
257
def run_argv_aliases(self, argv, alias_argv=None):
369
258
"""Parse the command line and run with extra aliases in alias_argv."""
371
warn("Passing None for [] is deprecated from bzrlib 0.10",
372
DeprecationWarning, stacklevel=2)
374
259
args, opts = parse_args(self, argv, alias_argv)
375
260
if 'help' in opts: # e.g. bzr add --help
376
sys.stdout.write(self.get_help_text())
261
from bzrlib.help import help_on_command
262
help_on_command(self.name())
264
# XXX: This should be handled by the parser
265
allowed_names = self.options().keys()
267
if oname not in allowed_names:
268
raise BzrOptionError("option '--%s' is not allowed for"
269
" command %r" % (oname, self.name()))
378
270
# mix arguments and options into one dictionary
379
271
cmdargs = _match_argform(self.name(), self.takes_args, args)
465
354
lookup table, something about the available options, what optargs
466
355
they take, and which commands will accept them.
468
# TODO: make it a method of the Command?
469
parser = option.get_optparser(command.options())
470
if alias_argv is not None:
471
args = alias_argv + argv
475
options, args = parser.parse_args(args)
476
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
477
v is not option.OptionParser.DEFAULT_VALUE])
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
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)
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
456
proc_aliasarg = False # Done with alias argv
478
457
return args, opts
495
474
argdict[argname + '_list'] = None
496
475
elif ap[-1] == '+':
498
raise errors.BzrCommandError("command %r needs one or more %s"
499
% (cmd, argname.upper()))
477
raise BzrCommandError("command %r needs one or more %s"
478
% (cmd, argname.upper()))
501
480
argdict[argname + '_list'] = args[:]
503
482
elif ap[-1] == '$': # all but one
504
483
if len(args) < 2:
505
raise errors.BzrCommandError("command %r needs one or more %s"
506
% (cmd, argname.upper()))
484
raise BzrCommandError("command %r needs one or more %s"
485
% (cmd, argname.upper()))
507
486
argdict[argname + '_list'] = args[:-1]
510
489
# just a plain arg
513
raise errors.BzrCommandError("command %r requires argument %s"
514
% (cmd, argname.upper()))
492
raise BzrCommandError("command %r requires argument %s"
493
% (cmd, argname.upper()))
516
495
argdict[argname] = args.pop(0)
519
raise errors.BzrCommandError("extra argument to command %s: %s"
498
raise BzrCommandError("extra argument to command %s: %s"
549
528
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
550
529
from bzrlib.lsprof import profile
551
531
ret, stats = profile(the_callable, *args, **kwargs)
553
533
if filename is None:
557
trace.note('Profile data written to "%s".', filename)
537
cPickle.dump(stats, open(filename, 'w'), 2)
538
print 'Profile data written to %r.' % filename
561
def get_alias(cmd, config=None):
562
"""Return an expanded alias, or None if no alias exists.
565
Command to be checked for an alias.
567
Used to specify an alternative config to use,
568
which is especially useful for testing.
569
If it is unspecified, the global config will be used.
573
config = bzrlib.config.GlobalConfig()
574
alias = config.get_alias(cmd)
543
"""Return an expanded alias, or None if no alias exists"""
545
alias = bzrlib.config.GlobalConfig().get_alias(cmd)
577
return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
547
return alias.split(' ')
673
640
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
674
641
argv[0] = alias_argv.pop(0)
677
# We want only 'ascii' command names, but the user may have typed
678
# in a Unicode name. In that case, they should just get a
679
# 'command not found' error later.
643
cmd = str(argv.pop(0))
681
645
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
682
run = cmd_obj.run_argv_aliases
683
run_argv = [argv, alias_argv]
646
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
647
run = cmd_obj.run_argv
650
run = cmd_obj.run_argv_aliases
651
run_argv = [argv, alias_argv]
720
688
bzrlib.ui.ui_factory = TextUIFactory()
721
689
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
722
690
ret = run_bzr_catch_errors(argv)
723
trace.mutter("return code %d", ret)
691
mutter("return code %d", ret)
727
695
def run_bzr_catch_errors(argv):
729
697
return run_bzr(argv)
730
except (KeyboardInterrupt, Exception), e:
698
# do this here inside the exception wrappers to catch EPIPE
731
701
# used to handle AssertionError and KeyboardInterrupt
732
702
# specially here, but hopefully they're handled ok by the logger now
733
trace.report_exception(sys.exc_info(), sys.stderr)
703
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
734
704
if os.environ.get('BZR_PDB'):
735
705
print '**** entering debugger'
737
707
pdb.post_mortem(sys.exc_traceback)
741
class HelpCommandIndex(object):
742
"""A index for bzr help that returns commands."""
745
self.prefix = 'commands/'
747
def get_topics(self, topic):
748
"""Search for topic amongst commands.
750
:param topic: A topic to search for.
751
:return: A list which is either empty or contains a single
754
if topic and topic.startswith(self.prefix):
755
topic = topic[len(self.prefix):]
757
cmd = _get_cmd_object(topic)
764
710
if __name__ == '__main__':
765
711
sys.exit(main(sys.argv))