/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/commands.py

  • Committer: Jelmer Vernooij
  • Date: 2019-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
from .lazy_import import lazy_import
36
36
lazy_import(globals(), """
37
37
import errno
38
 
import threading
39
38
 
40
39
import breezy
41
40
from breezy import (
42
 
    config,
43
41
    cleanup,
44
42
    cmdline,
45
43
    debug,
56
54
from . import errors, registry
57
55
from .sixish import (
58
56
    string_types,
59
 
    text_type,
60
 
    viewvalues,
61
57
    )
62
58
 
63
59
 
102
98
 
103
99
class CommandRegistry(registry.Registry):
104
100
    """Special registry mapping command names to command classes.
105
 
    
 
101
 
106
102
    :ivar overridden_registry: Look in this registry for commands being
107
103
        overridden by this registry.  This can be used to tell plugin commands
108
104
        about the builtin they're decorating.
151
147
        except KeyError:
152
148
            trace.warning('Two plugins defined the same command: %r' % k)
153
149
            trace.warning('Not loading the one in %r' %
154
 
                sys.modules[cmd.__module__])
 
150
                          sys.modules[cmd.__module__])
155
151
            trace.warning('Previously this command was registered from %r' %
156
 
                sys.modules[previous.__module__])
 
152
                          sys.modules[previous.__module__])
157
153
        for a in cmd.aliases:
158
154
            self._alias_dict[a] = k_unsquished
159
155
        return previous
180
176
def register_command(cmd, decorate=False):
181
177
    """Register a plugin command.
182
178
 
183
 
    Should generally be avoided in favor of lazy registration. 
 
179
    Should generally be avoided in favor of lazy registration.
184
180
    """
185
181
    global plugin_cmds
186
182
    return plugin_cmds.register(cmd, decorate)
213
209
 
214
210
def _list_bzr_commands(names):
215
211
    """Find commands from bzr's core and plugins.
216
 
    
217
 
    This is not the public interface, just the default hook called by all_command_names.
 
212
 
 
213
    This is not the public interface, just the default hook called by
 
214
    all_command_names.
218
215
    """
219
216
    # to eliminate duplicates
220
217
    names.update(builtin_command_names())
235
232
 
236
233
def builtin_command_names():
237
234
    """Return list of builtin command names.
238
 
    
 
235
 
239
236
    Use of all_command_names() is encouraged rather than builtin_command_names
240
237
    and/or plugin_command_names.
241
238
    """
250
247
 
251
248
# Overrides for common mispellings that heuristics get wrong
252
249
_GUESS_OVERRIDES = {
253
 
    'ic': {'ci': 0}, # heuristic finds nick
 
250
    'ic': {'ci': 0},  # heuristic finds nick
254
251
    }
255
252
 
256
253
 
267
264
        names.update(cmd.aliases)
268
265
    # candidate: modified levenshtein distance against cmd_name.
269
266
    costs = {}
270
 
    from . import patiencediff
 
267
    import patiencediff
271
268
    for name in sorted(names):
272
269
        matcher = patiencediff.PatienceSequenceMatcher(None, cmd_name, name)
273
270
        distance = 0.0
274
271
        opcodes = matcher.get_opcodes()
275
272
        for opcode, l1, l2, r1, r2 in opcodes:
276
273
            if opcode == 'delete':
277
 
                distance += l2-l1
 
274
                distance += l2 - l1
278
275
            elif opcode == 'replace':
279
 
                distance += max(l2-l1, r2-l1)
 
276
                distance += max(l2 - l1, r2 - l1)
280
277
            elif opcode == 'insert':
281
 
                distance += r2-r1
 
278
                distance += r2 - r1
282
279
            elif opcode == 'equal':
283
280
                # Score equal ranges lower, making similar commands of equal
284
281
                # length closer than arbitrary same length commands.
285
 
                distance -= 0.1 * (l2-l1)
 
282
                distance -= 0.1 * (l2 - l1)
286
283
        costs[name] = distance
287
284
    costs.update(_GUESS_OVERRIDES.get(cmd_name, {}))
288
285
    costs = sorted((costs[key], key) for key in costs)
307
304
        candidate = guess_command(cmd_name)
308
305
        if candidate is not None:
309
306
            raise errors.BzrCommandError(
310
 
                    gettext('unknown command "%s". Perhaps you meant "%s"')
311
 
                    % (cmd_name, candidate))
 
