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(), """
38
34
from warnings import warn
51
from bzrlib.symbol_versioning import (
38
import bzrlib.errors as errors
39
from bzrlib.errors import (BzrError,
43
from bzrlib import option
58
44
from bzrlib.option import Option
46
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
48
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
78
67
if k_unsquished not in plugin_cmds:
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
132
# We want only 'ascii' command names, but the user may have typed
222
204
replace - put in a bogus character (typically '?')
223
205
exact - do not encode sys.stdout
225
NOTE: by default on Windows, sys.stdout is opened as a text
226
stream, therefore LF line-endings are converted to CRLF.
227
When a command uses encoding_type = 'exact', then
228
sys.stdout is forced to be a binary stream, and line-endings
241
217
if self.__doc__ == Command.__doc__:
242
218
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
220
def options(self):
331
221
"""Return dict of valid options for this command.
333
223
Maps from long option name to option object."""
335
r['help'] = option._help_option
225
r['help'] = Option.OPTIONS['help']
336
226
for o in self.takes_options:
337
227
if isinstance(o, basestring):
338
o = option.Option.OPTIONS[o]
228
o = Option.OPTIONS[o]
346
236
# Originally I was using self.stdout, but that looks
347
237
# *way* too much like sys.stdout
348
238
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
239
self.outf = sys.stdout
358
output_encoding = osutils.get_terminal_encoding()
242
output_encoding = bzrlib.osutils.get_terminal_encoding()
360
244
# use 'replace' so that we don't abort if trying to write out
361
245
# in e.g. the default C locale.
365
249
# bogus. So set the attribute, so we can find the correct encoding later.
366
250
self.outf.encoding = output_encoding
252
@deprecated_method(zero_eight)
253
def run_argv(self, argv):
254
"""Parse command line and run.
256
See run_argv_aliases for the 0.8 and beyond api.
258
return self.run_argv_aliases(argv)
368
260
def run_argv_aliases(self, argv, alias_argv=None):
369
261
"""Parse the command line and run with extra aliases in alias_argv."""
371
warn("Passing None for [] is deprecated from bzrlib 0.10",
263
warn("Passing None for [] is deprecated from bzrlib 0.10",
372
264
DeprecationWarning, stacklevel=2)
374
266
args, opts = parse_args(self, argv, alias_argv)
375
267
if 'help' in opts: # e.g. bzr add --help
376
sys.stdout.write(self.get_help_text())
268
from bzrlib.help import help_on_command
269
help_on_command(self.name())
378
271
# mix arguments and options into one dictionary
379
272
cmdargs = _match_argform(self.name(), self.takes_args, args)
495
385
argdict[argname + '_list'] = None
496
386
elif ap[-1] == '+':
498
raise errors.BzrCommandError("command %r needs one or more %s"
499
% (cmd, argname.upper()))
388
raise BzrCommandError("command %r needs one or more %s"
389
% (cmd, argname.upper()))
501
391
argdict[argname + '_list'] = args[:]
503
393
elif ap[-1] == '$': # all but one
504
394
if len(args) < 2:
505
raise errors.BzrCommandError("command %r needs one or more %s"
506
% (cmd, argname.upper()))
395
raise BzrCommandError("command %r needs one or more %s"
396
% (cmd, argname.upper()))
507
397
argdict[argname + '_list'] = args[:-1]
510
400
# just a plain arg
513
raise errors.BzrCommandError("command %r requires argument %s"
514
% (cmd, argname.upper()))
403
raise BzrCommandError("command %r requires argument %s"
404
% (cmd, argname.upper()))
516
406
argdict[argname] = args.pop(0)
519
raise errors.BzrCommandError("extra argument to command %s: %s"
409
raise BzrCommandError("extra argument to command %s: %s"
549
439
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
550
440
from bzrlib.lsprof import profile
551
442
ret, stats = profile(the_callable, *args, **kwargs)
553
444
if filename is None:
557
trace.note('Profile data written to "%s".', filename)
448
cPickle.dump(stats, open(filename, 'w'), 2)
449
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)
454
"""Return an expanded alias, or None if no alias exists"""
456
alias = bzrlib.config.GlobalConfig().get_alias(cmd)
577
return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
458
return alias.split(' ')
679
557
# 'command not found' error later.
681
559
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
682
run = cmd_obj.run_argv_aliases
683
run_argv = [argv, alias_argv]
560
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
561
run = cmd_obj.run_argv
564
run = cmd_obj.run_argv_aliases
565
run_argv = [argv, alias_argv]
720
602
bzrlib.ui.ui_factory = TextUIFactory()
721
603
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
722
604
ret = run_bzr_catch_errors(argv)
723
trace.mutter("return code %d", ret)
605
mutter("return code %d", ret)
727
609
def run_bzr_catch_errors(argv):
729
611
return run_bzr(argv)
612
# do this here inside the exception wrappers to catch EPIPE
730
614
except (KeyboardInterrupt, Exception), e:
731
615
# used to handle AssertionError and KeyboardInterrupt
732
616
# specially here, but hopefully they're handled ok by the logger now
733
trace.report_exception(sys.exc_info(), sys.stderr)
617
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
734
618
if os.environ.get('BZR_PDB'):
735
619
print '**** entering debugger'
737
621
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
624
if __name__ == '__main__':
765
625
sys.exit(main(sys.argv))