~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Robert Collins
  • Date: 2009-03-12 23:04:45 UTC
  • mto: This revision was merged to the branch mainline in revision 4441.
  • Revision ID: robertc@robertcollins.net-20090312230445-wu5x0s0z9jrenu2y
Add Command lookup hooks: list_commands and get_command.

Show diffs side-by-side

added added

removed removed

Lines of Context:
141
141
    return r
142
142
 
143
143
 
 
144
def all_command_names():
 
145
    """Return a list of all command names."""
 
146
    # to eliminate duplicates
 
147
    names = set(builtin_command_names())
 
148
    names.update(plugin_command_names())
 
149
    for hook in Command.hooks['list_commands']:
 
150
        new_names = hook(names)
 
151
        if new_names is None:
 
152
            raise AssertionError(
 
153
                'hook %s returned None' % Command.hooks.get_hook_name(hook))
 
154
        names = new_names
 
155
    return names
 
156
 
 
157
 
144
158
def builtin_command_names():
145
 
    """Return list of builtin command names."""
 
159
    """Return list of builtin command names.
 
160
    
 
161
    Use of all_command_names() is encouraged rather than builtin_command_names
 
162
    and/or plugin_command_names.
 
163
    """
146
164
    return _builtin_commands().keys()
147
165
 
148
166
 
149
167
def plugin_command_names():
 
168
    """Returns command names from commands registered by plugins."""
150
169
    return plugin_cmds.keys()
151
170
 
152
171
 
165
184
 
166
185
 
167
186
def get_cmd_object(cmd_name, plugins_override=True):
168
 
    """Return the canonical name and command class for a command.
 
187
    """Return the command object for a command.
169
188
 
170
189
    plugins_override
171
190
        If true, plugin commands can override builtins.
172
191
    """
173
192
    try:
174
 
        cmd = _get_cmd_object(cmd_name, plugins_override)
175
 
        # Allow plugins to extend commands
176
 
        for hook in Command.hooks['extend_command']:
177
 
            hook(cmd)
178
 
        return cmd
 
193
        return _get_cmd_object(cmd_name, plugins_override)
179
194
    except KeyError:
180
195
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
181
196
 
182
197
 
183
198
def _get_cmd_object(cmd_name, plugins_override=True):
 
199
    """Get a command object.
 
200
 
 
201
    :param cmd_name: The name of the command.
 
202
    :param plugins_override: Allow plugins to override builtins.
 
203
    :return: A Command object instance
 
204
    :raises: KeyError if no command is found.
 
205
    """
 
206
    # Pre-hook command lookup logic.
 
207
    cmd = __get_cmd_object(cmd_name, plugins_override)
 
208
    # Allow hooks to supply/replace commands:
 
209
    for hook in Command.hooks['get_command']:
 
210
        cmd = hook(cmd, cmd_name)
 
211
    if cmd is None:
 
212
        try:
 
213
            plugin_metadata, provider = probe_for_provider(cmd_name)
 
214
            raise errors.CommandAvailableInPlugin(cmd_name,
 
215
                plugin_metadata, provider)
 
216
        except errors.NoPluginAvailable:
 
217
            pass
 
218
        # No command found.
 
219
        raise KeyError
 
220
    # Allow plugins to extend commands
 
221
    for hook in Command.hooks['extend_command']:
 
222
        hook(cmd)
 
223
    return cmd
 
224
 
 
225
 
 
226
def probe_for_provider(cmd_name):
 
227
    """Look for a provider for cmd_name.
 
228
 
 
229
    :param cmd_name: The command name.
 
230
    :return: plugin_metadata, provider for getting cmd_name.
 
231
    :raises NoPluginAvailable: When no provider can supply the plugin.
 
232
    """
 
233
    # look for providers that provide this command but aren't installed
 
234
    for provider in command_providers_registry:
 
235
        try:
 
236
            return provider.plugin_for_command(cmd_name), provider
 
237
        except errors.NoPluginAvailable:
 
238
            pass
 
239
    raise errors.NoPluginAvailable(cmd_name)
 
240
 
 
241
 
 
242
def __get_cmd_object(cmd_name, plugins_override):
184
243
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
185
244
    from bzrlib.externalcommand import ExternalCommand
186
245
 
213
272
    cmd_obj = ExternalCommand.find_command(cmd_name)
214
273
    if cmd_obj:
215
274
        return cmd_obj
216
 
 
217
 
    # look for plugins that provide this command but aren't installed
218
 
    for provider in command_providers_registry:
219
 
        try:
220
 
            plugin_metadata = provider.plugin_for_command(cmd_name)
221
 
        except errors.NoPluginAvailable:
222
 
            pass
223
 
        else:
224
 
            raise errors.CommandAvailableInPlugin(cmd_name,
225
 
                                                  plugin_metadata, provider)
226
 
    raise KeyError
 
275
    return None
227
276
 
228
277
 
229
278
class Command(object):
595
644
            "Called after creating a command object to allow modifications "
596
645
            "such as adding or removing options, docs etc. Called with the "
597
646
            "new bzrlib.commands.Command object.", (1, 13), None))
 
647
        self.create_hook(HookPoint('get_command',
 
648
            "Called when creating a single command. Called with "
 
649
            "(cmd_or_None, command_name). get_command should either return "
 
650
            "the cmd_or_None parameter, or a replacement Command object that "
 
651
            "should be used for the command.", (1, 14), None))
 
652
        self.create_hook(HookPoint('list_commands',
 
653
            "Called when enumerating commands. Called with a dict of "
 
654
            "cmd_name: cmd_class tuples for all the commands found "
 
655
            "so far. This dict is safe to mutate - to remove a command or "
 
656
            "to replace it with another (eg plugin supplied) version. "
 
657
            "list_commands should return the updated dict of commands.",
 
658
            (1, 14), None))
598
659
 
599
660
Command.hooks = CommandHooks()
600
661