279
def get_help_text(self, additional_see_also=None, plain=True,
280
see_also_as_links=False):
263
def get_help_text(self, additional_see_also=None):
281
264
"""Return a text string with help for this command.
283
266
:param additional_see_also: Additional help topics to be
284
267
cross-referenced.
285
:param plain: if False, raw help (reStructuredText) is
286
returned instead of plain text.
287
:param see_also_as_links: if True, convert items in 'See also'
288
list to internal links (used by bzr_man rstx generator)
290
269
doc = self.help()
292
271
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
294
# Extract the summary (purpose) and sections out from the text
295
purpose,sections = self._get_help_parts(doc)
297
# If a custom usage section was provided, use it
298
if sections.has_key('Usage'):
299
usage = sections.pop('Usage')
301
usage = self._usage()
303
# The header is the purpose and usage
305
result += ':Purpose: %s\n' % purpose
306
if usage.find('\n') >= 0:
307
result += ':Usage:\n%s\n' % usage
309
result += ':Usage: %s\n' % usage
313
options = option.get_optparser(self.options()).format_option_help()
314
if options.startswith('Options:'):
315
result += ':' + options
316
elif options.startswith('options:'):
317
# Python 2.4 version of optparse
318
result += ':Options:' + options[len('options:'):]
323
# Add the description, indenting it 2 spaces
324
# to match the indentation of the options
325
if sections.has_key(None):
326
text = sections.pop(None)
327
text = '\n '.join(text.splitlines())
328
result += ':%s:\n %s\n\n' % ('Description',text)
330
# Add the custom sections (e.g. Examples). Note that there's no need
331
# to indent these as they must be indented already in the source.
333
labels = sorted(sections.keys())
335
result += ':%s:\n%s\n\n' % (label,sections[label])
337
# Add the aliases, source (plug-in) and see also links, if any
274
result += 'usage: %s\n' % self._usage()
339
result += ':Aliases: '
277
result += 'aliases: '
340
278
result += ', '.join(self.aliases) + '\n'
341
282
plugin_name = self.plugin_name()
342
283
if plugin_name is not None:
343
result += ':From: plugin "%s"\n' % plugin_name
284
result += '(From plugin "%s")' % plugin_name
288
if result[-1] != '\n':
291
result += option.get_optparser(self.options()).format_option_help()
344
292
see_also = self.get_see_also(additional_see_also)
346
if not plain and see_also_as_links:
348
for item in see_also:
350
# topics doesn't have an independent section
351
# so don't create a real link
352
see_also_links.append(item)
354
# Use a reST link for this entry
355
see_also_links.append("`%s`_" % (item,))
356
see_also = see_also_links
357
result += ':See also: '
358
result += ', '.join(see_also) + '\n'
360
# If this will be rendered as plan text, convert it
362
import bzrlib.help_topics
363
result = bzrlib.help_topics.help_as_plain_text(result)
294
result += '\nSee also: '
295
result += ', '.join(see_also)
367
def _get_help_parts(text):
368
"""Split help text into a summary and named sections.
370
:return: (summary,sections) where summary is the top line and
371
sections is a dictionary of the rest indexed by section name.
372
A section starts with a heading line of the form ":xxx:".
373
Indented text on following lines is the section value.
374
All text found outside a named section is assigned to the
375
default section which is given the key of None.
377
def save_section(sections, label, section):
379
if sections.has_key(label):
380
sections[label] += '\n' + section
382
sections[label] = section
384
lines = text.rstrip().splitlines()
385
summary = lines.pop(0)
387
label,section = None,''
389
if line.startswith(':') and line.endswith(':') and len(line) > 2:
390
save_section(sections, label, section)
391
label,section = line[1:-1],''
392
elif label != None and len(line) > 1 and not line[0].isspace():
393
save_section(sections, label, section)
394
label,section = None,line
397
section += '\n' + line
400
save_section(sections, label, section)
401
return summary, sections
403
299
def get_help_topic(self):
404
300
"""Return the commands help topic - its name."""
405
301
return self.name()
407
303
def get_see_also(self, additional_terms=None):
408
"""Return a list of help topics that are related to this command.
304
"""Return a list of help topics that are related to this ommand.
410
306
The list is derived from the content of the _see_also attribute. Any
411
307
duplicates are removed and the result is in lexical order.
463
358
DeprecationWarning, stacklevel=2)
465
360
args, opts = parse_args(self, argv, alias_argv)
467
# Process the standard options
468
361
if 'help' in opts: # e.g. bzr add --help
469
362
sys.stdout.write(self.get_help_text())
471
trace.set_verbosity_level(option._verbosity_level)
472
if 'verbose' in self.supported_std_options:
473
opts['verbose'] = trace.is_verbose()
474
elif opts.has_key('verbose'):
476
if 'quiet' in self.supported_std_options:
477
opts['quiet'] = trace.is_quiet()
478
elif opts.has_key('quiet'):
481
364
# mix arguments and options into one dictionary
482
365
cmdargs = _match_argform(self.name(), self.takes_args, args)
790
706
from bzrlib.ui.text import TextUIFactory
791
707
bzrlib.ui.ui_factory = TextUIFactory()
793
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
794
except UnicodeDecodeError:
795
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
708
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
797
709
ret = run_bzr_catch_errors(argv)
798
710
trace.mutter("return code %d", ret)
802
714
def run_bzr_catch_errors(argv):
803
# Note: The except clause logic below should be kept in sync with the
804
# profile() routine in lsprof.py.
719
# do this here inside the exception wrappers to catch EPIPE
807
721
except (KeyboardInterrupt, Exception), e:
808
722
# used to handle AssertionError and KeyboardInterrupt
809
723
# specially here, but hopefully they're handled ok by the logger now
810
exitcode = trace.report_exception(sys.exc_info(), sys.stderr)
724
trace.report_exception(sys.exc_info(), sys.stderr)
811
725
if os.environ.get('BZR_PDB'):
812
726
print '**** entering debugger'
814
728
pdb.post_mortem(sys.exc_traceback)
818
def run_bzr_catch_user_errors(argv):
819
"""Run bzr and report user errors, but let internal errors propagate.
821
This is used for the test suite, and might be useful for other programs
822
that want to wrap the commandline interface.
827
if (isinstance(e, (OSError, IOError))
828
or not getattr(e, 'internal_error', True)):
829
trace.report_exception(sys.exc_info(), sys.stderr)
835
732
class HelpCommandIndex(object):