142
134
def _builtin_commands():
143
135
import bzrlib.builtins
144
return _scan_module_for_commands(bzrlib.builtins)
147
def _scan_module_for_commands(module):
149
for name, obj in module.__dict__.iteritems():
137
builtins = bzrlib.builtins.__dict__
138
for name in builtins:
150
139
if name.startswith("cmd_"):
151
140
real_name = _unsquish_command_name(name)
141
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))
175
145
def 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
"""Return list of builtin command names."""
181
147
return _builtin_commands().keys()
184
150
def plugin_command_names():
185
"""Returns command names from commands registered by plugins."""
186
151
return plugin_cmds.keys()
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.
154
def _get_cmd_dict(plugins_override=True):
155
"""Return name->class mapping for all commands."""
199
156
d = _builtin_commands()
200
157
if plugins_override:
201
158
d.update(plugin_cmds.iteritems())
202
for k, v in d.iteritems():
162
def get_all_cmds(plugins_override=True):
163
"""Return canonical name and class for all registered commands."""
164
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
206
168
def get_cmd_object(cmd_name, plugins_override=True):
207
"""Return the command object for a command.
169
"""Return the canonical name and command class for a command.
210
172
If true, plugin commands can override builtins.
213
return _get_cmd_object(cmd_name, plugins_override)
175
cmd = _get_cmd_object(cmd_name, plugins_override)
176
# Allow plugins to extend commands
177
for hook in Command.hooks['extend_command']:
215
181
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
218
184
def _get_cmd_object(cmd_name, plugins_override=True):
219
"""Get a command object.
185
"""Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
186
from bzrlib.externalcommand import ExternalCommand
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.
226
188
# We want only 'ascii' command names, but the user may have typed
227
189
# in a Unicode name. In that case, they should just get a
228
190
# 'command not found' error later.
229
191
# In the future, we may actually support Unicode command names.
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:
193
# first look up this command under the specified name
272
return provider.plugin_for_command(cmd_name), provider
273
except errors.NoPluginAvailable:
196
return plugin_cmds.get(cmd_name)()
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()
199
cmds = _get_cmd_dict(plugins_override=False)
282
201
return cmds[cmd_name]()
205
for key in plugin_cmds.keys():
206
info = plugin_cmds.get_info(key)
207
if cmd_name in info.aliases:
208
return plugin_cmds.get(key)()
285
209
# look for any command which claims this as an alias
286
210
for real_cmd_name, cmd_class in cmds.iteritems():
287
211
if cmd_name in cmd_class.aliases:
288
212
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
298
214
cmd_obj = ExternalCommand.find_command(cmd_name)
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)()
218
# look for plugins that provide this command but aren't installed
219
for provider in command_providers_registry:
221
plugin_metadata = provider.plugin_for_command(cmd_name)
222
except errors.NoPluginAvailable:
225
raise errors.CommandAvailableInPlugin(cmd_name,
226
plugin_metadata, provider)
316
230
class Command(object):
385
299
warn("No help message set for %r" % self)
386
300
# List of standard options directly supported
387
301
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)))
411
303
def _maybe_expand_globs(self, file_list):
412
304
"""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
417
306
:return: A possibly empty list of unicode paths.
419
308
Introduced in bzrlib 0.18.
312
if sys.platform == 'win32':
313
file_list = win32utils.glob_expand(file_list)
314
return list(file_list)
423
316
def _usage(self):
424
317
"""Return single-line grammar for this command.
620
501
def _setup_outf(self):
621
502
"""Return a file linked to stdout, which has proper encoding."""
622
self.outf = ui.ui_factory.make_output_stream(
623
encoding_type=self.encoding_type)
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
625
524
def run_argv_aliases(self, argv, alias_argv=None):
626
525
"""Parse the command line and run with extra aliases in alias_argv."""
713
608
"Called after creating a command object to allow modifications "
714
609
"such as adding or removing options, docs etc. Called with the "
715
610
"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.",
736
612
Command.hooks = CommandHooks()