~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-06-30 05:12:27 UTC
  • mfrom: (4490.1.2 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090630051227-ncar0w60u6cbyydk
(mbp) force deletion of readonly files from TreeTransform

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
    )
50
50
""")
51
51
 
52
 
from bzrlib import registry
53
 
# Compatibility
54
52
from bzrlib.hooks import HookPoint, Hooks
 
53
# Compatibility - Option used to be in commands.
55
54
from bzrlib.option import Option
 
55
from bzrlib import registry
 
56
from bzrlib.symbol_versioning import (
 
57
    deprecated_function,
 
58
    deprecated_in,
 
59
    suppress_deprecation_warnings,
 
60
    )
56
61
 
57
62
 
58
63
class CommandInfo(object):
133
138
 
134
139
def _builtin_commands():
135
140
    import bzrlib.builtins
 
141
    return _scan_module_for_commands(bzrlib.builtins)
 
142
 
 
143
 
 
144
def _scan_module_for_commands(module):
136
145
    r = {}
137
 
    builtins = bzrlib.builtins.__dict__
138
 
    for name in builtins:
 
146
    for name, obj in module.__dict__.iteritems():
139
147
        if name.startswith("cmd_"):
140
148
            real_name = _unsquish_command_name(name)
141
 
            r[real_name] = builtins[name]
 
149
            r[real_name] = obj
142
150
    return r
143
151
 
144
152
 
 
153
def _list_bzr_commands(names):
 
154
    """Find commands from bzr's core and plugins."""
 
155
    # to eliminate duplicates
 
156
    names.update(builtin_command_names())
 
157
    names.update(plugin_command_names())
 
158
    return names
 
159
 
 
160
 
 
161
def all_command_names():
 
162
    """Return a set of all command names."""
 
163
    names = set()
 
164
    for hook in Command.hooks['list_commands']:
 
165
        names = hook(names)
 
166
        if names is None:
 
167
            raise AssertionError(
 
168
                'hook %s returned None' % Command.hooks.get_hook_name(hook))
 
169
    return names
 
170
 
 
171
 
145
172
def builtin_command_names():
146
 
    """Return list of builtin command names."""
 
173
    """Return list of builtin command names.
 
174
    
 
175
    Use of all_command_names() is encouraged rather than builtin_command_names
 
176
    and/or plugin_command_names.
 
177
    """
147
178
    return _builtin_commands().keys()
148
179
 
149
180
 
150
181
def plugin_command_names():
 
182
    """Returns command names from commands registered by plugins."""
151
183
    return plugin_cmds.keys()
152
184
 
153
185
 
154
 
def _get_cmd_dict(plugins_override=True):
155
 
    """Return name->class mapping for all commands."""
 
186
@deprecated_function(deprecated_in((1, 17, 0)))
 
187
def get_all_cmds(plugins_override=False):
 
188
    """Return canonical name and class for most commands.
 
189
    
 
190
    NB: This does not return all commands since the introduction of
 
191
    command hooks, and returning the class is not sufficient to 
 
192
    get correctly setup commands, which is why it is deprecated.
 
193
 
 
194
    Use 'all_command_names' + 'get_cmd_object' instead.
 
195
    """
156
196
    d = _builtin_commands()
157
197
    if plugins_override:
158
198
        d.update(plugin_cmds.iteritems())
159
 
    return d
160
 
 
161
 
 
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():
 
199
    for k, v in d.iteritems():
165
200
        yield k,v
166
201
 
167
202
 
168
203
def get_cmd_object(cmd_name, plugins_override=True):
169
 
    """Return the canonical name and command class for a command.
 
204
    """Return the command object for a command.
170
205
 
171
206
    plugins_override
172
207
        If true, plugin commands can override builtins.
