~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Jonathan Lange
  • Date: 2009-06-26 08:46:52 UTC
  • mto: (4484.1.1 bring-1.16.1-back)
  • mto: This revision was merged to the branch mainline in revision 4485.
  • Revision ID: jml@canonical.com-20090626084652-x7wn8yimd3fj0j0y
Tweak NEWS slightly based on mbp's feedback.

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
52
54
from bzrlib.hooks import HookPoint, Hooks
53
 
# Compatibility - Option used to be in commands.
54
55
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
 
    )
61
56
 
62
57
 
63
58
class CommandInfo(object):
138
133
 
139
134
def _builtin_commands():
140
135
    import bzrlib.builtins
141
 
    return _scan_module_for_commands(bzrlib.builtins)
142
 
 
143
 
 
144
 
def _scan_module_for_commands(module):
145
136
    r = {}
146
 
    for name, obj in module.__dict__.iteritems():
 
137
    builtins = bzrlib.builtins.__dict__
 
138
    for name in builtins:
147
139
        if name.startswith("cmd_"):
148
140
            real_name = _unsquish_command_name(name)
149
 
            r[real_name] = obj
 
141
            r[real_name] = builtins[name]
150
142
    return r
151
143
 
152
144
 
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
 
 
172
145
def 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
 
    """
 
146
    """Return list of builtin command names."""
178
147
    return _builtin_commands().keys()
179
148
 
180
149
 
181
150
def plugin_command_names():
182
 
    """Returns command names from commands registered by plugins."""
183
151
    return plugin_cmds.keys()
184
152
 
185
153
 
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
 
    """
 
154
def _get_cmd_dict(plugins_override=True):
 
155
    """Return name->class mapping for all commands."""
196
156
    d = _builtin_commands()
197
157
    if plugins_override:
198
158
        d.update(plugin_cmds.iteritems())
199
 
    for k, v in d.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():
200
165
        yield k,v
201
166
 
202
167
 
203
168
def get_cmd_object(cmd_name, plugins_override=True):
204
 
    """Return the command object for a command.
 
169
    """Return the canonical name and command class for a command.
205
170
 
206
171
    plugins_override
207
172
        If true, plugin commands can override builtins.
208
173
    """
209
174
    try:
210
 
        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']:
 
178
            hook(cmd)
 
179
        return cmd
211
180
    except KeyError:
212
181
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
213
182
 
214
183
 
215
184
def _get_cmd_object(cmd_name, plugins_override=True):
216
 
    """Get a command object.
 
185
    """Worker for get_cmd_object which raises KeyError rather than BzrCommandError."""
 
186
    from bzrlib.externalcommand import ExternalCommand
217
187
 
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
 
    """
223
188
    # We want only 'ascii' command names, but the user may have typed
224
189
    # in a Unicode name. In that case, they should just get a
225
190
    # 'command not found' error later.
226
191
    # In the future, we may actually support Unicode command names.
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:
 
192
 
 
193
    # first look up this command under the specified name
 
194
    if plugins_override:
268
195
        try:
269
 
            return provider.plugin_for_command(cmd_name), provider
270
 
        except errors.NoPluginAvailable:
 
196
            return plugin_cmds.get(cmd_name)()
 
197
        except KeyError:
271
198
            pass
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()
 
199
    cmds = _get_cmd_dict(plugins_override=False)
278
200
    try:
279
201
        return cmds[cmd_name]()
280
202
    except KeyError:
281
203
        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)()
282
209
    # look for any command which claims this as an alias
283
210
    for real_cmd_name, cmd_class in cmds.iteritems():
284
211
        if cmd_name in cmd_class.aliases:
285
212
            return cmd_class()
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
 
213
 
295
214
    cmd_obj = ExternalCommand.find_command(cmd_name)
296
215
    if cmd_obj:
297
216
        return cmd_obj
298
217
 
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
 
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
311
228
 
312
229
 
313
230
class Command(object):
452
369
        result += '\n'
453
370
 
454
371
        # 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
459
372
        options = option.get_optparser(self.options()).format_option_help()
460
373
        if options.startswith('Options:'):
461
374
            result += ':' + options
695
608
            "Called after creating a command object to allow modifications "
696
609
            "such as adding or removing options, docs etc. Called with the "
697
610
            "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))
717
611
 
718
612
Command.hooks = CommandHooks()
719
613
 
1058
952
    return ignore_pipe
1059
953
 
1060
954
 
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
 
 
1077
955
def main(argv=None):
1078
956
    """Main entry point of command-line interface.
1079
957
 
1090
968
 
1091
969
    # Is this a final release version? If so, we should suppress warnings
1092
970
    if bzrlib.version_info[3] == 'final':
1093
 
        suppress_deprecation_warnings(override=False)
 
971
        from bzrlib import symbol_versioning
 
972
        symbol_versioning.suppress_deprecation_warnings(override=False)
1094
973
    if argv is None:
1095
974
        argv = osutils.get_unicode_argv()
1096
975
    else:
1116
995
    This function assumed that that UI layer is setup, that symbol deprecations
1117
996
    are already applied, and that unicode decoding has already been performed on argv.
1118
997
    """
1119
 
    install_bzr_command_hooks()
1120
998
    return exception_to_return_code(run_bzr, argv)
1121
999
 
1122
1000
 
1126
1004
    This is used for the test suite, and might be useful for other programs
1127
1005
    that want to wrap the commandline interface.
1128
1006
    """
1129
 
    install_bzr_command_hooks()
1130
1007
    try:
1131
1008
        return run_bzr(argv)
1132
1009
    except Exception, e: