232
252
"""Construct an instance of this command."""
233
253
if self.__doc__ == Command.__doc__:
234
254
warn("No help message set for %r" % self)
255
# List of standard options directly supported
256
self.supported_std_options = []
258
def _maybe_expand_globs(self, file_list):
259
"""Glob expand file_list if the platform does not do that itself.
261
:return: A possibly empty list of unicode paths.
263
Introduced in bzrlib 0.18.
267
if sys.platform == 'win32':
268
file_list = win32utils.glob_expand(file_list)
269
return list(file_list)
272
"""Return single-line grammar for this command.
274
Only describes arguments, not options.
276
s = 'bzr ' + self.name() + ' '
277
for aname in self.takes_args:
278
aname = aname.upper()
279
if aname[-1] in ['$', '+']:
280
aname = aname[:-1] + '...'
281
elif aname[-1] == '?':
282
aname = '[' + aname[:-1] + ']'
283
elif aname[-1] == '*':
284
aname = '[' + aname[:-1] + '...]'
291
def get_help_text(self, additional_see_also=None, plain=True,
292
see_also_as_links=False):
293
"""Return a text string with help for this command.
295
:param additional_see_also: Additional help topics to be
297
:param plain: if False, raw help (reStructuredText) is
298
returned instead of plain text.
299
:param see_also_as_links: if True, convert items in 'See also'
300
list to internal links (used by bzr_man rstx generator)
304
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
306
# Extract the summary (purpose) and sections out from the text
307
purpose,sections = self._get_help_parts(doc)
309
# If a custom usage section was provided, use it
310
if sections.has_key('Usage'):
311
usage = sections.pop('Usage')
313
usage = self._usage()
315
# The header is the purpose and usage
317
result += ':Purpose: %s\n' % purpose
318
if usage.find('\n') >= 0:
319
result += ':Usage:\n%s\n' % usage
321
result += ':Usage: %s\n' % usage
325
options = option.get_optparser(self.options()).format_option_help()
326
if options.startswith('Options:'):
327
result += ':' + options
328
elif options.startswith('options:'):
329
# Python 2.4 version of optparse
330
result += ':Options:' + options[len('options:'):]
335
# Add the description, indenting it 2 spaces
336
# to match the indentation of the options
337
if sections.has_key(None):
338
text = sections.pop(None)
339
text = '\n '.join(text.splitlines())
340
result += ':%s:\n %s\n\n' % ('Description',text)
342
# Add the custom sections (e.g. Examples). Note that there's no need
343
# to indent these as they must be indented already in the source.
345
labels = sorted(sections.keys())
347
result += ':%s:\n%s\n\n' % (label,sections[label])
349
# Add the aliases, source (plug-in) and see also links, if any
351
result += ':Aliases: '
352
result += ', '.join(self.aliases) + '\n'
353
plugin_name = self.plugin_name()
354
if plugin_name is not None:
355
result += ':From: plugin "%s"\n' % plugin_name
356
see_also = self.get_see_also(additional_see_also)
358
if not plain and see_also_as_links:
360
for item in see_also:
362
# topics doesn't have an independent section
363
# so don't create a real link
364
see_also_links.append(item)
366
# Use a reST link for this entry
367
see_also_links.append("`%s`_" % (item,))
368
see_also = see_also_links
369
result += ':See also: '
370
result += ', '.join(see_also) + '\n'
372
# If this will be rendered as plan text, convert it
374
import bzrlib.help_topics
375
result = bzrlib.help_topics.help_as_plain_text(result)
379
def _get_help_parts(text):
380
"""Split help text into a summary and named sections.
382
:return: (summary,sections) where summary is the top line and
383
sections is a dictionary of the rest indexed by section name.
384
A section starts with a heading line of the form ":xxx:".
385
Indented text on following lines is the section value.
386
All text found outside a named section is assigned to the
387
default section which is given the key of None.
389
def save_section(sections, label, section):
391
if sections.has_key(label):
392
sections[label] += '\n' + section
394
sections[label] = section
396
lines = text.rstrip().splitlines()
397
summary = lines.pop(0)
399
label,section = None,''
401
if line.startswith(':') and line.endswith(':') and len(line) > 2:
402
save_section(sections, label, section)
403
label,section = line[1:-1],''
404
elif label != None and len(line) > 1 and not line[0].isspace():
405
save_section(sections, label, section)
406
label,section = None,line
409
section += '\n' + line
412
save_section(sections, label, section)
413
return summary, sections
415
def get_help_topic(self):
416
"""Return the commands help topic - its name."""
419
def get_see_also(self, additional_terms=None):
420
"""Return a list of help topics that are related to this command.
422
The list is derived from the content of the _see_also attribute. Any
423
duplicates are removed and the result is in lexical order.
424
:param additional_terms: Additional help topics to cross-reference.
425
:return: A list of help topics.
427
see_also = set(getattr(self, '_see_also', []))
429
see_also.update(additional_terms)
430
return sorted(see_also)
236
432
def options(self):
237
433
"""Return dict of valid options for this command.
239
435
Maps from long option name to option object."""
241
r['help'] = option.Option.OPTIONS['help']
436
r = Option.STD_OPTIONS.copy()
242
438
for o in self.takes_options:
243
439
if isinstance(o, basestring):
244
440
o = option.Option.OPTIONS[o]
442
if o.name in std_names:
443
self.supported_std_options.append(o.name)
248
446
def _setup_outf(self):
596
782
# 'command not found' error later.
598
784
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
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]
785
run = cmd_obj.run_argv_aliases
786
run_argv = [argv, alias_argv]
792
'--coverage ignored, because --lsprof is in use.')
608
793
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
609
794
elif opt_profile:
797
'--coverage ignored, because --profile is in use.')
610
798
ret = apply_profiled(run, *run_argv)
799
elif opt_coverage_dir:
800
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
612
802
ret = run(*run_argv)
615
805
# reset, in case we may do other commands later within the same process
616
trace.be_quiet(False)
806
option._verbosity_level = 0
618
808
def display_command(func):
619
809
"""Decorator that suppresses pipe/interrupt errors."""
640
830
from bzrlib.ui.text import TextUIFactory
641
831
bzrlib.ui.ui_factory = TextUIFactory()
642
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
833
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
834
except UnicodeDecodeError:
835
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
643
837
ret = run_bzr_catch_errors(argv)
644
838
trace.mutter("return code %d", ret)
648
842
def run_bzr_catch_errors(argv):
843
# Note: The except clause logic below should be kept in sync with the
844
# profile() routine in lsprof.py.
650
846
return run_bzr(argv)
651
# do this here inside the exception wrappers to catch EPIPE
653
847
except (KeyboardInterrupt, Exception), e:
654
848
# used to handle AssertionError and KeyboardInterrupt
655
849
# specially here, but hopefully they're handled ok by the logger now
656
trace.report_exception(sys.exc_info(), sys.stderr)
850
exitcode = trace.report_exception(sys.exc_info(), sys.stderr)
657
851
if os.environ.get('BZR_PDB'):
658
852
print '**** entering debugger'
660
854
pdb.post_mortem(sys.exc_traceback)
858
def run_bzr_catch_user_errors(argv):
859
"""Run bzr and report user errors, but let internal errors propagate.
861
This is used for the test suite, and might be useful for other programs
862
that want to wrap the commandline interface.
867
if (isinstance(e, (OSError, IOError))
868
or not getattr(e, 'internal_error', True)):
869
trace.report_exception(sys.exc_info(), sys.stderr)
875
class HelpCommandIndex(object):
876
"""A index for bzr help that returns commands."""
879
self.prefix = 'commands/'
881
def get_topics(self, topic):
882
"""Search for topic amongst commands.
884
:param topic: A topic to search for.
885
:return: A list which is either empty or contains a single
888
if topic and topic.startswith(self.prefix):
889
topic = topic[len(self.prefix):]
891
cmd = _get_cmd_object(topic)
898
class Provider(object):
899
'''Generic class to be overriden by plugins'''
901
def plugin_for_command(self, cmd_name):
902
'''Takes a command and returns the information for that plugin
904
:return: A dictionary with all the available information
905
for the requested plugin
907
raise NotImplementedError
910
class ProvidersRegistry(registry.Registry):
911
'''This registry exists to allow other providers to exist'''
914
for key, provider in self.iteritems():
917
command_providers_registry = ProvidersRegistry()
663
920
if __name__ == '__main__':
664
921
sys.exit(main(sys.argv))