307
                gettext('unknown command "%s". Perhaps you meant "%s"')
 
308
                % (cmd_name, candidate))
312
309
        raise errors.BzrCommandError(gettext('unknown command "%s"')
313
 
                % cmd_name)
 
310
                                     % cmd_name)
314
311
 
315
312
 
316
313
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):
585
582
        # XXX: optparse implicitly rewraps the help, and not always perfectly,
586
583
        # so we get <https://bugs.launchpad.net/bzr/+bug/249908>.  -- mbp
587
584
        # 20090319
588
 
        parser = option.get_optparser([v for k, v in sorted(self.options().items())])
 
585
        parser = option.get_optparser(
 
586
            [v for k, v in sorted(self.options().items())])
589
587
        options = parser.format_option_help()
590
588
        # FIXME: According to the spec, ReST option lists actually don't
591
589
        # support options like --1.14 so that causes syntax errors (in Sphinx
618
616
                result += '\n'
619
617
        else:
620
618
            result += (gettext("See brz help %s for more details and examples.\n\n")
621
 
                % self.name())
 
619
                       % self.name())
622
620
 
623
621
        # Add the aliases, source (plug-in) and see also links, if any
624
622
        if self.aliases:
639
637
                    else:
640
638
                        # Use a Sphinx link for this entry
641
639
                        link_text = gettext(":doc:`{0} <{1}-help>`").format(
642
 
                                                                    item, item)
 
640
                            item, item)
643
641
                        see_also_links.append(link_text)
644
642
                see_also = see_also_links
645
643
            result += gettext(':See also: %s') % ', '.join(see_also) + '\n'
679
677
            if line.startswith(':') and line.endswith(':') and len(line) > 2:
680
678
                save_section(sections, order, label, section)
681
679
                label, section = line[1:-1], ''
682
 
            elif (label is not None) and len(line) > 1 and not line[0].isspace():
 
680
            elif (label is not None and len(line) > 1 and
 
681
                    not line[0].isspace()):
683
682
                save_section(sections, order, label, section)
684
683
                label, section = None, line
685
684
            else:
776
775
        you can override this method.
777
776
        """
778
777
        class_run = self.run
 
778
 
779
779
        def run(*args, **kwargs):
780
780
            for hook in Command.hooks['pre_command']:
781
781
                hook(self)
798
798
        shell error code if not.  It's OK for this method to allow
799
799
        an exception to raise up.
800
800
 
801
 
        This method is automatically wrapped by Command.__init__ with a 
 
801
        This method is automatically wrapped by Command.__init__ with a
802
802
        cleanup operation, stored as self._operation. This can be used
803
803
        via self.add_cleanup to perform automatic cleanups at the end of
804
804
        run().
830
830
    def name(self):
831
831
        """Return the canonical name for this command.
832
832
 
833
 
        The name under which it was actually invoked is available in invoked_as.
 
833
        The name under which it was actually invoked is available in invoked_as
834
834
        """
835
835
        return _unsquish_command_name(self.__class__.__name__)
836
836
 
852
852
        notified.
853
853
        """
854
854
        Hooks.__init__(self, "breezy.commands", "Command.hooks")
