35
35
lazy_import(globals(), """
39
38
from warnings import warn
42
41
from bzrlib import (
55
from bzrlib.hooks import HookPoint, Hooks
56
# Compatibility - Option used to be in commands.
57
from bzrlib.option import Option
58
from bzrlib.plugin import disable_plugins, load_plugins
59
from bzrlib import registry
60
51
from bzrlib.symbol_versioning import (
61
52
deprecated_function,
67
class CommandInfo(object):
68
"""Information about a command."""
70
def __init__(self, aliases):
71
"""The list of aliases for the command."""
72
self.aliases = aliases
75
def from_command(klass, command):
76
"""Factory to construct a CommandInfo from a command."""
77
return klass(command.aliases)
80
class CommandRegistry(registry.Registry):
83
def _get_name(command_name):
84
if command_name.startswith("cmd_"):
85
return _unsquish_command_name(command_name)
89
def register(self, cmd, decorate=False):
90
"""Utility function to help register a command
92
:param cmd: Command subclass to register
93
:param decorate: If true, allow overriding an existing command
94
of the same name; the old command is returned by this function.
95
Otherwise it is an error to try to override an existing command.
98
k_unsquished = self._get_name(k)
100
previous = self.get(k_unsquished)
102
previous = _builtin_commands().get(k_unsquished)
103
info = CommandInfo.from_command(cmd)
105
registry.Registry.register(self, k_unsquished, cmd,
106
override_existing=decorate, info=info)
108
trace.warning('Two plugins defined the same command: %r' % k)
109
trace.warning('Not loading the one in %r' %
110
sys.modules[cmd.__module__])
111
trace.warning('Previously this command was registered from %r' %
112
sys.modules[previous.__module__])
115
def register_lazy(self, command_name, aliases, module_name):
116
"""Register a command without loading its module.
118
:param command_name: The primary name of the command.
119
:param aliases: A list of aliases for the command.
120
:module_name: The module that the command lives in.
122
key = self._get_name(command_name)
123
registry.Registry.register_lazy(self, key, module_name, command_name,
124
info=CommandInfo(aliases))
127
plugin_cmds = CommandRegistry()
58
from bzrlib.option import Option
130
64
def register_command(cmd, decorate=False):
65
"""Utility function to help register a command
67
:param cmd: Command subclass to register
68
:param decorate: If true, allow overriding an existing command
69
of the same name; the old command is returned by this function.
70
Otherwise it is an error to try to override an existing command.
131
72
global plugin_cmds
132
return plugin_cmds.register(cmd, decorate)
74
if k.startswith("cmd_"):
75
k_unsquished = _unsquish_command_name(k)
78
if k_unsquished not in plugin_cmds:
79
plugin_cmds[k_unsquished] = cmd
80
## trace.mutter('registered plugin command %s', k_unsquished)
81
if decorate and k_unsquished in builtin_command_names():
82
return _builtin_commands()[k_unsquished]
84
result = plugin_cmds[k_unsquished]
85
plugin_cmds[k_unsquished] = cmd
88
trace.log_error('Two plugins defined the same command: %r' % k)
89
trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
135
92
def _squish_command_name(cmd):
139
96
def _unsquish_command_name(cmd):
97
assert cmd.startswith("cmd_")
140
98
return cmd[4:].replace('_','-')
143
101
def _builtin_commands():
144
102
import bzrlib.builtins
145
return _scan_module_for_commands(bzrlib.builtins)
148
def _scan_module_for_commands(module):
150
for name, obj in module.__dict__.iteritems():
104
builtins = bzrlib.builtins.__dict__
105
for name in builtins:
151
106
if name.startswith("cmd_"):
152
107
real_name = _unsquish_command_name(name)
108
r[real_name] = builtins[name]
157
def _list_bzr_commands(names):
158
"""Find commands from bzr's core and plugins."""
159
# to eliminate duplicates
160
names.update(builtin_command_names())
161
names.update(plugin_command_names())
165
def all_command_names():
166
"""Return a set of all command names."""
168
for hook in Command.hooks['list_commands']:
171
raise AssertionError(
172
'hook %s returned None' % Command.hooks.get_hook_name(hook))
176
112
def builtin_command_names():
177
"""Return list of builtin command names.
179
Use of all_command_names() is encouraged rather than builtin_command_names
180
and/or plugin_command_names.
113
"""Return list of builtin command names."""
182
114
return _builtin_commands().keys()
185
117
def plugin_command_names():
186
"""Returns command names from commands registered by plugins."""
187
118
return plugin_cmds.keys()
121
def _get_cmd_dict(plugins_override=True):
122
"""Return name->class mapping for all commands."""
123
d = _builtin_commands()
125
d.update(plugin_cmds)
129
def get_all_cmds(plugins_override=True):
130
"""Return canonical name and class for all registered commands."""
131
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
190
135
def get_cmd_object(cmd_name, plugins_override=True):
191
"""Return the command object for a command.
136
"""Return the canonical name and command class for a command.
194
139
If true, plugin commands can override builtins.
199
144
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
202
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):
203
"""Get a command object.
147
def _get_cmd_object(cmd_name, plugins_override=True):
148
"""Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
149
from bzrlib.externalcommand import ExternalCommand
205
:param cmd_name: The name of the command.
206
:param plugins_override: Allow plugins to override builtins.
207
:param check_missing: Look up commands not found in the regular index via
208
the get_missing_command hook.
209
:return: A Command object instance
210
:raises KeyError: If no command is found.
212
151
# We want only 'ascii' command names, but the user may have typed
213
152
# in a Unicode name. In that case, they should just get a
214
153
# 'command not found' error later.
215
154
# In the future, we may actually support Unicode command names.
218
for hook in Command.hooks['get_command']:
219
cmd = hook(cmd, cmd_name)
220
if cmd is not None and not plugins_override and not cmd.plugin_name():
221
# We've found a non-plugin command, don't permit it to be
224
if cmd is None and check_missing:
225
for hook in Command.hooks['get_missing_command']:
232
# Allow plugins to extend commands
233
for hook in Command.hooks['extend_command']:
238
def _try_plugin_provider(cmd_name):
239
"""Probe for a plugin provider having cmd_name."""
241
plugin_metadata, provider = probe_for_provider(cmd_name)
242
raise errors.CommandAvailableInPlugin(cmd_name,
243
plugin_metadata, provider)
244
except errors.NoPluginAvailable:
248
def probe_for_provider(cmd_name):
249
"""Look for a provider for cmd_name.
251
:param cmd_name: The command name.
252
:return: plugin_metadata, provider for getting cmd_name.
253
:raises NoPluginAvailable: When no provider can supply the plugin.
255
# look for providers that provide this command but aren't installed
256
for provider in command_providers_registry:
258
return provider.plugin_for_command(cmd_name), provider
259
except errors.NoPluginAvailable:
261
raise errors.NoPluginAvailable(cmd_name)
264
def _get_bzr_command(cmd_or_None, cmd_name):
265
"""Get a command from bzr's core."""
266
cmds = _builtin_commands()
156
# first look up this command under the specified name
157
cmds = _get_cmd_dict(plugins_override=plugins_override)
268
159
return cmds[cmd_name]()
271
163
# look for any command which claims this as an alias
272
164
for real_cmd_name, cmd_class in cmds.iteritems():
273
165
if cmd_name in cmd_class.aliases:
274
166
return cmd_class()
278
def _get_external_command(cmd_or_None, cmd_name):
279
"""Lookup a command that is a shell script."""
280
# Only do external command lookups when no command is found so far.
281
if cmd_or_None is not None:
283
from bzrlib.externalcommand import ExternalCommand
284
168
cmd_obj = ExternalCommand.find_command(cmd_name)
289
def _get_plugin_command(cmd_or_None, cmd_name):
290
"""Get a command from bzr's plugins."""
292
return plugin_cmds.get(cmd_name)()
295
for key in plugin_cmds.keys():
296
info = plugin_cmds.get_info(key)
297
if cmd_name in info.aliases:
298
return plugin_cmds.get(key)()
302
174
class Command(object):
364
235
encoding_type = 'strict'
368
239
def __init__(self):
369
240
"""Construct an instance of this command."""
370
241
if self.__doc__ == Command.__doc__:
371
242
warn("No help message set for %r" % self)
372
# List of standard options directly supported
373
self.supported_std_options = []
374
self._operation = cleanup.OperationWithCleanups(self.run)
376
def add_cleanup(self, cleanup_func, *args, **kwargs):
377
"""Register a function to call after self.run returns or raises.
379
Functions will be called in LIFO order.
381
self._operation.add_cleanup(cleanup_func, *args, **kwargs)
383
def cleanup_now(self):
384
"""Execute and empty pending cleanup functions immediately.
386
After cleanup_now all registered cleanups are forgotten. add_cleanup
387
may be called again after cleanup_now; these cleanups will be called
388
after self.run returns or raises (or when cleanup_now is next called).
390
This is useful for releasing expensive or contentious resources (such
391
as write locks) before doing further work that does not require those
392
resources (such as writing results to self.outf).
394
self._operation.cleanup_now()
396
@deprecated_method(deprecated_in((2, 1, 0)))
397
244
def _maybe_expand_globs(self, file_list):
398
245
"""Glob expand file_list if the platform does not do that itself.
400
Not used anymore, now that the bzr command-line parser globs on
403
247
:return: A possibly empty list of unicode paths.
405
249
Introduced in bzrlib 0.18.
253
if sys.platform == 'win32':
254
file_list = win32utils.glob_expand(file_list)
255
return list(file_list)
409
257
def _usage(self):
410
258
"""Return single-line grammar for this command.
421
269
elif aname[-1] == '*':
422
270
aname = '[' + aname[:-1] + '...]'
424
s = s[:-1] # remove last space
427
277
def get_help_text(self, additional_see_also=None, plain=True,
428
see_also_as_links=False, verbose=True):
278
see_also_as_links=False):
429
279
"""Return a text string with help for this command.
431
281
:param additional_see_also: Additional help topics to be
432
282
cross-referenced.
433
283
:param plain: if False, raw help (reStructuredText) is
434
284
returned instead of plain text.
435
285
:param see_also_as_links: if True, convert items in 'See also'
436
286
list to internal links (used by bzr_man rstx generator)
437
:param verbose: if True, display the full help, otherwise
438
leave out the descriptive sections and just display
439
usage help (e.g. Purpose, Usage, Options) with a
440
message explaining how to obtain full help.
442
288
doc = self.help()
444
290
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
446
292
# Extract the summary (purpose) and sections out from the text
447
purpose,sections,order = self._get_help_parts(doc)
293
purpose,sections = self._get_help_parts(doc)
449
295
# If a custom usage section was provided, use it
450
296
if sections.has_key('Usage'):
464
310
# Add the options
466
# XXX: optparse implicitly rewraps the help, and not always perfectly,
467
# so we get <https://bugs.launchpad.net/bzr/+bug/249908>. -- mbp
469
311
options = option.get_optparser(self.options()).format_option_help()
470
# XXX: According to the spec, ReST option lists actually don't support
471
# options like --1.9 so that causes syntax errors (in Sphinx at least).
472
# As that pattern always appears in the commands that break, we trap
473
# on that and then format that block of 'format' options as a literal
475
if not plain and options.find(' --1.9 ') != -1:
476
options = options.replace(' format:\n', ' format::\n\n', 1)
477
312
if options.startswith('Options:'):
478
313
result += ':' + options
479
314
elif options.startswith('options:'):
483
318
result += options
487
# Add the description, indenting it 2 spaces
488
# to match the indentation of the options
489
if sections.has_key(None):
490
text = sections.pop(None)
491
text = '\n '.join(text.splitlines())
492
result += ':%s:\n %s\n\n' % ('Description',text)
321
# Add the description, indenting it 2 spaces
322
# to match the indentation of the options
323
if sections.has_key(None):
324
text = sections.pop(None)
325
text = '\n '.join(text.splitlines())
326
result += ':%s:\n %s\n\n' % ('Description',text)
494
# Add the custom sections (e.g. Examples). Note that there's no need
495
# to indent these as they must be indented already in the source.
498
if sections.has_key(label):
499
result += ':%s:\n%s\n' % (label,sections[label])
502
result += ("See bzr help %s for more details and examples.\n\n"
328
# Add the custom sections (e.g. Examples). Note that there's no need
329
# to indent these as they must be indented already in the source.
331
labels = sorted(sections.keys())
333
result += ':%s:\n%s\n\n' % (label,sections[label])
505
335
# Add the aliases, source (plug-in) and see also links, if any
519
349
# so don't create a real link
520
350
see_also_links.append(item)
522
# Use a Sphinx link for this entry
523
link_text = ":doc:`%s <%s-help>`" % (item, item)
524
see_also_links.append(link_text)
352
# Use a reST link for this entry
353
see_also_links.append("`%s`_" % (item,))
525
354
see_also = see_also_links
526
355
result += ':See also: '
527
356
result += ', '.join(see_also) + '\n'
529
# If this will be rendered as plain text, convert it
358
# If this will be rendered as plan text, convert it
531
360
import bzrlib.help_topics
532
361
result = bzrlib.help_topics.help_as_plain_text(result)
536
365
def _get_help_parts(text):
537
366
"""Split help text into a summary and named sections.
539
:return: (summary,sections,order) where summary is the top line and
368
:return: (summary,sections) where summary is the top line and
540
369
sections is a dictionary of the rest indexed by section name.
541
order is the order the section appear in the text.
542
370
A section starts with a heading line of the form ":xxx:".
543
371
Indented text on following lines is the section value.
544
372
All text found outside a named section is assigned to the
545
373
default section which is given the key of None.
547
def save_section(sections, order, label, section):
375
def save_section(sections, label, section):
548
376
if len(section) > 0:
549
377
if sections.has_key(label):
550
378
sections[label] += '\n' + section
553
380
sections[label] = section
555
382
lines = text.rstrip().splitlines()
556
383
summary = lines.pop(0)
559
385
label,section = None,''
560
386
for line in lines:
561
387
if line.startswith(':') and line.endswith(':') and len(line) > 2:
562
save_section(sections, order, label, section)
388
save_section(sections, label, section)
563
389
label,section = line[1:-1],''
564
elif (label is not None) and len(line) > 1 and not line[0].isspace():
565
save_section(sections, order, label, section)
390
elif label != None and len(line) > 1 and not line[0].isspace():
391
save_section(sections, label, section)
566
392
label,section = None,line
568
394
if len(section) > 0:
569
395
section += '\n' + line
572
save_section(sections, order, label, section)
573
return summary, sections, order
398
save_section(sections, label, section)
399
return summary, sections
575
401
def get_help_topic(self):
576
402
"""Return the commands help topic - its name."""
593
419
"""Return dict of valid options for this command.
595
421
Maps from long option name to option object."""
596
r = Option.STD_OPTIONS.copy()
423
r['help'] = option._help_option
598
424
for o in self.takes_options:
599
425
if isinstance(o, basestring):
600
426
o = option.Option.OPTIONS[o]
602
if o.name in std_names:
603
self.supported_std_options.append(o.name)
606
430
def _setup_outf(self):
607
431
"""Return a file linked to stdout, which has proper encoding."""
608
self.outf = ui.ui_factory.make_output_stream(
609
encoding_type=self.encoding_type)
432
assert self.encoding_type in ['strict', 'exact', 'replace']
434
# Originally I was using self.stdout, but that looks
435
# *way* too much like sys.stdout
436
if self.encoding_type == 'exact':
437
# force sys.stdout to be binary stream on win32
438
if sys.platform == 'win32':
439
fileno = getattr(sys.stdout, 'fileno', None)
442
msvcrt.setmode(fileno(), os.O_BINARY)
443
self.outf = sys.stdout
446
output_encoding = osutils.get_terminal_encoding()
448
# use 'replace' so that we don't abort if trying to write out
449
# in e.g. the default C locale.
450
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
451
# For whatever reason codecs.getwriter() does not advertise its encoding
452
# it just returns the encoding of the wrapped file, which is completely
453
# bogus. So set the attribute, so we can find the correct encoding later.
454
self.outf.encoding = output_encoding
611
456
def run_argv_aliases(self, argv, alias_argv=None):
612
457
"""Parse the command line and run with extra aliases in alias_argv."""
459
warn("Passing None for [] is deprecated from bzrlib 0.10",
460
DeprecationWarning, stacklevel=2)
613
462
args, opts = parse_args(self, argv, alias_argv)
615
# Process the standard options
616
463
if 'help' in opts: # e.g. bzr add --help
617
464
sys.stdout.write(self.get_help_text())
619
if 'usage' in opts: # e.g. bzr add --usage
620
sys.stdout.write(self.get_help_text(verbose=False))
622
trace.set_verbosity_level(option._verbosity_level)
623
if 'verbose' in self.supported_std_options:
624
opts['verbose'] = trace.is_verbose()
625
elif opts.has_key('verbose'):
627
if 'quiet' in self.supported_std_options:
628
opts['quiet'] = trace.is_quiet()
629
elif opts.has_key('quiet'):
632
466
# mix arguments and options into one dictionary
633
467
cmdargs = _match_argform(self.name(), self.takes_args, args)
684
class CommandHooks(Hooks):
685
"""Hooks related to Command object creation/enumeration."""
688
"""Create the default hooks.
690
These are all empty initially, because by default nothing should get
694
self.create_hook(HookPoint('extend_command',
695
"Called after creating a command object to allow modifications "
696
"such as adding or removing options, docs etc. Called with the "
697
"new bzrlib.commands.Command object.", (1, 13), None))
698
self.create_hook(HookPoint('get_command',
699
"Called when creating a single command. Called with "
700
"(cmd_or_None, command_name). get_command should either return "
701
"the cmd_or_None parameter, or a replacement Command object that "
702
"should be used for the command. Note that the Command.hooks "
703
"hooks are core infrastructure. Many users will prefer to use "
704
"bzrlib.commands.register_command or plugin_cmds.register_lazy.",
706
self.create_hook(HookPoint('get_missing_command',
707
"Called when creating a single command if no command could be "
708
"found. Called with (command_name). get_missing_command should "
709
"either return None, or a Command object to be used for the "
710
"command.", (1, 17), None))
711
self.create_hook(HookPoint('list_commands',
712
"Called when enumerating commands. Called with a set of "
713
"cmd_name strings for all the commands found so far. This set "
714
" is safe to mutate - e.g. to remove a command. "
715
"list_commands should return the updated set of command names.",
718
Command.hooks = CommandHooks()
514
# Technically, this function hasn't been use in a *really* long time
515
# but we are only deprecating it now.
516
@deprecated_function(zero_eleven)
517
def parse_spec(spec):
523
>>> parse_spec("../@")
525
>>> parse_spec("../f/@35")
527
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
528
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
533
parsed = spec.split('/@')
534
assert len(parsed) == 2
539
parsed[1] = int(parsed[1])
541
pass # We can allow stuff like ./@revid:blahblahblah
545
parsed = [spec, None]
721
548
def parse_args(command, argv, alias_argv=None):
722
549
"""Parse command line.
724
551
Arguments and options are parsed at this level before being passed
725
552
down to specific command handlers. This routine knows, from a
726
553
lookup table, something about the available options, what optargs
775
602
% (cmd, argname.upper()))
777
604
argdict[argname] = args.pop(0)
780
607
raise errors.BzrCommandError("extra argument to command %s: %s"
781
608
% (cmd, args[0]))
785
def apply_coveraged(dirname, the_callable, *args, **kwargs):
786
# Cannot use "import trace", as that would import bzrlib.trace instead of
787
# the standard library's trace.
788
trace = __import__('trace')
790
tracer = trace.Trace(count=1, trace=0)
791
sys.settrace(tracer.globaltrace)
792
threading.settrace(tracer.globaltrace)
795
return exception_to_return_code(the_callable, *args, **kwargs)
798
results = tracer.results()
799
results.write_results(show_missing=1, summary=False,
803
614
def apply_profiled(the_callable, *args, **kwargs):
824
634
os.remove(pfname)
827
def exception_to_return_code(the_callable, *args, **kwargs):
828
"""UI level helper for profiling and coverage.
830
This transforms exceptions into a return value of 3. As such its only
831
relevant to the UI layer, and should never be called where catching
832
exceptions may be desirable.
835
return the_callable(*args, **kwargs)
836
except (KeyboardInterrupt, Exception), e:
837
# used to handle AssertionError and KeyboardInterrupt
838
# specially here, but hopefully they're handled ok by the logger now
839
exc_info = sys.exc_info()
840
exitcode = trace.report_exception(exc_info, sys.stderr)
841
if os.environ.get('BZR_PDB'):
842
print '**** entering debugger'
845
if sys.version_info[:2] < (2, 6):
847
# pdb.post_mortem(tb)
848
# but because pdb.post_mortem gives bad results for tracebacks
849
# from inside generators, we do it manually.
850
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
852
# Setup pdb on the traceback
855
p.setup(tb.tb_frame, tb)
856
# Point the debugger at the deepest frame of the stack
857
p.curindex = len(p.stack) - 1
858
p.curframe = p.stack[p.curindex][0]
859
# Start the pdb prompt.
860
p.print_stack_entry(p.stack[p.curindex])
868
637
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
869
638
from bzrlib.lsprof import profile
870
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
639
ret, stats = profile(the_callable, *args, **kwargs)
872
641
if filename is None:
897
661
config = bzrlib.config.GlobalConfig()
898
662
alias = config.get_alias(cmd)
900
return cmdline.split(alias)
665
return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
904
def run_bzr(argv, load_plugins=load_plugins, disable_plugins=disable_plugins):
905
670
"""Execute a command.
907
:param argv: The command-line arguments, without the program name from
908
argv[0] These should already be decoded. All library/test code calling
909
run_bzr should be passing valid strings (don't need decoding).
910
:param load_plugins: What function to call when triggering plugin loading.
911
This function should take no arguments and cause all plugins to be
913
:param disable_plugins: What function to call when disabling plugin
914
loading. This function should take no arguments and cause all plugin
915
loading to be prohibited (so that code paths in your application that
916
know about some plugins possibly being present will fail to import
917
those plugins even if they are installed.)
918
:return: Returns a command exit code or raises an exception.
672
This is similar to main(), but without all the trappings for
673
logging and error handling.
676
The command-line arguments, without the program name from argv[0]
677
These should already be decoded. All library/test code calling
678
run_bzr should be passing valid strings (don't need decoding).
680
Returns a command status or raises an exception.
920
682
Special master options: these must come before the command because
921
683
they control how the command is interpreted.
972
727
opt_no_aliases = True
973
728
elif a == '--builtin':
974
729
opt_builtin = True
975
elif a == '--concurrency':
976
os.environ['BZR_CONCURRENCY'] = argv[i + 1]
978
elif a == '--coverage':
979
opt_coverage_dir = argv[i + 1]
730
elif a in ('--quiet', '-q'):
981
732
elif a.startswith('-D'):
982
733
debug.debug_flags.add(a[2:])
984
735
argv_copy.append(a)
987
debug.set_debug_flags_from_config()
740
from bzrlib.builtins import cmd_help
741
cmd_help().run_argv_aliases([])
744
if argv[0] == '--version':
745
from bzrlib.version import show_version
989
749
if not opt_no_plugins:
750
from bzrlib.plugin import load_plugins
753
from bzrlib.plugin import disable_plugins
992
754
disable_plugins()
996
get_cmd_object('help').run_argv_aliases([])
999
if argv[0] == '--version':
1000
get_cmd_object('version').run_argv_aliases([])
1003
756
alias_argv = None
1005
758
if not opt_no_aliases:
1006
759
alias_argv = get_alias(argv[0])
1008
user_encoding = osutils.get_user_encoding()
1009
alias_argv = [a.decode(user_encoding) for a in alias_argv]
761
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
1010
762
argv[0] = alias_argv.pop(0)
1012
764
cmd = argv.pop(0)
1019
771
run_argv = [argv, alias_argv]
1022
# We can be called recursively (tests for example), but we don't want
1023
# the verbosity level to propagate.
1024
saved_verbosity_level = option._verbosity_level
1025
option._verbosity_level = 0
1027
if opt_coverage_dir:
1029
'--coverage ignored, because --lsprof is in use.')
1030
775
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
1031
776
elif opt_profile:
1032
if opt_coverage_dir:
1034
'--coverage ignored, because --profile is in use.')
1035
777
ret = apply_profiled(run, *run_argv)
1036
elif opt_coverage_dir:
1037
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1039
779
ret = run(*run_argv)
1042
# reset, in case we may do other commands later within the same
1043
# process. Commands that want to execute sub-commands must propagate
1044
# --verbose in their own way.
1045
if 'memory' in debug.debug_flags:
1046
trace.debug_memory('Process status after command:', short=False)
1047
option._verbosity_level = saved_verbosity_level
782
# reset, in case we may do other commands later within the same process
783
trace.be_quiet(False)
1050
785
def display_command(func):
1051
786
"""Decorator that suppresses pipe/interrupt errors."""
1067
802
return ignore_pipe
1070
def install_bzr_command_hooks():
1071
"""Install the hooks to supply bzr's own commands."""
1072
if _list_bzr_commands in Command.hooks["list_commands"]:
1074
Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1076
Command.hooks.install_named_hook("get_command", _get_bzr_command,
1078
Command.hooks.install_named_hook("get_command", _get_plugin_command,
1079
"bzr plugin commands")
1080
Command.hooks.install_named_hook("get_command", _get_external_command,
1081
"bzr external command lookup")
1082
Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1083
"bzr plugin-provider-db check")
1087
def _specified_or_unicode_argv(argv):
1088
# For internal or testing use, argv can be passed. Otherwise, get it from
1089
# the process arguments in a unicode-safe way.
1091
return osutils.get_unicode_argv()
1095
# ensure all arguments are unicode strings
1097
if isinstance(a, unicode):
1100
new_argv.append(a.decode('ascii'))
1101
except UnicodeDecodeError:
1102
raise errors.BzrError("argv should be list of unicode strings.")
1106
def main(argv=None):
1107
"""Main entry point of command-line interface.
1109
Typically `bzrlib.initialize` should be called first.
1111
:param argv: list of unicode command-line arguments similar to sys.argv.
1112
argv[0] is script name usually, it will be ignored.
1113
Don't pass here sys.argv because this list contains plain strings
1114
and not unicode; pass None instead.
1116
:return: exit code of bzr command.
1118
argv = _specified_or_unicode_argv(argv)
807
from bzrlib.ui.text import TextUIFactory
808
bzrlib.ui.ui_factory = TextUIFactory()
809
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
1119
810
ret = run_bzr_catch_errors(argv)
1120
bzrlib.ui.ui_factory.log_transport_activity(
1121
display=('bytes' in debug.debug_flags))
1122
811
trace.mutter("return code %d", ret)
1126
815
def run_bzr_catch_errors(argv):
1127
"""Run a bzr command with parameters as described by argv.
1129
This function assumed that that UI layer is setup, that symbol deprecations
1130
are already applied, and that unicode decoding has already been performed on argv.
1132
# done here so that they're covered for every test run
1133
install_bzr_command_hooks()
1134
return exception_to_return_code(run_bzr, argv)
1137
def run_bzr_catch_user_errors(argv):
1138
"""Run bzr and report user errors, but let internal errors propagate.
1140
This is used for the test suite, and might be useful for other programs
1141
that want to wrap the commandline interface.
1143
# done here so that they're covered for every test run
1144
install_bzr_command_hooks()
1146
817
return run_bzr(argv)
1147
except Exception, e:
1148
if (isinstance(e, (OSError, IOError))
1149
or not getattr(e, 'internal_error', True)):
1150
trace.report_exception(sys.exc_info(), sys.stderr)
818
except (KeyboardInterrupt, Exception), e:
819
# used to handle AssertionError and KeyboardInterrupt
820
# specially here, but hopefully they're handled ok by the logger now
821
trace.report_exception(sys.exc_info(), sys.stderr)
822
if os.environ.get('BZR_PDB'):
823
print '**** entering debugger'
825
pdb.post_mortem(sys.exc_traceback)
1156
829
class HelpCommandIndex(object):
1169
842
if topic and topic.startswith(self.prefix):
1170
843
topic = topic[len(self.prefix):]
1172
cmd = _get_cmd_object(topic, check_missing=False)
845
cmd = _get_cmd_object(topic)
1173
846
except KeyError:
1179
class Provider(object):
1180
'''Generic class to be overriden by plugins'''
1182
def plugin_for_command(self, cmd_name):
1183
'''Takes a command and returns the information for that plugin
1185
:return: A dictionary with all the available information
1186
for the requested plugin
1188
raise NotImplementedError
1191
class ProvidersRegistry(registry.Registry):
1192
'''This registry exists to allow other providers to exist'''
1195
for key, provider in self.iteritems():
1198
command_providers_registry = ProvidersRegistry()
852
if __name__ == '__main__':
853
sys.exit(main(sys.argv))