173
208
    """
174
209
    try:
175
 
        cmd = _get_cmd_object(cmd_name, plugins_override)
176
 
        # Allow plugins to extend commands
177
 
        for hook in Command.hooks['extend_command']:
178
 
            hook(cmd)
179
 
        return cmd
 
210
        return _get_cmd_object(cmd_name, plugins_override)
180
211
    except KeyError:
181
212
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
182
213
 
183
214
 
184
215
def _get_cmd_object(cmd_name, plugins_override=True):
185
 
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
186
 
    from bzrlib.externalcommand import ExternalCommand
 
216
    """Get a command object.
187
217
 
 
218
    :param cmd_name: The name of the command.
 
219
    :param plugins_override: Allow plugins to override builtins.
 
220
    :return: A Command object instance
 
221
    :raises KeyError: If no command is found.
 
222
    """
188
223
    # We want only 'ascii' command names, but the user may have typed
189
224
    # in a Unicode name. In that case, they should just get a
190
225
    # 'command not found' error later.
191
226
    # In the future, we may actually support Unicode command names.
192
 
 
193
 
    # first look up this command under the specified name
194
 
    if plugins_override:
 
227
    cmd = None
 
228
    # Get a command
 
229
    for hook in Command.hooks['get_command']:
 
230
        cmd = hook(cmd, cmd_name)
 
231
        if cmd is not None and not plugins_override and not cmd.plugin_name():
 
232
            # We've found a non-plugin command, don't permit it to be
 
233
            # overridden.
 
234
            break
 
235
    if cmd is None:
 
236
        for hook in Command.hooks['get_missing_command']:
 
237
            cmd = hook(cmd_name)
 
238
            if cmd is not None:
 
239
                break
 
240
    if cmd is None:
 
241
        # No command found.
 
242
        raise KeyError
 
243
    # Allow plugins to extend commands
 
244
    for hook in Command.hooks['extend_command']:
 
245
        hook(cmd)
 
246
    return cmd
 
247
 
 
248
 
 
249
def _try_plugin_provider(cmd_name):
 
250
    """Probe for a plugin provider having cmd_name."""
 
251
    try:
 
252
        plugin_metadata, provider = probe_for_provider(cmd_name)
 
253
        raise errors.CommandAvailableInPlugin(cmd_name,
 
254
            plugin_metadata, provider)
 
255
    except errors.NoPluginAvailable:
 
256
        pass
 
257
 
 
258
 
 
259
def probe_for_provider(cmd_name):
 
260
    """Look for a provider for cmd_name.
 
261
 
 
262
    :param cmd_name: The command name.
 
263
    :return: plugin_metadata, provider for getting cmd_name.
 
264
    :raises NoPluginAvailable: When no provider can supply the plugin.
 
265
    """
 
266
    # look for providers that provide this command but aren't installed
 
267
    for provider in command_providers_registry:
195
268
        try:
196
 
            return plugin_cmds.get(cmd_name)()
197
 
        except KeyError:
 
269
            return provider.plugin_for_command(cmd_name), provider
 
270
        except errors.NoPluginAvailable:
198
271
            pass
199
 
    cmds = _get_cmd_dict(plugins_override=False)
 
272
    raise errors.NoPluginAvailable(cmd_name)
 
273
 
 
274
 
 
275
def _get_bzr_command(cmd_or_None, cmd_name):
 
276
    """Get a command from bzr's core."""
 
277
    cmds = _builtin_commands()
200
278
    try:
201
279
        return cmds[cmd_name]()
202
280
    except KeyError:
203
281
        pass
204
 
    if plugins_override:
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)()
209
282
    # look for any command which claims this as an alias
210
283
    for real_cmd_name, cmd_class in cmds.iteritems():
211
284
        if cmd_name in cmd_class.aliases:
212
285
            return cmd_class()
213
 
 
 
286
    return cmd_or_None
 
287
 
 
288
 
 
289
def _get_external_command(cmd_or_None, cmd_name):
 
290
    """Lookup a command that is a shell script."""
 
291
    # Only do external command lookups when no command is found so far.
 
292
    if cmd_or_None is not None:
 