855
 
        self.add_hook('extend_command',
 
855
        self.add_hook(
 
856
            'extend_command',
856
857
            "Called after creating a command object to allow modifications "
857
858
            "such as adding or removing options, docs etc. Called with the "
858
859
            "new breezy.commands.Command object.", (1, 13))
859
 
        self.add_hook('get_command',
 
860
        self.add_hook(
 
861
            'get_command',
860
862
            "Called when creating a single command. Called with "
861
863
            "(cmd_or_None, command_name). get_command should either return "
862
864
            "the cmd_or_None parameter, or a replacement Command object that "
864
866
            "hooks are core infrastructure. Many users will prefer to use "
865
867
            "breezy.commands.register_command or plugin_cmds.register_lazy.",
866
868
            (1, 17))
867
 
        self.add_hook('get_missing_command',
 
869
        self.add_hook(
 
870
            'get_missing_command',
868
871
            "Called when creating a single command if no command could be "
869
872
            "found. Called with (command_name). get_missing_command should "
870
873
            "either return None, or a Command object to be used for the "
871
874
            "command.", (1, 17))
872
 
        self.add_hook('list_commands',
 
875
        self.add_hook(
 
876
            'list_commands',
873
877
            "Called when enumerating commands. Called with a set of "
874
878
            "cmd_name strings for all the commands found so far. This set "
875
879
            " is safe to mutate - e.g. to remove a command. "
876
880
            "list_commands should return the updated set of command names.",
877
881
            (1, 17))
878
 
        self.add_hook('pre_command',
 
882
        self.add_hook(
 
883
            'pre_command',
879
884
            "Called prior to executing a command. Called with the command "
880
885
            "object.", (2, 6))
881
 
        self.add_hook('post_command',
 
886
        self.add_hook(
 
887
            'post_command',
882
888
            "Called after executing a command. Called with the command "
883
889
            "object.", (2, 6))
884
890
 
 
891
 
885
892
Command.hooks = CommandHooks()
886
893
 
887
894
 
895
902
    """
896
903
    # TODO: make it a method of the Command?
897
904
    parser = option.get_optparser(
898
 
            [v for k, v in sorted(command.options().items())])
 
905
        [v for k, v in sorted(command.options().items())])
899
906
    if alias_argv is not None:
900
907
        args = alias_argv + argv
901
908
    else:
905
912
    # option name is given.  See http://bugs.python.org/issue2931
906
913
    try:
907
914
        options, args = parser.parse_args(args)
908
 
    except UnicodeEncodeError as e:
 
915
    except UnicodeEncodeError:
909
916
        raise errors.BzrCommandError(
910
917
            gettext('Only ASCII permitted in option names'))
911
918
 
923
930
        if ap[-1] == '?':
924
931
            if args:
925
932
                argdict[argname] = args.pop(0)
926
 
        elif ap[-1] == '*': # all remaining arguments
 
933
        elif ap[-1] == '*':  # all remaining arguments
927
934
            if args:
928
935
                argdict[argname + '_list'] = args[:]
929
936
                args = []
932
939
        elif ap[-1] == '+':
933
940
            if not args:
934
941
                raise errors.BzrCommandError(gettext(
935
 
                      "command {0!r} needs one or more {1}").format(
936
 
                      cmd, argname.upper()))
 
942
                    "command {0!r} needs one or more {1}").format(
 
943
                    cmd, argname.upper()))
937
944
            else:
938
945
                argdict[argname + '_list'] = args[:]
939
946
                args = []
940
 
        elif ap[-1] == '$': # all but one
 
947
        elif ap[-1] == '$':  # all but one
941
948
            if len(args) < 2:
942
949
                raise errors.BzrCommandError(
943
 
                      gettext("command {0!r} needs one or more {1}").format(
944
 
                                             cmd, argname.upper()))
 
950
                    gettext("command {0!r} needs one or more {1}").format(
 
951
                        cmd, argname.upper()))
945
952
            argdict[argname + '_list'] = args[:-1]
946
953
            args[:-1] = []
947
954
        else:
949
956
            argname = ap
950
957
            if not args:
951
958
                raise errors.BzrCommandError(
952
 
                     gettext("command {0!r} requires argument {1}").format(
953
 
                               cmd, argname.upper()))
 
959
                    gettext("command {0!r} requires argument {1}").format(
 
960
                        cmd, argname.upper()))
954
961
            else:
955
962
                argdict[argname] = args.pop(0)
956
963
 
957
964
    if args:
958
 
        raise errors.BzrCommandError( gettext(
959
 
                              "extra argument to command {0}: {1}").format(
960
 
                                       cmd, args[0]) )
 
965
        raise errors.BzrCommandError(gettext(
 
966
            "extra argument to command {0}: {1}").format(
 
967
            cmd, args[0]))
961
968
 
962
969
    return argdict
963
970
 
983
990
        prof = hotshot.Profile(pfname)
984
991
        try:
985
992
            ret = prof.runcall(exception_to_return_code, the_callable, *args,
986
 
                **kwargs) or 0
 
993
                               **kwargs) or 0
987
994
        finally:
988
995
            prof.close()
989
996
        stats = hotshot.stats.load(pfname)
990
997
        stats.strip_dirs()
991
998
        stats.sort_stats('cum')   # 'time'
992
 
        ## XXX: Might like to write to stderr or the trace file instead but
993
 
        ## print_stats seems hardcoded to stdout
 
999
        # XXX: Might like to write to stderr or the trace file instead but
 
1000
        # print_stats seems hardcoded to stdout
994
1001
        stats.print_stats(20)
995
1002
        return ret
996
1003
    finally:
1007
1014
    """
1008
1015
    try:
1009
1016
        return the_callable(*args, **kwargs)
1010
 
    except (KeyboardInterrupt, Exception) as e:
 
1017
    except (KeyboardInterrupt, Exception):
1011
1018
        # used to handle AssertionError and KeyboardInterrupt
1012
1019
        # specially here, but hopefully they're handled ok by the logger now
1013
1020
        exc_info = sys.exc_info()
1090
1097
        Generate code coverage report
1091
1098
 
1092
1099
    --concurrency
1093
 
        Specify the number of processes that can be run concurrently (selftest).
 
1100
        Specify the number of processes that can be run concurrently
 
1101
        (selftest).
1094
1102
    """
1095
1103
    trace.mutter("breezy version: " + breezy.__version__)
1096
1104
    argv = _specified_or_unicode_argv(argv)
1097
1105
    trace.mutter("brz arguments: %r", argv)
1098
1106
 
1099
1107
    opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
1100
 
            opt_coverage = opt_no_l10n = opt_no_aliases = False
 
1108
        opt_coverage = opt_no_l10n = opt_no_aliases = False
1101
1109
    opt_lsprof_file = None
1102
1110
 
1103
1111
    # --no-plugins is handled specially at a very early stage. We need
1131
1139
        elif a == '--coverage':
1132
1140
            opt_coverage = True
1133
1141
        elif a == '--profile-imports':
1134
 
            pass # already handled in startup script Bug #588277
 
1142
            pass  # already handled in startup script Bug #588277
1135
1143
        elif a.startswith('-D'):
1136
1144
            debug.debug_flags.add(a[2:])
1137
1145
        elif a.startswith('-O'):
1200
1208
        if 'memory' in debug.debug_flags:
1201
1209
            trace.debug_memory('Process status after command:', short=False)
1202
1210
        option._verbosity_level = saved_verbosity_level
1203
 
        # Reset the overrides 
 
1211
        # Reset the overrides
1204
1212
        cmdline_overrides._reset()
1205
1213
 
1206
1214
 
1229
1237
    if _list_bzr_commands in Command.hooks["list_commands"]:
1230
1238
        return
1231
1239
    Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1232
 
        "bzr commands")
 
1240
                                     "bzr commands")
1233
1241
    Command.hooks.install_named_hook("get_command", _get_bzr_command,
1234
 
        "bzr commands")
 
1242
                                     "bzr commands")
1235
1243
    Command.hooks.install_named_hook("get_command", _get_plugin_command,
1236
 
        "bzr plugin commands")
 
1244
                                     "bzr plugin commands")
1237
1245
    Command.hooks.install_named_hook("get_command", _get_external_command,
1238
 
        "bzr external command lookup")
 
1246
                                     "bzr external command lookup")
1239
1247
    Command.hooks.install_named_hook("get_missing_command",
1240
1248
                                     _try_plugin_provider,
1241
1249
                                     "bzr plugin-provider-db check")
1242
1250
 
1243
1251
 
1244
 
 
1245
1252
def _specified_or_unicode_argv(argv):
1246
1253
    # For internal or testing use, argv can be passed.  Otherwise, get it from
1247
1254
    # the process arguments in a unicode-safe way.
1286
1293
    """Run a bzr command with parameters as described by argv.
1287
1294
 
1288
1295
    This function assumed that that UI layer is setup, that symbol deprecations
1289
 
    are already applied, and that unicode decoding has already been performed on argv.
 
1296
    are already applied, and that unicode decoding has already been performed
 
1297
    on argv.
1290
1298
    """
1291
1299
    # done here so that they're covered for every test run
1292
1300
    install_bzr_command_hooks()
1305
1313
        return run_bzr(argv)
1306
1314
    except Exception as e:
1307
1315
        if (isinstance(e, (OSError, IOError))
1308
 
            or not getattr(e, 'internal_error', True)):
 
1316
                or not getattr(e, 'internal_error', True)):
1309
1317
            trace.report_exception(sys.exc_info(), sys.stderr)
1310
1318
            return 3
1311
1319
        else:
1354
1362
        for key, provider in self.items():
1355
1363
            yield provider
1356
1364
 
 
1365
 
1357
1366
command_providers_registry = ProvidersRegistry()