Rev 5111: (mbp) allow builtin commands to be lazy loaded; make bundle-info lazy in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Mar 25 06:52:41 GMT 2010
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5111 [merge]
revision-id: pqm at pqm.ubuntu.com-20100325065238-0mser11okatoq0yz
parent: pqm at pqm.ubuntu.com-20100325000251-bwsv5c5d3l9x3lnn
parent: mbp at canonical.com-20100325060216-mwaldgns6nvrl91m
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2010-03-25 06:52:38 +0000
message:
(mbp) allow builtin commands to be lazy loaded; make bundle-info lazy
modified:
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/tests/test_commands.py test_command.py-20051019190109-3b17be0f52eaa7a8
bzrlib/tests/test_import_tariff.py test_import_tariff.p-20100207155145-ff9infp7goncs7zh-1
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py 2010-03-22 13:59:33 +0000
+++ b/bzrlib/builtins.py 2010-03-25 06:52:38 +0000
@@ -5974,15 +5974,7 @@
self.outf.write('%s %s\n' % (path, location))
-# these get imported and then picked up by the scan for cmd_*
-# TODO: Some more consistent way to split command definitions across files;
-# we do need to load at least some information about them to know of
-# aliases. ideally we would avoid loading the implementation until the
-# details were needed.
from bzrlib.cmd_version_info import cmd_version_info
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
-from bzrlib.bundle.commands import (
- cmd_bundle_info,
- )
from bzrlib.foreign import cmd_dpush
from bzrlib.sign_my_commits import cmd_sign_my_commits
=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py 2010-03-01 09:27:39 +0000
+++ b/bzrlib/commands.py 2010-03-25 06:52:38 +0000
@@ -15,9 +15,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-# TODO: probably should say which arguments are candidates for glob
-# expansion on windows and do that at the command level.
-
# TODO: Define arguments by objects, rather than just using names.
# Those objects can specify the expected type of the argument, which
# would help with validation and shell completion. They could also provide
@@ -25,9 +22,6 @@
# TODO: Specific "examples" property on commands for consistent formatting.
-# TODO: "--profile=cum", to change sort order. Is there any value in leaving
-# the profile output behind so it can be interactively examined?
-
import os
import sys
@@ -78,6 +72,22 @@
class CommandRegistry(registry.Registry):
+ """Special registry mapping command names to command classes.
+
+ :ivar overridden_registry: Look in this registry for commands being
+ overridden by this registry. This can be used to tell plugin commands
+ about the builtin they're decorating.
+ """
+
+ def __init__(self):
+ registry.Registry.__init__(self)
+ self.overridden_registry = None
+ # map from aliases to the real command that implements the name
+ self._alias_dict = {}
+
+ def get(self, command_name):
+ real_name = self._alias_dict.get(command_name, command_name)
+ return registry.Registry.get(self, real_name)
@staticmethod
def _get_name(command_name):
@@ -99,7 +109,12 @@
try:
previous = self.get(k_unsquished)
except KeyError:
- previous = _builtin_commands().get(k_unsquished)
+ previous = None
+ if self.overridden_registry:
+ try:
+ previous = self.overridden_registry.get(k_unsquished)
+ except KeyError:
+ pass
info = CommandInfo.from_command(cmd)
try:
registry.Registry.register(self, k_unsquished, cmd,
@@ -110,6 +125,8 @@
sys.modules[cmd.__module__])
trace.warning('Previously this command was registered from %r' %
sys.modules[previous.__module__])
+ for a in cmd.aliases:
+ self._alias_dict[a] = k_unsquished
return previous
def register_lazy(self, command_name, aliases, module_name):
@@ -122,12 +139,20 @@
key = self._get_name(command_name)
registry.Registry.register_lazy(self, key, module_name, command_name,
info=CommandInfo(aliases))
+ for a in aliases:
+ self._alias_dict[a] = key
plugin_cmds = CommandRegistry()
+builtin_command_registry = CommandRegistry()
+plugin_cmds.overridden_registry = builtin_command_registry
def register_command(cmd, decorate=False):
+ """Register a plugin command.
+
+ Should generally be avoided in favor of lazy registration.
+ """
global plugin_cmds
return plugin_cmds.register(cmd, decorate)
@@ -140,9 +165,27 @@
return cmd[4:].replace('_','-')
+ at deprecated_function(deprecated_in((2, 2, 0)))
def _builtin_commands():
+ """Return a dict of {name: cmd_class} for builtin commands.
+
+ :deprecated: Use the builtin_command_registry registry instead
+ """
+ # return dict(name: cmd_class)
+ return dict(builtin_command_registry.items())
+
+
+def _register_builtin_commands():
+ if builtin_command_registry.keys():
+ # only load once
+ return
import bzrlib.builtins
- return _scan_module_for_commands(bzrlib.builtins)
+ for cmd_class in _scan_module_for_commands(bzrlib.builtins).values():
+ builtin_command_registry.register(cmd_class)
+ # lazy builtins
+ builtin_command_registry.register_lazy('cmd_bundle_info',
+ [],
+ 'bzrlib.bundle.commands')
def _scan_module_for_commands(module):
@@ -155,7 +198,10 @@
def _list_bzr_commands(names):
- """Find commands from bzr's core and plugins."""
+ """Find commands from bzr's core and plugins.
+
+ This is not the public interface, just the default hook called by all_command_names.
+ """
# to eliminate duplicates
names.update(builtin_command_names())
names.update(plugin_command_names())
@@ -179,7 +225,7 @@
Use of all_command_names() is encouraged rather than builtin_command_names
and/or plugin_command_names.
"""
- return _builtin_commands().keys()
+ return builtin_command_registry.keys()
def plugin_command_names():
@@ -263,15 +309,12 @@
def _get_bzr_command(cmd_or_None, cmd_name):
"""Get a command from bzr's core."""
- cmds = _builtin_commands()
try:
- return cmds[cmd_name]()
+ cmd_class = builtin_command_registry.get(cmd_name)
except KeyError:
pass
- # look for any command which claims this as an alias
- for real_cmd_name, cmd_class in cmds.iteritems():
- if cmd_name in cmd_class.aliases:
- return cmd_class()
+ else:
+ return cmd_class()
return cmd_or_None
@@ -1116,6 +1159,7 @@
:return: exit code of bzr command.
"""
argv = _specified_or_unicode_argv(argv)
+ _register_builtin_commands()
ret = run_bzr_catch_errors(argv)
bzrlib.ui.ui_factory.log_transport_activity(
display=('bytes' in debug.debug_flags))
=== modified file 'bzrlib/tests/test_commands.py'
--- a/bzrlib/tests/test_commands.py 2010-03-01 09:27:39 +0000
+++ b/bzrlib/tests/test_commands.py 2010-03-25 06:52:38 +0000
@@ -211,14 +211,13 @@
commands.Command.hooks.install_named_hook(
"extend_command", hook_calls.append, None)
# create a command, should not fire
- class ACommand(commands.Command):
+ class cmd_test_extend_command_hook(commands.Command):
"""A sample command."""
- cmd = ACommand()
self.assertEqual([], hook_calls)
# -- as a builtin
# register the command class, should not fire
try:
- builtins.cmd_test_extend_command_hook = ACommand
+ commands.builtin_command_registry.register(cmd_test_extend_command_hook)
self.assertEqual([], hook_calls)
# and ask for the object, should fire
cmd = commands.get_cmd_object('test-extend-command-hook')
@@ -228,7 +227,7 @@
self.assertSubset([cmd], hook_calls)
del hook_calls[:]
finally:
- del builtins.cmd_test_extend_command_hook
+ commands.builtin_command_registry.remove('test-extend-command-hook')
# -- as a plugin lazy registration
try:
# register the command class, should not fire
=== modified file 'bzrlib/tests/test_import_tariff.py'
--- a/bzrlib/tests/test_import_tariff.py 2010-02-10 02:17:15 +0000
+++ b/bzrlib/tests/test_import_tariff.py 2010-03-23 06:03:14 +0000
@@ -36,6 +36,14 @@
"""
def run_command_check_imports(self, args, forbidden_imports):
+ """Run bzr ARGS in a subprocess and check its imports.
+
+ This is fairly expensive because we start a subprocess, so we aim to
+ cover representative rather than exhaustive cases.
+
+ :param forbidden_imports: List of fully-qualified Python module names
+ that should not be loaded while running this command.
+ """
# We use PYTHON_VERBOSE rather than --profile-importts because in
# experimentation the profile-imports output seems to not always show
# the modules you'd expect; this can be debugged but python -v seems
@@ -82,6 +90,7 @@
# 'st' in a working tree shouldn't need many modules
self.make_branch_and_tree('.')
self.run_command_check_imports(['st'], [
+ 'bzrlib.bundle.commands',
'bzrlib.remote',
'bzrlib.smart',
'smtplib',
More information about the bazaar-commits
mailing list