293
        return cmd_or_None
 
294
    from bzrlib.externalcommand import ExternalCommand
214
295
    cmd_obj = ExternalCommand.find_command(cmd_name)
215
296
    if cmd_obj:
216
297
        return cmd_obj
217
298
 
218
 
    # look for plugins that provide this command but aren't installed
219
 
    for provider in command_providers_registry:
220
 
        try:
221
 
            plugin_metadata = provider.plugin_for_command(cmd_name)
222
 
        except errors.NoPluginAvailable:
223
 
            pass
224
 
        else:
225
 
            raise errors.CommandAvailableInPlugin(cmd_name,
226
 
                                                  plugin_metadata, provider)
227
 
    raise KeyError
 
299
 
 
300
def _get_plugin_command(cmd_or_None, cmd_name):
 
301
    """Get a command from bzr's plugins."""
 
302
    try:
 
303
        return plugin_cmds.get(cmd_name)()
 
304
    except KeyError:
 
305
        pass
 
306
    for key in plugin_cmds.keys():
 
307
        info = plugin_cmds.get_info(key)
 
308
        if cmd_name in info.aliases:
 
309
            return plugin_cmds.get(key)()
 
310
    return cmd_or_None
228
311
 
229
312
 
230
313
class Command(object):
369
452
        result += '\n'
370
453
 
371
454
        # Add the options
 
455
        #
 
456
        # XXX: optparse implicitly rewraps the help, and not always perfectly,
 
457
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
 
458
        # 20090319
372
459
        options = option.get_optparser(self.options()).format_option_help()
373
460
        if options.startswith('Options:'):
374
461
            result += ':' + options
608
695
            "Called after creating a command object to allow modifications "
609
696
            "such as adding or removing options, docs etc. Called with the "
610
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.",
 
705
            (1, 17), None))
 
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.",
 
716
            (1, 17), None))
611
717
 
612
718
Command.hooks = CommandHooks()
613
719
 
952
1058
    return ignore_pipe
953
1059
 
954
1060
 
 
1061
def install_bzr_command_hooks():
 
1062
    """Install the hooks to supply bzr's own commands."""
 
1063
    if _list_bzr_commands in Command.hooks["list_commands"]:
 
1064
        return
 
1065
    Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
 
1066
        "bzr commands")
 
1067
    Command.hooks.install_named_hook("get_command", _get_bzr_command,
 
1068
        "bzr commands")
 
1069
    Command.hooks.install_named_hook("get_command", _get_plugin_command,
 
1070
        "bzr plugin commands")
 
1071
    Command.hooks.install_named_hook("get_command", _get_external_command,
 
1072
        "bzr external command lookup")
 
1073
    Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
 
1074
        "bzr plugin-provider-db check")
 
1075
 
 
1076
 
955
1077
def main(argv=None):
956
1078
    """Main entry point of command-line interface.
957
1079
 
968
1090
 
969
1091
    # Is this a final release version? If so, we should suppress warnings
970
1092
    if bzrlib.version_info[3] == 'final':
971
 
        from bzrlib import symbol_versioning
972
 
        symbol_versioning.suppress_deprecation_warnings(override=False)
 
1093
        suppress_deprecation_warnings(override=False)
973
1094
    if argv is None:
974
1095
        argv = osutils.get_unicode_argv()
975
1096
    else:
995
1116
    This function assumed that that UI layer is setup, that symbol deprecations
996
1117
    are already applied, and that unicode decoding has already been performed on argv.
997
1118
    """
 
1119
    install_bzr_command_hooks()
998
1120
    return exception_to_return_code(run_bzr, argv)
999
1121
 
1000
1122
 
1004
1126
    This is used for the test suite, and might be useful for other programs
1005
1127
    that want to wrap the commandline interface.
1006
1128
    """
 
1129
    install_bzr_command_hooks()
1007
1130
    try:
1008
1131
        return run_bzr(argv)
1009
1132
    except Exception, e: