1
# Copyright (C) 2006, 2008 Canonical Ltd
1
# Copyright (C) 2004, 2005 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
# TODO: probably should say which arguments are candidates for glob
19
19
# expansion on windows and do that at the command level.
21
# TODO: Help messages for options.
21
23
# TODO: Define arguments by objects, rather than just using names.
22
24
# Those objects can specify the expected type of the argument, which
23
# would help with validation and shell completion. They could also provide
24
# help/explanation for that argument in a structured way.
26
# TODO: Specific "examples" property on commands for consistent formatting.
25
# would help with validation and shell completion.
28
27
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
29
28
# the profile output behind so it can be interactively examined?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
32
from warnings import warn
33
from inspect import getdoc
39
from warnings import warn
52
from bzrlib import registry
54
from bzrlib.hooks import HookPoint, Hooks
38
from bzrlib.trace import mutter, note, log_error, warning
39
from bzrlib.errors import (BzrError,
44
from bzrlib.revisionspec import RevisionSpec
45
from bzrlib import BZRDIR
55
46
from bzrlib.option import Option
58
class CommandInfo(object):
59
"""Information about a command."""
61
def __init__(self, aliases):
62
"""The list of aliases for the command."""
63
self.aliases = aliases
66
def from_command(klass, command):
67
"""Factory to construct a CommandInfo from a command."""
68
return klass(command.aliases)
71
class CommandRegistry(registry.Registry):
74
def _get_name(command_name):
75
if command_name.startswith("cmd_"):
76
return _unsquish_command_name(command_name)
80
def register(self, cmd, decorate=False):
81
"""Utility function to help register a command
83
:param cmd: Command subclass to register
84
:param decorate: If true, allow overriding an existing command
85
of the same name; the old command is returned by this function.
86
Otherwise it is an error to try to override an existing command.
89
k_unsquished = self._get_name(k)
91
previous = self.get(k_unsquished)
93
previous = _builtin_commands().get(k_unsquished)
94
info = CommandInfo.from_command(cmd)
96
registry.Registry.register(self, k_unsquished, cmd,
97
override_existing=decorate, info=info)
99
trace.log_error('Two plugins defined the same command: %r' % k)
100
trace.log_error('Not loading the one in %r' %
101
sys.modules[cmd.__module__])
102
trace.log_error('Previously this command was registered from %r' %
103
sys.modules[previous.__module__])
106
def register_lazy(self, command_name, aliases, module_name):
107
"""Register a command without loading its module.
109
:param command_name: The primary name of the command.
110
:param aliases: A list of aliases for the command.
111
:module_name: The module that the command lives in.
113
key = self._get_name(command_name)
114
registry.Registry.register_lazy(self, key, module_name, command_name,
115
info=CommandInfo(aliases))
118
plugin_cmds = CommandRegistry()
121
51
def register_command(cmd, decorate=False):
52
"Utility function to help register a command"
122
53
global plugin_cmds
123
return plugin_cmds.register(cmd, decorate)
55
if k.startswith("cmd_"):
56
k_unsquished = _unsquish_command_name(k)
59
if not plugin_cmds.has_key(k_unsquished):
60
plugin_cmds[k_unsquished] = cmd
61
mutter('registered plugin command %s', k_unsquished)
62
if decorate and k_unsquished in builtin_command_names():
63
return _builtin_commands()[k_unsquished]
65
result = plugin_cmds[k_unsquished]
66
plugin_cmds[k_unsquished] = cmd
69
log_error('Two plugins defined the same command: %r' % k)
70
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
126
73
def _squish_command_name(cmd):
269
177
If true, this command isn't advertised. This is typically
270
178
for commands intended for expert users.
273
Command objects will get a 'outf' attribute, which has been
274
setup to properly handle encoding of unicode strings.
275
encoding_type determines what will happen when characters cannot
277
strict - abort if we cannot decode
278
replace - put in a bogus character (typically '?')
279
exact - do not encode sys.stdout
281
NOTE: by default on Windows, sys.stdout is opened as a text
282
stream, therefore LF line-endings are converted to CRLF.
283
When a command uses encoding_type = 'exact', then
284
sys.stdout is forced to be a binary stream, and line-endings
287
:cvar hooks: An instance of CommandHooks.
291
182
takes_options = []
292
encoding_type = 'strict'
296
186
def __init__(self):
297
187
"""Construct an instance of this command."""
298
188
if self.__doc__ == Command.__doc__:
299
189
warn("No help message set for %r" % self)
300
# List of standard options directly supported
301
self.supported_std_options = []
303
def _maybe_expand_globs(self, file_list):
304
"""Glob expand file_list if the platform does not do that itself.
306
:return: A possibly empty list of unicode paths.
308
Introduced in bzrlib 0.18.
312
if sys.platform == 'win32':
313
file_list = win32utils.glob_expand(file_list)
314
return list(file_list)
317
"""Return single-line grammar for this command.
319
Only describes arguments, not options.
321
s = 'bzr ' + self.name() + ' '
322
for aname in self.takes_args:
323
aname = aname.upper()
324
if aname[-1] in ['$', '+']:
325
aname = aname[:-1] + '...'
326
elif aname[-1] == '?':
327
aname = '[' + aname[:-1] + ']'
328
elif aname[-1] == '*':
329
aname = '[' + aname[:-1] + '...]'
331
s = s[:-1] # remove last space
334
def get_help_text(self, additional_see_also=None, plain=True,
335
see_also_as_links=False, verbose=True):
336
"""Return a text string with help for this command.
338
:param additional_see_also: Additional help topics to be
340
:param plain: if False, raw help (reStructuredText) is
341
returned instead of plain text.
342
:param see_also_as_links: if True, convert items in 'See also'
343
list to internal links (used by bzr_man rstx generator)
344
:param verbose: if True, display the full help, otherwise
345
leave out the descriptive sections and just display
346
usage help (e.g. Purpose, Usage, Options) with a
347
message explaining how to obtain full help.
351
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
353
# Extract the summary (purpose) and sections out from the text
354
purpose,sections,order = self._get_help_parts(doc)
356
# If a custom usage section was provided, use it
357
if sections.has_key('Usage'):
358
usage = sections.pop('Usage')
360
usage = self._usage()
362
# The header is the purpose and usage
364
result += ':Purpose: %s\n' % purpose
365
if usage.find('\n') >= 0:
366
result += ':Usage:\n%s\n' % usage
368
result += ':Usage: %s\n' % usage
372
options = option.get_optparser(self.options()).format_option_help()
373
if options.startswith('Options:'):
374
result += ':' + options
375
elif options.startswith('options:'):
376
# Python 2.4 version of optparse
377
result += ':Options:' + options[len('options:'):]
383
# Add the description, indenting it 2 spaces
384
# to match the indentation of the options
385
if sections.has_key(None):
386
text = sections.pop(None)
387
text = '\n '.join(text.splitlines())
388
result += ':%s:\n %s\n\n' % ('Description',text)
390
# Add the custom sections (e.g. Examples). Note that there's no need
391
# to indent these as they must be indented already in the source.
394
if sections.has_key(label):
395
result += ':%s:\n%s\n' % (label,sections[label])
398
result += ("See bzr help %s for more details and examples.\n\n"
401
# Add the aliases, source (plug-in) and see also links, if any
403
result += ':Aliases: '
404
result += ', '.join(self.aliases) + '\n'
405
plugin_name = self.plugin_name()
406
if plugin_name is not None:
407
result += ':From: plugin "%s"\n' % plugin_name
408
see_also = self.get_see_also(additional_see_also)
410
if not plain and see_also_as_links:
412
for item in see_also:
414
# topics doesn't have an independent section
415
# so don't create a real link
416
see_also_links.append(item)
418
# Use a reST link for this entry
419
see_also_links.append("`%s`_" % (item,))
420
see_also = see_also_links
421
result += ':See also: '
422
result += ', '.join(see_also) + '\n'
424
# If this will be rendered as plain text, convert it
426
import bzrlib.help_topics
427
result = bzrlib.help_topics.help_as_plain_text(result)
431
def _get_help_parts(text):
432
"""Split help text into a summary and named sections.
434
:return: (summary,sections,order) where summary is the top line and
435
sections is a dictionary of the rest indexed by section name.
436
order is the order the section appear in the text.
437
A section starts with a heading line of the form ":xxx:".
438
Indented text on following lines is the section value.
439
All text found outside a named section is assigned to the
440
default section which is given the key of None.
442
def save_section(sections, order, label, section):
444
if sections.has_key(label):
445
sections[label] += '\n' + section
448
sections[label] = section
450
lines = text.rstrip().splitlines()
451
summary = lines.pop(0)
454
label,section = None,''
456
if line.startswith(':') and line.endswith(':') and len(line) > 2:
457
save_section(sections, order, label, section)
458
label,section = line[1:-1],''
459
elif (label is not None) and len(line) > 1 and not line[0].isspace():
460
save_section(sections, order, label, section)
461
label,section = None,line
464
section += '\n' + line
467
save_section(sections, order, label, section)
468
return summary, sections, order
470
def get_help_topic(self):
471
"""Return the commands help topic - its name."""
474
def get_see_also(self, additional_terms=None):
475
"""Return a list of help topics that are related to this command.
477
The list is derived from the content of the _see_also attribute. Any
478
duplicates are removed and the result is in lexical order.
479
:param additional_terms: Additional help topics to cross-reference.
480
:return: A list of help topics.
482
see_also = set(getattr(self, '_see_also', []))
484
see_also.update(additional_terms)
485
return sorted(see_also)
487
191
def options(self):
488
192
"""Return dict of valid options for this command.
490
194
Maps from long option name to option object."""
491
r = Option.STD_OPTIONS.copy()
196
r['help'] = Option.OPTIONS['help']
493
197
for o in self.takes_options:
494
if isinstance(o, basestring):
495
o = option.Option.OPTIONS[o]
198
if not isinstance(o, Option):
199
o = Option.OPTIONS[o]
497
if o.name in std_names:
498
self.supported_std_options.append(o.name)
501
def _setup_outf(self):
502
"""Return a file linked to stdout, which has proper encoding."""
503
# Originally I was using self.stdout, but that looks
504
# *way* too much like sys.stdout
505
if self.encoding_type == 'exact':
506
# force sys.stdout to be binary stream on win32
507
if sys.platform == 'win32':
508
fileno = getattr(sys.stdout, 'fileno', None)
511
msvcrt.setmode(fileno(), os.O_BINARY)
512
self.outf = sys.stdout
515
output_encoding = osutils.get_terminal_encoding()
517
self.outf = codecs.getwriter(output_encoding)(sys.stdout,
518
errors=self.encoding_type)
519
# For whatever reason codecs.getwriter() does not advertise its encoding
520
# it just returns the encoding of the wrapped file, which is completely
521
# bogus. So set the attribute, so we can find the correct encoding later.
522
self.outf.encoding = output_encoding
524
def run_argv_aliases(self, argv, alias_argv=None):
525
"""Parse the command line and run with extra aliases in alias_argv."""
527
warn("Passing None for [] is deprecated from bzrlib 0.10",
528
DeprecationWarning, stacklevel=2)
530
args, opts = parse_args(self, argv, alias_argv)
532
# Process the standard options
203
def run_argv(self, argv):
204
"""Parse command line and run."""
205
args, opts = parse_args(self, argv)
533
206
if 'help' in opts: # e.g. bzr add --help
534
sys.stdout.write(self.get_help_text())
536
if 'usage' in opts: # e.g. bzr add --usage
537
sys.stdout.write(self.get_help_text(verbose=False))
539
trace.set_verbosity_level(option._verbosity_level)
540
if 'verbose' in self.supported_std_options:
541
opts['verbose'] = trace.is_verbose()
542
elif opts.has_key('verbose'):
544
if 'quiet' in self.supported_std_options:
545
opts['quiet'] = trace.is_quiet()
546
elif opts.has_key('quiet'):
207
from bzrlib.help import help_on_command
208
help_on_command(self.name())
210
# XXX: This should be handled by the parser
211
allowed_names = self.options().keys()
213
if oname not in allowed_names:
214
raise BzrCommandError("option '--%s' is not allowed for command %r"
215
% (oname, self.name()))
549
216
# mix arguments and options into one dictionary
550
217
cmdargs = _match_argform(self.name(), self.takes_args, args)
583
247
return _unsquish_command_name(self.__class__.__name__)
585
def plugin_name(self):
586
"""Get the name of the plugin that provides this command.
588
:return: The name of the plugin or None if the command is builtin.
590
mod_parts = self.__module__.split('.')
591
if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
250
def parse_spec(spec):
256
>>> parse_spec("../@")
258
>>> parse_spec("../f/@35")
260
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
261
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
266
parsed = spec.split('/@')
267
assert len(parsed) == 2
597
class CommandHooks(Hooks):
598
"""Hooks related to Command object creation/enumeration."""
601
"""Create the default hooks.
603
These are all empty initially, because by default nothing should get
607
self.create_hook(HookPoint('extend_command',
608
"Called after creating a command object to allow modifications "
609
"such as adding or removing options, docs etc. Called with the "
610
"new bzrlib.commands.Command object.", (1, 13), None))
612
Command.hooks = CommandHooks()
615
def parse_args(command, argv, alias_argv=None):
272
parsed[1] = int(parsed[1])
274
pass # We can allow stuff like ./@revid:blahblahblah
278
parsed = [spec, None]
281
def parse_args(command, argv):
616
282
"""Parse command line.
618
284
Arguments and options are parsed at this level before being passed
619
285
down to specific command handlers. This routine knows, from a
620
286
lookup table, something about the available options, what optargs
621
287
they take, and which commands will accept them.
623
# TODO: make it a method of the Command?
624
parser = option.get_optparser(command.options())
625
if alias_argv is not None:
626
args = alias_argv + argv
630
options, args = parser.parse_args(args)
631
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
632
v is not option.OptionParser.DEFAULT_VALUE])
289
# TODO: chop up this beast; make it a method of the Command
293
cmd_options = command.options()
301
# We've received a standalone -- No more flags
305
# option names must not be unicode
309
mutter(" got option %r" % a)
311
optname, optarg = a[2:].split('=', 1)
314
if optname not in cmd_options:
315
raise BzrOptionError('unknown long option %r for command %s'
316
% (a, command.name()))
319
if shortopt in Option.SHORT_OPTIONS:
320
# Multi-character options must have a space to delimit
322
# ^^^ what does this mean? mbp 20051014
323
optname = Option.SHORT_OPTIONS[shortopt].name
325
# Single character short options, can be chained,
326
# and have their value appended to their name
328
if shortopt not in Option.SHORT_OPTIONS:
329
# We didn't find the multi-character name, and we
330
# didn't find the single char name
331
raise BzrError('unknown short option %r' % a)
332
optname = Option.SHORT_OPTIONS[shortopt].name
335
# There are extra things on this option
336
# see if it is the value, or if it is another
338
optargfn = Option.OPTIONS[optname].type
340
# This option does not take an argument, so the
341
# next entry is another short option, pack it back
343
argv.insert(0, '-' + a[2:])
345
# This option takes an argument, so pack it
350
# XXX: Do we ever want to support this, e.g. for -r?
351
raise BzrError('repeated option %r' % a)
353
option_obj = cmd_options[optname]
354
optargfn = option_obj.type
358
raise BzrError('option %r needs an argument' % a)
361
opts[optname] = optargfn(optarg)
364
raise BzrError('option %r takes no argument' % optname)
633
368
return args, opts
718
436
os.remove(pfname)
721
def exception_to_return_code(the_callable, *args, **kwargs):
722
"""UI level helper for profiling and coverage.
724
This transforms exceptions into a return value of 3. As such its only
725
relevant to the UI layer, and should never be called where catching
726
exceptions may be desirable.
729
return the_callable(*args, **kwargs)
730
except (KeyboardInterrupt, Exception), e:
731
# used to handle AssertionError and KeyboardInterrupt
732
# specially here, but hopefully they're handled ok by the logger now
733
exc_info = sys.exc_info()
734
exitcode = trace.report_exception(exc_info, sys.stderr)
735
if os.environ.get('BZR_PDB'):
736
print '**** entering debugger'
739
if sys.version_info[:2] < (2, 6):
741
# pdb.post_mortem(tb)
742
# but because pdb.post_mortem gives bad results for tracebacks
743
# from inside generators, we do it manually.
744
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
746
# Setup pdb on the traceback
749
p.setup(tb.tb_frame, tb)
750
# Point the debugger at the deepest frame of the stack
751
p.curindex = len(p.stack) - 1
752
p.curframe = p.stack[p.curindex][0]
753
# Start the pdb prompt.
754
p.print_stack_entry(p.stack[p.curindex])
762
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
763
from bzrlib.lsprof import profile
764
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
770
trace.note('Profile data written to "%s".', filename)
774
def shlex_split_unicode(unsplit):
776
return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
779
def get_alias(cmd, config=None):
780
"""Return an expanded alias, or None if no alias exists.
783
Command to be checked for an alias.
785
Used to specify an alternative config to use,
786
which is especially useful for testing.
787
If it is unspecified, the global config will be used.
791
config = bzrlib.config.GlobalConfig()
792
alias = config.get_alias(cmd)
794
return shlex_split_unicode(alias)
798
439
def run_bzr(argv):
799
440
"""Execute a command.
442
This is similar to main(), but without all the trappings for
443
logging and error handling.
802
446
The command-line arguments, without the program name from argv[0]
803
These should already be decoded. All library/test code calling
804
run_bzr should be passing valid strings (don't need decoding).
806
448
Returns a command status or raises an exception.
808
450
Special master options: these must come before the command because
812
454
Do not load plugin modules at all
818
457
Only use builtin commands. (Plugins are still allowed to change
819
458
other behaviour.)
822
Run under the Python hotshot profiler.
825
Run under the Python lsprof profiler.
828
Generate line coverage report in the specified directory.
461
Run under the Python profiler.
831
trace.mutter("bzr arguments: %r", argv)
463
argv = [a.decode(bzrlib.user_encoding) for a in argv]
833
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
834
opt_no_aliases = False
835
opt_lsprof_file = opt_coverage_dir = None
465
opt_profile = opt_no_plugins = opt_builtin = False
837
467
# --no-plugins is handled specially at a very early stage. We need
838
468
# to load plugins before doing other command parsing so that they
839
469
# can override commands, but this needs to happen first.
845
472
if a == '--profile':
846
473
opt_profile = True
847
elif a == '--lsprof':
849
elif a == '--lsprof-file':
851
opt_lsprof_file = argv[i + 1]
853
474
elif a == '--no-plugins':
854
475
opt_no_plugins = True
855
elif a == '--no-aliases':
856
opt_no_aliases = True
857
476
elif a == '--builtin':
858
477
opt_builtin = True
859
elif a == '--coverage':
860
opt_coverage_dir = argv[i + 1]
862
elif a.startswith('-D'):
863
debug.debug_flags.add(a[2:])
868
debug.set_debug_flags_from_config()
872
from bzrlib.builtins import cmd_help
873
cmd_help().run_argv_aliases([])
482
if (not argv) or (argv[0] == '--help'):
483
from bzrlib.help import help
876
490
if argv[0] == '--version':
877
from bzrlib.builtins import cmd_version
878
cmd_version().run_argv_aliases([])
491
from bzrlib.builtins import show_version
881
495
if not opt_no_plugins:
882
496
from bzrlib.plugin import load_plugins
885
from bzrlib.plugin import disable_plugins
890
if not opt_no_aliases:
891
alias_argv = get_alias(argv[0])
893
user_encoding = osutils.get_user_encoding()
894
alias_argv = [a.decode(user_encoding) for a in alias_argv]
895
argv[0] = alias_argv.pop(0)
898
# We want only 'ascii' command names, but the user may have typed
899
# in a Unicode name. In that case, they should just get a
900
# 'command not found' error later.
499
cmd = str(argv.pop(0))
902
501
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
903
run = cmd_obj.run_argv_aliases
904
run_argv = [argv, alias_argv]
907
# We can be called recursively (tests for example), but we don't want
908
# the verbosity level to propagate.
909
saved_verbosity_level = option._verbosity_level
910
option._verbosity_level = 0
914
'--coverage ignored, because --lsprof is in use.')
915
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
919
'--coverage ignored, because --profile is in use.')
920
ret = apply_profiled(run, *run_argv)
921
elif opt_coverage_dir:
922
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
925
if 'memory' in debug.debug_flags:
926
trace.debug_memory('Process status after command:', short=False)
929
# reset, in case we may do other commands later within the same
930
# process. Commands that want to execute sub-commands must propagate
931
# --verbose in their own way.
932
option._verbosity_level = saved_verbosity_level
504
ret = apply_profiled(cmd_obj.run_argv, argv)
506
ret = cmd_obj.run_argv(argv)
935
509
def display_command(func):
936
"""Decorator that suppresses pipe/interrupt errors."""
937
510
def ignore_pipe(*args, **kwargs):
939
result = func(*args, **kwargs)
512
return func(*args, **kwargs)
942
513
except IOError, e:
943
if getattr(e, 'errno', None) is None:
514
if e.errno != errno.EPIPE:
945
if e.errno != errno.EPIPE:
946
# Win32 raises IOError with errno=0 on a broken pipe
947
if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
950
516
except KeyboardInterrupt:
952
518
return ignore_pipe
957
bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
958
sys.stdin, sys.stdout, sys.stderr)
522
bzrlib.trace.log_startup(argv)
523
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
960
# Is this a final release version? If so, we should suppress warnings
961
if bzrlib.version_info[3] == 'final':
962
from bzrlib import symbol_versioning
963
symbol_versioning.suppress_deprecation_warnings(override=False)
965
user_encoding = osutils.get_user_encoding()
966
argv = [a.decode(user_encoding) for a in argv[1:]]
967
except UnicodeDecodeError:
968
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
970
ret = run_bzr_catch_errors(argv)
971
trace.mutter("return code %d", ret)
525
return run_bzr_catch_errors(argv[1:])
975
528
def run_bzr_catch_errors(argv):
976
"""Run a bzr command with parameters as described by argv.
978
This function assumed that that UI layer is setup, that symbol deprecations
979
are already applied, and that unicode decoding has already been performed on argv.
981
return exception_to_return_code(run_bzr, argv)
984
def run_bzr_catch_user_errors(argv):
985
"""Run bzr and report user errors, but let internal errors propagate.
987
This is used for the test suite, and might be useful for other programs
988
that want to wrap the commandline interface.
533
# do this here inside the exception wrappers to catch EPIPE
535
except BzrCommandError, e:
536
# command line syntax error, etc
540
bzrlib.trace.log_exception()
542
except AssertionError, e:
543
bzrlib.trace.log_exception('assertion failed: ' + str(e))
545
except KeyboardInterrupt, e:
546
bzrlib.trace.log_exception('interrupted')
992
548
except Exception, e:
993
if (isinstance(e, (OSError, IOError))
994
or not getattr(e, 'internal_error', True)):
995
trace.report_exception(sys.exc_info(), sys.stderr)
1001
class HelpCommandIndex(object):
1002
"""A index for bzr help that returns commands."""
1005
self.prefix = 'commands/'
1007
def get_topics(self, topic):
1008
"""Search for topic amongst commands.
1010
:param topic: A topic to search for.
1011
:return: A list which is either empty or contains a single
1014
if topic and topic.startswith(self.prefix):
1015
topic = topic[len(self.prefix):]
1017
cmd = _get_cmd_object(topic)
1024
class Provider(object):
1025
'''Generic class to be overriden by plugins'''
1027
def plugin_for_command(self, cmd_name):
1028
'''Takes a command and returns the information for that plugin
1030
:return: A dictionary with all the available information
1031
for the requested plugin
1033
raise NotImplementedError
1036
class ProvidersRegistry(registry.Registry):
1037
'''This registry exists to allow other providers to exist'''
1040
for key, provider in self.iteritems():
1043
command_providers_registry = ProvidersRegistry()
550
if (isinstance(e, IOError)
551
and hasattr(e, 'errno')
552
and e.errno == errno.EPIPE):
553
bzrlib.trace.note('broken pipe')
558
bzrlib.trace.log_exception()
1046
561
if __name__ == '__main__':
1047
562
sys.exit(main(sys.argv))