133
142
def _builtin_commands():
134
143
import bzrlib.builtins
144
return _scan_module_for_commands(bzrlib.builtins)
147
def _scan_module_for_commands(module):
136
builtins = bzrlib.builtins.__dict__
137
for name in builtins:
149
for name, obj in module.__dict__.iteritems():
138
150
if name.startswith("cmd_"):
139
151
real_name = _unsquish_command_name(name)
140
r[real_name] = builtins[name]
156
def _list_bzr_commands(names):
157
"""Find commands from bzr's core and plugins."""
158
# to eliminate duplicates
159
names.update(builtin_command_names())
160
names.update(plugin_command_names())
164
def all_command_names():
165
"""Return a set of all command names."""
167
for hook in Command.hooks['list_commands']:
170
raise AssertionError(
171
'hook %s returned None' % Command.hooks.get_hook_name(hook))
144
175
def builtin_command_names():
145
"""Return list of builtin command names."""
176
"""Return list of builtin command names.
178
Use of all_command_names() is encouraged rather than builtin_command_names
179
and/or plugin_command_names.
146
181
return _builtin_commands().keys()
149
184
def plugin_command_names():
185
"""Returns command names from commands registered by plugins."""
150
186
return plugin_cmds.keys()
153
def _get_cmd_dict(plugins_override=True):
154
"""Return name->class mapping for all commands."""
189
@deprecated_function(deprecated_in((1, 17, 0)))
190
def get_all_cmds(plugins_override=False):
191
"""Return canonical name and class for most commands.
193
NB: This does not return all commands since the introduction of
194
command hooks, and returning the class is not sufficient to
195
get correctly setup commands, which is why it is deprecated.
197
Use 'all_command_names' + 'get_cmd_object' instead.
155
199
d = _builtin_commands()
156
200
if plugins_override:
157
201
d.update(plugin_cmds.iteritems())
161
def get_all_cmds(plugins_override=True):
162
"""Return canonical name and class for all registered commands."""
163
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
202
for k, v in d.iteritems():
167
206
def get_cmd_object(cmd_name, plugins_override=True):
168
"""Return the canonical name and command class for a command.
207
"""Return the command object for a command.
171
210
If true, plugin commands can override builtins.
174
cmd = _get_cmd_object(cmd_name, plugins_override)
175
# Allow plugins to extend commands
176
for hook in Command.hooks['extend_command']:
213
return _get_cmd_object(cmd_name, plugins_override)
180
215
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
183
218
def _get_cmd_object(cmd_name, plugins_override=True):
184
"""Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
185
from bzrlib.externalcommand import ExternalCommand
219
"""Get a command object.
221
:param cmd_name: The name of the command.
222
:param plugins_override: Allow plugins to override builtins.
223
:return: A Command object instance
224
:raises KeyError: If no command is found.
187
226
# We want only 'ascii' command names, but the user may have typed
188
227
# in a Unicode name. In that case, they should just get a
189
228
# 'command not found' error later.
190
229
# In the future, we may actually support Unicode command names.
192
# first look up this command under the specified name
232
for hook in Command.hooks['get_command']:
233
cmd = hook(cmd, cmd_name)
234
if cmd is not None and not plugins_override and not cmd.plugin_name():
235
# We've found a non-plugin command, don't permit it to be
239
for hook in Command.hooks['get_missing_command']:
246
# Allow plugins to extend commands
247
for hook in Command.hooks['extend_command']:
252
def _try_plugin_provider(cmd_name):
253
"""Probe for a plugin provider having cmd_name."""
255
plugin_metadata, provider = probe_for_provider(cmd_name)
256
raise errors.CommandAvailableInPlugin(cmd_name,
257
plugin_metadata, provider)
258
except errors.NoPluginAvailable:
262
def probe_for_provider(cmd_name):
263
"""Look for a provider for cmd_name.
265
:param cmd_name: The command name.
266
:return: plugin_metadata, provider for getting cmd_name.
267
:raises NoPluginAvailable: When no provider can supply the plugin.
269
# look for providers that provide this command but aren't installed
270
for provider in command_providers_registry:
195
return plugin_cmds.get(cmd_name)()
272
return provider.plugin_for_command(cmd_name), provider
273
except errors.NoPluginAvailable:
198
cmds = _get_cmd_dict(plugins_override=False)
275
raise errors.NoPluginAvailable(cmd_name)
278
def _get_bzr_command(cmd_or_None, cmd_name):
279
"""Get a command from bzr's core."""
280
cmds = _builtin_commands()
200
282
return cmds[cmd_name]()
204
for key in plugin_cmds.keys():
205
info = plugin_cmds.get_info(key)
206
if cmd_name in info.aliases:
207
return plugin_cmds.get(key)()
208
285
# look for any command which claims this as an alias
209
286
for real_cmd_name, cmd_class in cmds.iteritems():
210
287
if cmd_name in cmd_class.aliases:
211
288
return cmd_class()
292
def _get_external_command(cmd_or_None, cmd_name):
293
"""Lookup a command that is a shell script."""
294
# Only do external command lookups when no command is found so far.
295
if cmd_or_None is not None:
297
from bzrlib.externalcommand import ExternalCommand
213
298
cmd_obj = ExternalCommand.find_command(cmd_name)
217
# look for plugins that provide this command but aren't installed
218
for provider in command_providers_registry:
220
plugin_metadata = provider.plugin_for_command(cmd_name)
221
except errors.NoPluginAvailable:
224
raise errors.CommandAvailableInPlugin(cmd_name,
225
plugin_metadata, provider)
303
def _get_plugin_command(cmd_or_None, cmd_name):
304
"""Get a command from bzr's plugins."""
306
return plugin_cmds.get(cmd_name)()
309
for key in plugin_cmds.keys():
310
info = plugin_cmds.get_info(key)
311
if cmd_name in info.aliases:
312
return plugin_cmds.get(key)()
229
316
class Command(object):
291
378
encoding_type = 'strict'
295
382
def __init__(self):
296
383
"""Construct an instance of this command."""
297
384
if self.__doc__ == Command.__doc__:
298
385
warn("No help message set for %r" % self)
299
386
# List of standard options directly supported
300
387
self.supported_std_options = []
388
self._operation = cleanup.OperationWithCleanups(self.run)
390
def add_cleanup(self, cleanup_func, *args, **kwargs):
391
"""Register a function to call after self.run returns or raises.
393
Functions will be called in LIFO order.
395
self._operation.add_cleanup(cleanup_func, *args, **kwargs)
397
def cleanup_now(self):
398
"""Execute and empty pending cleanup functions immediately.
400
After cleanup_now all registered cleanups are forgotten. add_cleanup
401
may be called again after cleanup_now; these cleanups will be called
402
after self.run returns or raises (or when cleanup_now is next called).
404
This is useful for releasing expensive or contentious resources (such
405
as write locks) before doing further work that does not require those
406
resources (such as writing results to self.outf).
408
self._operation.cleanup_now()
410
@deprecated_method(deprecated_in((2, 1, 0)))
302
411
def _maybe_expand_globs(self, file_list):
303
412
"""Glob expand file_list if the platform does not do that itself.
414
Not used anymore, now that the bzr command-line parser globs on
305
417
:return: A possibly empty list of unicode paths.
307
419
Introduced in bzrlib 0.18.
311
if sys.platform == 'win32':
312
file_list = win32utils.glob_expand(file_list)
313
return list(file_list)
315
423
def _usage(self):
316
424
"""Return single-line grammar for this command.
374
497
result += options
377
# Add the description, indenting it 2 spaces
378
# to match the indentation of the options
379
if sections.has_key(None):
380
text = sections.pop(None)
381
text = '\n '.join(text.splitlines())
382
result += ':%s:\n %s\n\n' % ('Description',text)
501
# Add the description, indenting it 2 spaces
502
# to match the indentation of the options
503
if sections.has_key(None):
504
text = sections.pop(None)
505
text = '\n '.join(text.splitlines())
506
result += ':%s:\n %s\n\n' % ('Description',text)
384
# Add the custom sections (e.g. Examples). Note that there's no need
385
# to indent these as they must be indented already in the source.
388
if sections.has_key(label):
389
result += ':%s:\n%s\n\n' % (label,sections[label])
508
# Add the custom sections (e.g. Examples). Note that there's no need
509
# to indent these as they must be indented already in the source.
512
if sections.has_key(label):
513
result += ':%s:\n%s\n' % (label,sections[label])
516
result += ("See bzr help %s for more details and examples.\n\n"
391
519
# Add the aliases, source (plug-in) and see also links, if any
491
620
def _setup_outf(self):
492
621
"""Return a file linked to stdout, which has proper encoding."""
493
# Originally I was using self.stdout, but that looks
494
# *way* too much like sys.stdout
495
if self.encoding_type == 'exact':
496
# force sys.stdout to be binary stream on win32
497
if sys.platform == 'win32':
498
fileno = getattr(sys.stdout, 'fileno', None)
501
msvcrt.setmode(fileno(), os.O_BINARY)
502
self.outf = sys.stdout
505
output_encoding = osutils.get_terminal_encoding()
507
self.outf = codecs.getwriter(output_encoding)(sys.stdout,
508
errors=self.encoding_type)
509
# For whatever reason codecs.getwriter() does not advertise its encoding
510
# it just returns the encoding of the wrapped file, which is completely
511
# bogus. So set the attribute, so we can find the correct encoding later.
512
self.outf.encoding = output_encoding
622
self.outf = ui.ui_factory.make_output_stream(
623
encoding_type=self.encoding_type)
514
625
def run_argv_aliases(self, argv, alias_argv=None):
515
626
"""Parse the command line and run with extra aliases in alias_argv."""
593
711
Hooks.__init__(self)
594
# Introduced in 1.13:
595
# invoked after creating a command object to allow modifications such
596
# as adding or removing options, docs etc. Invoked with the command
598
self['extend_command'] = []
712
self.create_hook(HookPoint('extend_command',
713
"Called after creating a command object to allow modifications "
714
"such as adding or removing options, docs etc. Called with the "
715
"new bzrlib.commands.Command object.", (1, 13), None))
716
self.create_hook(HookPoint('get_command',
717
"Called when creating a single command. Called with "
718
"(cmd_or_None, command_name). get_command should either return "
719
"the cmd_or_None parameter, or a replacement Command object that "
720
"should be used for the command. Note that the Command.hooks "
721
"hooks are core infrastructure. Many users will prefer to use "
722
"bzrlib.commands.register_command or plugin_cmds.register_lazy.",
724
self.create_hook(HookPoint('get_missing_command',
725
"Called when creating a single command if no command could be "
726
"found. Called with (command_name). get_missing_command should "
727
"either return None, or a Command object to be used for the "
728
"command.", (1, 17), None))
729
self.create_hook(HookPoint('list_commands',
730
"Called when enumerating commands. Called with a set of "
731
"cmd_name strings for all the commands found so far. This set "
732
" is safe to mutate - e.g. to remove a command. "
733
"list_commands should return the updated set of command names.",
600
736
Command.hooks = CommandHooks()
603
739
def parse_args(command, argv, alias_argv=None):
604
740
"""Parse command line.
606
742
Arguments and options are parsed at this level before being passed
607
743
down to specific command handlers. This routine knows, from a
608
744
lookup table, something about the available options, what optargs
703
842
os.remove(pfname)
845
def exception_to_return_code(the_callable, *args, **kwargs):
846
"""UI level helper for profiling and coverage.
848
This transforms exceptions into a return value of 3. As such its only
849
relevant to the UI layer, and should never be called where catching
850
exceptions may be desirable.
853
return the_callable(*args, **kwargs)
854
except (KeyboardInterrupt, Exception), e:
855
# used to handle AssertionError and KeyboardInterrupt
856
# specially here, but hopefully they're handled ok by the logger now
857
exc_info = sys.exc_info()
858
exitcode = trace.report_exception(exc_info, sys.stderr)
859
if os.environ.get('BZR_PDB'):
860
print '**** entering debugger'
863
if sys.version_info[:2] < (2, 6):
865
# pdb.post_mortem(tb)
866
# but because pdb.post_mortem gives bad results for tracebacks
867
# from inside generators, we do it manually.
868
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
870
# Setup pdb on the traceback
873
p.setup(tb.tb_frame, tb)
874
# Point the debugger at the deepest frame of the stack
875
p.curindex = len(p.stack) - 1
876
p.curframe = p.stack[p.curindex][0]
877
# Start the pdb prompt.
878
p.print_stack_entry(p.stack[p.curindex])
706
886
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
707
887
from bzrlib.lsprof import profile
708
ret, stats = profile(the_callable, *args, **kwargs)
888
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
710
890
if filename is None:
894
1083
return ignore_pipe
1086
def install_bzr_command_hooks():
1087
"""Install the hooks to supply bzr's own commands."""
1088
if _list_bzr_commands in Command.hooks["list_commands"]:
1090
Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1092
Command.hooks.install_named_hook("get_command", _get_bzr_command,
1094
Command.hooks.install_named_hook("get_command", _get_plugin_command,
1095
"bzr plugin commands")
1096
Command.hooks.install_named_hook("get_command", _get_external_command,
1097
"bzr external command lookup")
1098
Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1099
"bzr plugin-provider-db check")
1102
def main(argv=None):
1103
"""Main entry point of command-line interface.
1105
:param argv: list of unicode command-line arguments similar to sys.argv.
1106
argv[0] is script name usually, it will be ignored.
1107
Don't pass here sys.argv because this list contains plain strings
1108
and not unicode; pass None instead.
1110
:return: exit code of bzr command.
898
1112
import bzrlib.ui
899
1113
bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
900
1114
sys.stdin, sys.stdout, sys.stderr)
902
1116
# Is this a final release version? If so, we should suppress warnings
903
1117
if bzrlib.version_info[3] == 'final':
904
from bzrlib import symbol_versioning
905
symbol_versioning.suppress_deprecation_warnings(override=False)
907
user_encoding = osutils.get_user_encoding()
908
argv = [a.decode(user_encoding) for a in argv[1:]]
909
except UnicodeDecodeError:
910
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
1118
suppress_deprecation_warnings(override=True)
1120
argv = osutils.get_unicode_argv()
1124
# ensure all arguments are unicode strings
1126
if isinstance(a, unicode):
1129
new_argv.append(a.decode('ascii'))
1130
except UnicodeDecodeError:
1131
raise errors.BzrError("argv should be list of unicode strings.")
912
1133
ret = run_bzr_catch_errors(argv)
1134
bzrlib.ui.ui_factory.log_transport_activity(
1135
display=('bytes' in debug.debug_flags))
913
1136
trace.mutter("return code %d", ret)
1137
osutils.report_extension_load_failures()
917
1141
def run_bzr_catch_errors(argv):
918
# Note: The except clause logic below should be kept in sync with the
919
# profile() routine in lsprof.py.
922
except (KeyboardInterrupt, Exception), e:
923
# used to handle AssertionError and KeyboardInterrupt
924
# specially here, but hopefully they're handled ok by the logger now
925
exc_info = sys.exc_info()
926
exitcode = trace.report_exception(exc_info, sys.stderr)
927
if os.environ.get('BZR_PDB'):
928
print '**** entering debugger'
931
if sys.version_info[:2] < (2, 6):
933
# pdb.post_mortem(tb)
934
# but because pdb.post_mortem gives bad results for tracebacks
935
# from inside generators, we do it manually.
936
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
938
# Setup pdb on the traceback
941
p.setup(tb.tb_frame, tb)
942
# Point the debugger at the deepest frame of the stack
943
p.curindex = len(p.stack) - 1
944
p.curframe = p.stack[p.curindex]
945
# Start the pdb prompt.
946
p.print_stack_entry(p.stack[p.curindex])
1142
"""Run a bzr command with parameters as described by argv.
1144
This function assumed that that UI layer is setup, that symbol deprecations
1145
are already applied, and that unicode decoding has already been performed on argv.
1147
install_bzr_command_hooks()
1148
return exception_to_return_code(run_bzr, argv)
954
1151
def run_bzr_catch_user_errors(argv):