247
200
"""Construct an instance of this command."""
248
201
if self.__doc__ == Command.__doc__:
249
202
warn("No help message set for %r" % self)
250
# List of standard options directly supported
251
self.supported_std_options = []
253
def _maybe_expand_globs(self, file_list):
254
"""Glob expand file_list if the platform does not do that itself.
256
:return: A possibly empty list of unicode paths.
258
Introduced in bzrlib 0.18.
262
if sys.platform == 'win32':
263
file_list = win32utils.glob_expand(file_list)
264
return list(file_list)
267
"""Return single-line grammar for this command.
269
Only describes arguments, not options.
271
s = 'bzr ' + self.name() + ' '
272
for aname in self.takes_args:
273
aname = aname.upper()
274
if aname[-1] in ['$', '+']:
275
aname = aname[:-1] + '...'
276
elif aname[-1] == '?':
277
aname = '[' + aname[:-1] + ']'
278
elif aname[-1] == '*':
279
aname = '[' + aname[:-1] + '...]'
281
s = s[:-1] # remove last space
284
def get_help_text(self, additional_see_also=None, plain=True,
285
see_also_as_links=False):
286
"""Return a text string with help for this command.
288
:param additional_see_also: Additional help topics to be
290
:param plain: if False, raw help (reStructuredText) is
291
returned instead of plain text.
292
:param see_also_as_links: if True, convert items in 'See also'
293
list to internal links (used by bzr_man rstx generator)
297
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
299
# Extract the summary (purpose) and sections out from the text
300
purpose,sections = self._get_help_parts(doc)
302
# If a custom usage section was provided, use it
303
if sections.has_key('Usage'):
304
usage = sections.pop('Usage')
306
usage = self._usage()
308
# The header is the purpose and usage
310
result += ':Purpose: %s\n' % purpose
311
if usage.find('\n') >= 0:
312
result += ':Usage:\n%s\n' % usage
314
result += ':Usage: %s\n' % usage
318
options = option.get_optparser(self.options()).format_option_help()
319
if options.startswith('Options:'):
320
result += ':' + options
321
elif options.startswith('options:'):
322
# Python 2.4 version of optparse
323
result += ':Options:' + options[len('options:'):]
328
# Add the description, indenting it 2 spaces
329
# to match the indentation of the options
330
if sections.has_key(None):
331
text = sections.pop(None)
332
text = '\n '.join(text.splitlines())
333
result += ':%s:\n %s\n\n' % ('Description',text)
335
# Add the custom sections (e.g. Examples). Note that there's no need
336
# to indent these as they must be indented already in the source.
338
labels = sorted(sections.keys())
340
result += ':%s:\n%s\n\n' % (label,sections[label])
342
# Add the aliases, source (plug-in) and see also links, if any
344
result += ':Aliases: '
345
result += ', '.join(self.aliases) + '\n'
346
plugin_name = self.plugin_name()
347
if plugin_name is not None:
348
result += ':From: plugin "%s"\n' % plugin_name
349
see_also = self.get_see_also(additional_see_also)
351
if not plain and see_also_as_links:
353
for item in see_also:
355
# topics doesn't have an independent section
356
# so don't create a real link
357
see_also_links.append(item)
359
# Use a reST link for this entry
360
see_also_links.append("`%s`_" % (item,))
361
see_also = see_also_links
362
result += ':See also: '
363
result += ', '.join(see_also) + '\n'
365
# If this will be rendered as plain text, convert it
367
import bzrlib.help_topics
368
result = bzrlib.help_topics.help_as_plain_text(result)
372
def _get_help_parts(text):
373
"""Split help text into a summary and named sections.
375
:return: (summary,sections) where summary is the top line and
376
sections is a dictionary of the rest indexed by section name.
377
A section starts with a heading line of the form ":xxx:".
378
Indented text on following lines is the section value.
379
All text found outside a named section is assigned to the
380
default section which is given the key of None.
382
def save_section(sections, label, section):
384
if sections.has_key(label):
385
sections[label] += '\n' + section
387
sections[label] = section
389
lines = text.rstrip().splitlines()
390
summary = lines.pop(0)
392
label,section = None,''
394
if line.startswith(':') and line.endswith(':') and len(line) > 2:
395
save_section(sections, label, section)
396
label,section = line[1:-1],''
397
elif (label is not None) and len(line) > 1 and not line[0].isspace():
398
save_section(sections, label, section)
399
label,section = None,line
402
section += '\n' + line
405
save_section(sections, label, section)
406
return summary, sections
408
def get_help_topic(self):
409
"""Return the commands help topic - its name."""
412
def get_see_also(self, additional_terms=None):
413
"""Return a list of help topics that are related to this command.
415
The list is derived from the content of the _see_also attribute. Any
416
duplicates are removed and the result is in lexical order.
417
:param additional_terms: Additional help topics to cross-reference.
418
:return: A list of help topics.
420
see_also = set(getattr(self, '_see_also', []))
422
see_also.update(additional_terms)
423
return sorted(see_also)
425
204
def options(self):
426
205
"""Return dict of valid options for this command.
428
207
Maps from long option name to option object."""
429
r = Option.STD_OPTIONS.copy()
209
r['help'] = Option.OPTIONS['help']
431
210
for o in self.takes_options:
432
if isinstance(o, basestring):
433
o = option.Option.OPTIONS[o]
211
if not isinstance(o, Option):
212
o = Option.OPTIONS[o]
435
if o.name in std_names:
436
self.supported_std_options.append(o.name)
439
def _setup_outf(self):
440
"""Return a file linked to stdout, which has proper encoding."""
441
# Originally I was using self.stdout, but that looks
442
# *way* too much like sys.stdout
443
if self.encoding_type == 'exact':
444
# force sys.stdout to be binary stream on win32
445
if sys.platform == 'win32':
446
fileno = getattr(sys.stdout, 'fileno', None)
449
msvcrt.setmode(fileno(), os.O_BINARY)
450
self.outf = sys.stdout
453
output_encoding = osutils.get_terminal_encoding()
455
self.outf = codecs.getwriter(output_encoding)(sys.stdout,
456
errors=self.encoding_type)
457
# For whatever reason codecs.getwriter() does not advertise its encoding
458
# it just returns the encoding of the wrapped file, which is completely
459
# bogus. So set the attribute, so we can find the correct encoding later.
460
self.outf.encoding = output_encoding
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)
462
224
def run_argv_aliases(self, argv, alias_argv=None):
463
225
"""Parse the command line and run with extra aliases in alias_argv."""
465
warn("Passing None for [] is deprecated from bzrlib 0.10",
466
DeprecationWarning, stacklevel=2)
468
226
args, opts = parse_args(self, argv, alias_argv)
470
# Process the standard options
471
227
if 'help' in opts: # e.g. bzr add --help
472
sys.stdout.write(self.get_help_text())
228
from bzrlib.help import help_on_command
229
help_on_command(self.name())
474
trace.set_verbosity_level(option._verbosity_level)
475
if 'verbose' in self.supported_std_options:
476
opts['verbose'] = trace.is_verbose()
477
elif opts.has_key('verbose'):
479
if 'quiet' in self.supported_std_options:
480
opts['quiet'] = trace.is_quiet()
481
elif opts.has_key('quiet'):
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()))
484
237
# mix arguments and options into one dictionary
485
238
cmdargs = _match_argform(self.name(), self.takes_args, args)
537
308
lookup table, something about the available options, what optargs
538
309
they take, and which commands will accept them.
540
# TODO: make it a method of the Command?
541
parser = option.get_optparser(command.options())
542
if alias_argv is not None:
543
args = alias_argv + argv
547
options, args = parser.parse_args(args)
548
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
549
v is not option.OptionParser.DEFAULT_VALUE])
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
550
413
return args, opts
567
430
argdict[argname + '_list'] = None
568
431
elif ap[-1] == '+':
570
raise errors.BzrCommandError("command %r needs one or more %s"
571
% (cmd, argname.upper()))
433
raise BzrCommandError("command %r needs one or more %s"
434
% (cmd, argname.upper()))
573
436
argdict[argname + '_list'] = args[:]
575
438
elif ap[-1] == '$': # all but one
576
439
if len(args) < 2:
577
raise errors.BzrCommandError("command %r needs one or more %s"
578
% (cmd, argname.upper()))
440
raise BzrCommandError("command %r needs one or more %s"
441
% (cmd, argname.upper()))
579
442
argdict[argname + '_list'] = args[:-1]
582
445
# just a plain arg
585
raise errors.BzrCommandError("command %r requires argument %s"
586
% (cmd, argname.upper()))
448
raise BzrCommandError("command %r requires argument %s"
449
% (cmd, argname.upper()))
588
451
argdict[argname] = args.pop(0)
591
raise errors.BzrCommandError("extra argument to command %s: %s"
454
raise BzrCommandError("extra argument to command %s: %s"
596
def apply_coveraged(dirname, the_callable, *args, **kwargs):
597
# Cannot use "import trace", as that would import bzrlib.trace instead of
598
# the standard library's trace.
599
trace = __import__('trace')
601
tracer = trace.Trace(count=1, trace=0)
602
sys.settrace(tracer.globaltrace)
604
ret = the_callable(*args, **kwargs)
607
results = tracer.results()
608
results.write_results(show_missing=1, summary=False,
612
461
def apply_profiled(the_callable, *args, **kwargs):
635
484
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
636
485
from bzrlib.lsprof import profile
637
487
ret, stats = profile(the_callable, *args, **kwargs)
639
489
if filename is None:
643
trace.note('Profile data written to "%s".', filename)
493
cPickle.dump(stats, open(filename, 'w'), 2)
494
print 'Profile data written to %r.' % filename
647
def shlex_split_unicode(unsplit):
649
return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
652
def get_alias(cmd, config=None):
653
"""Return an expanded alias, or None if no alias exists.
656
Command to be checked for an alias.
658
Used to specify an alternative config to use,
659
which is especially useful for testing.
660
If it is unspecified, the global config will be used.
664
config = bzrlib.config.GlobalConfig()
665
alias = config.get_alias(cmd)
499
"""Return an expanded alias, or None if no alias exists"""
501
alias = bzrlib.config.GlobalConfig().get_alias(cmd)
667
return shlex_split_unicode(alias)
503
return alias.split(' ')
671
507
def run_bzr(argv):
672
508
"""Execute a command.
510
This is similar to main(), but without all the trappings for
511
logging and error handling.
675
514
The command-line arguments, without the program name from argv[0]
676
These should already be decoded. All library/test code calling
677
run_bzr should be passing valid strings (don't need decoding).
679
516
Returns a command status or raises an exception.
761
590
if not opt_no_aliases:
762
591
alias_argv = get_alias(argv[0])
764
user_encoding = osutils.get_user_encoding()
765
alias_argv = [a.decode(user_encoding) for a in alias_argv]
593
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
766
594
argv[0] = alias_argv.pop(0)
769
# We want only 'ascii' command names, but the user may have typed
770
# in a Unicode name. In that case, they should just get a
771
# 'command not found' error later.
596
cmd = str(argv.pop(0))
773
598
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
774
run = cmd_obj.run_argv_aliases
775
run_argv = [argv, alias_argv]
599
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
600
run = cmd_obj.run_argv
603
run = cmd_obj.run_argv_aliases
604
run_argv = [argv, alias_argv]
778
# We can be called recursively (tests for example), but we don't want
779
# the verbosity level to propagate.
780
saved_verbosity_level = option._verbosity_level
781
option._verbosity_level = 0
785
'--coverage ignored, because --lsprof is in use.')
786
608
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
787
609
elif opt_profile:
790
'--coverage ignored, because --profile is in use.')
791
610
ret = apply_profiled(run, *run_argv)
792
elif opt_coverage_dir:
793
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
795
612
ret = run(*run_argv)
796
if 'memory' in debug.debug_flags:
797
trace.debug_memory('Process status after command:', short=False)
800
# reset, in case we may do other commands later within the same
801
# process. Commands that want to execute sub-commands must propagate
802
# --verbose in their own way.
803
option._verbosity_level = saved_verbosity_level
615
# reset, in case we may do other commands later within the same process
805
618
def display_command(func):
806
619
"""Decorator that suppresses pipe/interrupt errors."""
827
638
from bzrlib.ui.text import TextUIFactory
639
## bzrlib.trace.enable_default_logging()
640
bzrlib.trace.log_startup(argv)
828
641
bzrlib.ui.ui_factory = TextUIFactory()
830
# Is this a final release version? If so, we should suppress warnings
831
if bzrlib.version_info[3] == 'final':
832
from bzrlib import symbol_versioning
833
symbol_versioning.suppress_deprecation_warnings(override=False)
835
user_encoding = osutils.get_user_encoding()
836
argv = [a.decode(user_encoding) for a in argv[1:]]
837
except UnicodeDecodeError:
838
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
840
ret = run_bzr_catch_errors(argv)
841
trace.mutter("return code %d", ret)
642
ret = run_bzr_catch_errors(argv[1:])
643
mutter("return code %d", ret)
845
647
def run_bzr_catch_errors(argv):
846
# Note: The except clause logic below should be kept in sync with the
847
# profile() routine in lsprof.py.
850
except (KeyboardInterrupt, Exception), e:
652
# do this here inside the exception wrappers to catch EPIPE
851
655
# used to handle AssertionError and KeyboardInterrupt
852
656
# specially here, but hopefully they're handled ok by the logger now
853
exitcode = trace.report_exception(sys.exc_info(), sys.stderr)
854
if os.environ.get('BZR_PDB'):
855
print '**** entering debugger'
857
pdb.post_mortem(sys.exc_traceback)
861
def run_bzr_catch_user_errors(argv):
862
"""Run bzr and report user errors, but let internal errors propagate.
864
This is used for the test suite, and might be useful for other programs
865
that want to wrap the commandline interface.
870
if (isinstance(e, (OSError, IOError))
871
or not getattr(e, 'internal_error', True)):
872
trace.report_exception(sys.exc_info(), sys.stderr)
878
class HelpCommandIndex(object):
879
"""A index for bzr help that returns commands."""
882
self.prefix = 'commands/'
884
def get_topics(self, topic):
885
"""Search for topic amongst commands.
887
:param topic: A topic to search for.
888
:return: A list which is either empty or contains a single
891
if topic and topic.startswith(self.prefix):
892
topic = topic[len(self.prefix):]
894
cmd = _get_cmd_object(topic)
901
class Provider(object):
902
'''Generic class to be overriden by plugins'''
904
def plugin_for_command(self, cmd_name):
905
'''Takes a command and returns the information for that plugin
907
:return: A dictionary with all the available information
908
for the requested plugin
910
raise NotImplementedError
913
class ProvidersRegistry(registry.Registry):
914
'''This registry exists to allow other providers to exist'''
917
for key, provider in self.iteritems():
920
command_providers_registry = ProvidersRegistry()
658
if (isinstance(e, IOError)
659
and hasattr(e, 'errno')
660
and e.errno == errno.EPIPE):
661
bzrlib.trace.note('broken pipe')
664
bzrlib.trace.log_exception()
665
if os.environ.get('BZR_PDB'):
666
print '**** entering debugger'
668
pdb.post_mortem(sys.exc_traceback)
923
671
if __name__ == '__main__':
924
672
sys.exit(main(sys.argv))