~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Joe Julian
  • Date: 2010-01-10 02:25:31 UTC
  • mto: (4634.119.7 2.0)
  • mto: This revision was merged to the branch mainline in revision 4959.
  • Revision ID: joe@julianfamily.org-20100110022531-wqk61rsagz8xsiga
Added MANIFEST.in to allow bdist_rpm to have all the required include files and tools. bdist_rpm will still fail to build correctly on some distributions due to a disttools bug http://bugs.python.org/issue644744

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
lazy_import(globals(), """
36
36
import codecs
37
37
import errno
 
38
import threading
38
39
from warnings import warn
39
40
 
40
41
import bzrlib
48
49
    )
49
50
""")
50
51
 
51
 
from bzrlib import registry
52
 
# Compatibility
53
52
from bzrlib.hooks import HookPoint, Hooks
 
53
# Compatibility - Option used to be in commands.
54
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
    )
55
61
 
56
62
 
57
63
class CommandInfo(object):
132
138
 
133
139
def _builtin_commands():
134
140
    import bzrlib.builtins
 
141
    return _scan_module_for_commands(bzrlib.builtins)
 
142
 
 
143
 
 
144
def _scan_module_for_commands(module):
135
145
    r = {}
136
 
    builtins = bzrlib.builtins.__dict__
137
 
    for name in builtins:
 
146
    for name, obj in module.__dict__.iteritems():
138
147
        if name.startswith("cmd_"):
139
148
            real_name = _unsquish_command_name(name)
140
 
            r[real_name] = builtins[name]
 
149
            r[real_name] = obj
141
150
    return r
142
151
 
143
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
 
144
172
def builtin_command_names():
145
 
    """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
    """
146
178
    return _builtin_commands().keys()
147
179
 
148
180
 
149
181
def plugin_command_names():
 
182
    """Returns command names from commands registered by plugins."""
150
183
    return plugin_cmds.keys()
151
184
 
152
185
 
153
 
def _get_cmd_dict(plugins_override=True):
154
 
    """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
    """
155
196
    d = _builtin_commands()
156
197
    if plugins_override:
157
198
        d.update(plugin_cmds.iteritems())
158
 
    return d
159
 
 
160
 
 
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():
 
199
    for k, v in d.iteritems():
164
200
        yield k,v
165
201
 
166
202
 
167
203
def get_cmd_object(cmd_name, plugins_override=True):
168
 
    """Return the canonical name and command class for a command.
 
204
    """Return the command object for a command.
169
205
 
170
206
    plugins_override
171
207
        If true, plugin commands can override builtins.
172
208
    """
173
209
    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
 
210
        return _get_cmd_object(cmd_name, plugins_override)
179
211
    except KeyError:
180
212
        raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
181
213
 
182
214
 
183
215
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
 
216
    """Get a command object.
186
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
    """
187
223
    # We want only 'ascii' command names, but the user may have typed
188
224
    # in a Unicode name. In that case, they should just get a
189
225
    # 'command not found' error later.
190
226
    # In the future, we may actually support Unicode command names.
191
 
 
192
 
    # first look up this command under the specified name
193
 
    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:
194
268
        try:
195
 
            return plugin_cmds.get(cmd_name)()
196
 
        except KeyError:
 
269
            return provider.plugin_for_command(cmd_name), provider
 
270
        except errors.NoPluginAvailable:
197
271
            pass
198
 
    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()
199
278
    try:
200
279
        return cmds[cmd_name]()
201
280
    except KeyError:
202
281
        pass
203
 
    if plugins_override:
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
282
    # look for any command which claims this as an alias
209
283
    for real_cmd_name, cmd_class in cmds.iteritems():
210
284
        if cmd_name in cmd_class.aliases:
211
285
            return cmd_class()
212
 
 
 
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
    cmd_obj = ExternalCommand.find_command(cmd_name)
214
296
    if cmd_obj:
215
297
        return cmd_obj
216
298
 
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
 
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
227
311
 
228
312
 
229
313
class Command(object):
368
452
        result += '\n'
369
453
 
370
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
371
459
        options = option.get_optparser(self.options()).format_option_help()
 
460
        # XXX: According to the spec, ReST option lists actually don't support 
 
461
        # options like --1.9 so that causes syntax errors (in Sphinx at least).
 
462
        # As that pattern always appears in the commands that break, we trap
 
463
        # on that and then format that block of 'format' options as a literal
 
464
        # block.
 
465
        if not plain and options.find('  --1.9  ') != -1:
 
466
            options = options.replace(' format:\n', ' format::\n\n', 1)
372
467
        if options.startswith('Options:'):
373
468
            result += ':' + options
374
469
        elif options.startswith('options:'):
607
702
            "Called after creating a command object to allow modifications "
608
703
            "such as adding or removing options, docs etc. Called with the "
609
704
            "new bzrlib.commands.Command object.", (1, 13), None))
 
705
        self.create_hook(HookPoint('get_command',
 
706
            "Called when creating a single command. Called with "
 
707
            "(cmd_or_None, command_name). get_command should either return "
 
708
            "the cmd_or_None parameter, or a replacement Command object that "
 
709
            "should be used for the command. Note that the Command.hooks "
 
710
            "hooks are core infrastructure. Many users will prefer to use "
 
711
            "bzrlib.commands.register_command or plugin_cmds.register_lazy.",
 
712
            (1, 17), None))
 
713
        self.create_hook(HookPoint('get_missing_command',
 
714
            "Called when creating a single command if no command could be "
 
715
            "found. Called with (command_name). get_missing_command should "
 
716
            "either return None, or a Command object to be used for the "
 
717
            "command.", (1, 17), None))
 
718
        self.create_hook(HookPoint('list_commands',
 
719
            "Called when enumerating commands. Called with a set of "
 
720
            "cmd_name strings for all the commands found so far. This set "
 
721
            " is safe to mutate - e.g. to remove a command. "
 
722
            "list_commands should return the updated set of command names.",
 
723
            (1, 17), None))
610
724
 
611
725
Command.hooks = CommandHooks()
612
726
 
682
796
 
683
797
    tracer = trace.Trace(count=1, trace=0)
684
798
    sys.settrace(tracer.globaltrace)
 
799
    threading.settrace(tracer.globaltrace)
685
800
 
686
801
    try:
687
802
        return exception_to_return_code(the_callable, *args, **kwargs)
950
1065
    return ignore_pipe
951
1066
 
952
1067
 
953
 
def main(argv):
 
1068
def install_bzr_command_hooks():
 
1069
    """Install the hooks to supply bzr's own commands."""
 
1070
    if _list_bzr_commands in Command.hooks["list_commands"]:
 
1071
        return
 
1072
    Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
 
1073
        "bzr commands")
 
1074
    Command.hooks.install_named_hook("get_command", _get_bzr_command,
 
1075
        "bzr commands")
 
1076
    Command.hooks.install_named_hook("get_command", _get_plugin_command,
 
1077
        "bzr plugin commands")
 
1078
    Command.hooks.install_named_hook("get_command", _get_external_command,
 
1079
        "bzr external command lookup")
 
1080
    Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
 
1081
        "bzr plugin-provider-db check")
 
1082
 
 
1083
 
 
1084
def main(argv=None):
 
1085
    """Main entry point of command-line interface.
 
1086
 
 
1087
    :param argv: list of unicode command-line arguments similar to sys.argv.
 
1088
        argv[0] is script name usually, it will be ignored.
 
1089
        Don't pass here sys.argv because this list contains plain strings
 
1090
        and not unicode; pass None instead.
 
1091
 
 
1092
    :return: exit code of bzr command.
 
1093
    """
954
1094
    import bzrlib.ui
955
1095
    bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
956
1096
        sys.stdin, sys.stdout, sys.stderr)
957
1097
 
958
1098
    # Is this a final release version? If so, we should suppress warnings
959
1099
    if bzrlib.version_info[3] == 'final':
960
 
        from bzrlib import symbol_versioning
961
 
        symbol_versioning.suppress_deprecation_warnings(override=False)
962
 
    try:
963
 
        user_encoding = osutils.get_user_encoding()
964
 
        argv = [a.decode(user_encoding) for a in argv[1:]]
965
 
    except UnicodeDecodeError:
966
 
        raise errors.BzrError(("Parameter '%r' is unsupported by the current "
967
 
                                                            "encoding." % a))
 
1100
        suppress_deprecation_warnings(override=True)
 
1101
    if argv is None:
 
1102
        argv = osutils.get_unicode_argv()
 
1103
    else:
 
1104
        new_argv = []
 
1105
        try:
 
1106
            # ensure all arguments are unicode strings
 
1107
            for a in argv[1:]:
 
1108
                if isinstance(a, unicode):
 
1109
                    new_argv.append(a)
 
1110
                else:
 
1111
                    new_argv.append(a.decode('ascii'))
 
1112
        except UnicodeDecodeError:
 
1113
            raise errors.BzrError("argv should be list of unicode strings.")
 
1114
        argv = new_argv
968
1115
    ret = run_bzr_catch_errors(argv)
969
1116
    trace.mutter("return code %d", ret)
970
1117
    return ret
976
1123
    This function assumed that that UI layer is setup, that symbol deprecations
977
1124
    are already applied, and that unicode decoding has already been performed on argv.
978
1125
    """
 
1126
    install_bzr_command_hooks()
979
1127
    return exception_to_return_code(run_bzr, argv)
980
1128
 
981
1129
 
985
1133
    This is used for the test suite, and might be useful for other programs
986
1134
    that want to wrap the commandline interface.
987
1135
    """
 
1136
    install_bzr_command_hooks()
988
1137
    try:
989
1138
        return run_bzr(argv)
990
1139
    except Exception, e: