Rev 3789: Use Registry for plugin commands, enable lazy command loading. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Oct 22 00:18:49 BST 2008
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 3789
revision-id: pqm at pqm.ubuntu.com-20081021231845-k119hl1icewguq50
parent: pqm at pqm.ubuntu.com-20081021060139-fpwr4fxr2oww2x5o
parent: aaron at aaronbentley.com-20081021204954-6ly1dyb9ix92el1a
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2008-10-22 00:18:45 +0100
message:
Use Registry for plugin commands, enable lazy command loading.
added:
bzrlib/tests/fake_command.py fake_command.py-20081021195002-r9v65tgxx63c25v9-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/tests/blackbox/test_command_encoding.py test_command_encoding.py-20060106032110-45431fd2ce9ff21f
bzrlib/tests/test_commands.py test_command.py-20051019190109-3b17be0f52eaa7a8
bzrlib/tests/test_plugins.py plugins.py-20050622075746-32002b55e5e943e9
bzrlib/tests/test_store.py teststore.py-20050826022702-f6caadb647395769
------------------------------------------------------------
revno: 3785.1.5
revision-id: aaron at aaronbentley.com-20081021204954-6ly1dyb9ix92el1a
parent: aaron at aaronbentley.com-20081021204305-4yf2n78r6b61yo91
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: command-registry
timestamp: Tue 2008-10-21 21:49:54 +0100
message:
Update NEWS
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
------------------------------------------------------------
revno: 3785.1.4
revision-id: aaron at aaronbentley.com-20081021204305-4yf2n78r6b61yo91
parent: aaron at aaronbentley.com-20081021184910-kvfby9230xv2mbfz
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: command-registry
timestamp: Tue 2008-10-21 21:43:05 +0100
message:
Enable lazy-loading of commands
added:
bzrlib/tests/fake_command.py fake_command.py-20081021195002-r9v65tgxx63c25v9-1
modified:
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/tests/test_commands.py test_command.py-20051019190109-3b17be0f52eaa7a8
------------------------------------------------------------
revno: 3785.1.3
revision-id: aaron at aaronbentley.com-20081021184910-kvfby9230xv2mbfz
parent: aaron at aaronbentley.com-20081021184829-wb5obp7gst2207ge
parent: pqm at pqm.ubuntu.com-20081021060139-fpwr4fxr2oww2x5o
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: command-registry
timestamp: Tue 2008-10-21 19:49:10 +0100
message:
merge with bzr.dev
added:
doc/developers/cycle.txt cycle.txt-20081017031739-rw24r0cywm2ok3xu-1
tools/packaging/lp-upload-release lpuploadrelease-20081020075647-56zdf9z6yav1bx81-1
modified:
Makefile Makefile-20050805140406-d96e3498bb61c5bb
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/knit.py knit.py-20051212171256-f056ac8f0fbe1bd9
bzrlib/tests/test_knit.py test_knit.py-20051212171302-95d4c00dd5f11f2b
doc/developers/index.txt index.txt-20070508041241-qznziunkg0nffhiw-1
doc/developers/releasing.txt releasing.txt-20080502015919-fnrcav8fwy8ccibu-1
------------------------------------------------------------
revno: 3785.1.2
revision-id: aaron at aaronbentley.com-20081021184829-wb5obp7gst2207ge
parent: aaron at aaronbentley.com-20081021140831-a8sqdr5sg8y82z4e
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: command-registry
timestamp: Tue 2008-10-21 19:48:29 +0100
message:
Avoid getting plugins unnecessarily
modified:
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
------------------------------------------------------------
revno: 3785.1.1
revision-id: aaron at aaronbentley.com-20081021140831-a8sqdr5sg8y82z4e
parent: pqm at pqm.ubuntu.com-20081017223605-ais9run1hp476y1c
committer: Aaron Bentley <aaron at aaronbentley.com>
branch nick: command-registry
timestamp: Tue 2008-10-21 15:08:31 +0100
message:
Switch from dict to Registry for plugin_cmds
modified:
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/tests/blackbox/test_command_encoding.py test_command_encoding.py-20060106032110-45431fd2ce9ff21f
bzrlib/tests/test_plugins.py plugins.py-20050622075746-32002b55e5e943e9
bzrlib/tests/test_store.py teststore.py-20050826022702-f6caadb647395769
=== modified file 'NEWS'
--- a/NEWS 2008-10-17 22:36:05 +0000
+++ b/NEWS 2008-10-21 20:49:54 +0000
@@ -48,6 +48,8 @@
API CHANGES:
+ * commands.plugins_cmds is now a CommandRegistry, not a dict.
+
TESTING:
INTERNALS:
=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py 2008-10-02 06:18:42 +0000
+++ b/bzrlib/commands.py 2008-10-21 20:43:05 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 Canonical Ltd
+# Copyright (C) 2006, 2008 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -53,37 +53,72 @@
from bzrlib.option import Option
-plugin_cmds = {}
+class CommandInfo(object):
+ """Information about a command."""
+
+ def __init__(self, aliases):
+ """The list of aliases for the command."""
+ self.aliases = aliases
+
+ @classmethod
+ def from_command(klass, command):
+ """Factory to construct a CommandInfo from a command."""
+ return klass(command.aliases)
+
+
+class CommandRegistry(registry.Registry):
+
+ @staticmethod
+ def _get_name(command_name):
+ if command_name.startswith("cmd_"):
+ return _unsquish_command_name(command_name)
+ else:
+ return command_name
+
+ def register(self, cmd, decorate=False):
+ """Utility function to help register a command
+
+ :param cmd: Command subclass to register
+ :param decorate: If true, allow overriding an existing command
+ of the same name; the old command is returned by this function.
+ Otherwise it is an error to try to override an existing command.
+ """
+ k = cmd.__name__
+ k_unsquished = self._get_name(k)
+ try:
+ previous = self.get(k_unsquished)
+ except KeyError:
+ previous = _builtin_commands().get(k_unsquished)
+ info = CommandInfo.from_command(cmd)
+ try:
+ registry.Registry.register(self, k_unsquished, cmd,
+ override_existing=decorate, info=info)
+ except KeyError:
+ trace.log_error('Two plugins defined the same command: %r' % k)
+ trace.log_error('Not loading the one in %r' %
+ sys.modules[cmd.__module__])
+ trace.log_error('Previously this command was registered from %r' %
+ sys.modules[previous.__module__])
+ return previous
+
+ def register_lazy(self, command_name, aliases, module_name):
+ """Register a command without loading its module.
+
+ :param command_name: The primary name of the command.
+ :param aliases: A list of aliases for the command.
+ :module_name: The module that the command lives in.
+ """
+ key = self._get_name(command_name)
+ registry.Registry.register_lazy(self, key, module_name, command_name,
+ info=CommandInfo(aliases))
+
+
+plugin_cmds = CommandRegistry()
def register_command(cmd, decorate=False):
- """Utility function to help register a command
-
- :param cmd: Command subclass to register
- :param decorate: If true, allow overriding an existing command
- of the same name; the old command is returned by this function.
- Otherwise it is an error to try to override an existing command.
- """
global plugin_cmds
- k = cmd.__name__
- if k.startswith("cmd_"):
- k_unsquished = _unsquish_command_name(k)
- else:
- k_unsquished = k
- if k_unsquished not in plugin_cmds:
- plugin_cmds[k_unsquished] = cmd
- ## trace.mutter('registered plugin command %s', k_unsquished)
- if decorate and k_unsquished in builtin_command_names():
- return _builtin_commands()[k_unsquished]
- elif decorate:
- result = plugin_cmds[k_unsquished]
- plugin_cmds[k_unsquished] = cmd
- return result
- else:
- trace.log_error('Two plugins defined the same command: %r' % k)
- trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
- trace.log_error('Previously this command was registered from %r' %
- sys.modules[plugin_cmds[k_unsquished].__module__])
+ return plugin_cmds.register(cmd, decorate)
def _squish_command_name(cmd):
@@ -118,7 +153,7 @@
"""Return name->class mapping for all commands."""
d = _builtin_commands()
if plugins_override:
- d.update(plugin_cmds)
+ d.update(plugin_cmds.iteritems())
return d
@@ -150,12 +185,21 @@
# In the future, we may actually support Unicode command names.
# first look up this command under the specified name
- cmds = _get_cmd_dict(plugins_override=plugins_override)
+ if plugins_override:
+ try:
+ return plugin_cmds.get(cmd_name)()
+ except KeyError:
+ pass
+ cmds = _get_cmd_dict(plugins_override=False)
try:
return cmds[cmd_name]()
except KeyError:
pass
-
+ if plugins_override:
+ for key in plugin_cmds.keys():
+ info = plugin_cmds.get_info(key)
+ if cmd_name in info.aliases:
+ return plugin_cmds.get(key)()
# 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:
=== modified file 'bzrlib/tests/blackbox/test_command_encoding.py'
--- a/bzrlib/tests/blackbox/test_command_encoding.py 2007-09-18 05:47:31 +0000
+++ b/bzrlib/tests/blackbox/test_command_encoding.py 2008-10-21 14:08:31 +0000
@@ -62,7 +62,7 @@
bzr,
['echo-exact', u'foo\xb5'])
finally:
- plugin_cmds.pop('echo-exact')
+ plugin_cmds.remove('echo-exact')
def test_strict_utf8(self):
def bzr(*args, **kwargs):
@@ -75,7 +75,7 @@
self.assertEqual(u'foo\xb5'.encode('utf-8'),
bzr(['echo-strict', u'foo\xb5']))
finally:
- plugin_cmds.pop('echo-strict')
+ plugin_cmds.remove('echo-strict')
def test_strict_ascii(self):
def bzr(*args, **kwargs):
@@ -90,7 +90,7 @@
bzr,
['echo-strict', u'foo\xb5'])
finally:
- plugin_cmds.pop('echo-strict')
+ plugin_cmds.remove('echo-strict')
def test_replace_utf8(self):
def bzr(*args, **kwargs):
@@ -103,7 +103,7 @@
self.assertEqual(u'foo\xb5'.encode('utf-8'),
bzr(['echo-replace', u'foo\xb5']))
finally:
- plugin_cmds.pop('echo-replace')
+ plugin_cmds.remove('echo-replace')
def test_replace_ascii(self):
def bzr(*args, **kwargs):
@@ -116,6 +116,6 @@
# ascii can't encode \xb5
self.assertEqual('foo?', bzr(['echo-replace', u'foo\xb5']))
finally:
- plugin_cmds.pop('echo-replace')
+ plugin_cmds.remove('echo-replace')
=== added file 'bzrlib/tests/fake_command.py'
--- a/bzrlib/tests/fake_command.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/fake_command.py 2008-10-21 20:43:05 +0000
@@ -0,0 +1,23 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from bzrlib.tests import test_commands
+test_commands.lazy_command_imported = True
+
+
+class cmd_fake(object):
+
+ pass
=== modified file 'bzrlib/tests/test_commands.py'
--- a/bzrlib/tests/test_commands.py 2007-04-20 03:54:06 +0000
+++ b/bzrlib/tests/test_commands.py 2008-10-21 20:43:05 +0000
@@ -16,6 +16,7 @@
from cStringIO import StringIO
import errno
+import sys
from bzrlib import (
commands,
@@ -134,3 +135,43 @@
self.assertEqual(['bar', 'foo', 'gam'],
command.get_see_also(['gam', 'bar', 'gam']))
+
+class TestRegisterLazy(tests.TestCase):
+
+ def setUp(self):
+ import bzrlib.tests.fake_command
+ del sys.modules['bzrlib.tests.fake_command']
+ global lazy_command_imported
+ lazy_command_imported = False
+
+ @staticmethod
+ def remove_fake():
+ commands.plugin_cmds.remove('fake')
+
+ def assertIsFakeCommand(self, cmd_obj):
+ from bzrlib.tests.fake_command import cmd_fake
+ self.assertIsInstance(cmd_obj, cmd_fake)
+
+ def test_register_lazy(self):
+ """Ensure lazy registration works"""
+ commands.plugin_cmds.register_lazy('cmd_fake', [],
+ 'bzrlib.tests.fake_command')
+ self.addCleanup(self.remove_fake)
+ self.assertFalse(lazy_command_imported)
+ fake_instance = commands.get_cmd_object('fake')
+ self.assertTrue(lazy_command_imported)
+ self.assertIsFakeCommand(fake_instance)
+
+ def test_get_unrelated_does_not_import(self):
+ commands.plugin_cmds.register_lazy('cmd_fake', [],
+ 'bzrlib.tests.fake_command')
+ self.addCleanup(self.remove_fake)
+ commands.get_cmd_object('status')
+ self.assertFalse(lazy_command_imported)
+
+ def test_aliases(self):
+ commands.plugin_cmds.register_lazy('cmd_fake', ['fake_alias'],
+ 'bzrlib.tests.fake_command')
+ self.addCleanup(self.remove_fake)
+ fake_instance = commands.get_cmd_object('fake_alias')
+ self.assertIsFakeCommand(fake_instance)
=== modified file 'bzrlib/tests/test_plugins.py'
--- a/bzrlib/tests/test_plugins.py 2008-10-07 06:41:46 +0000
+++ b/bzrlib/tests/test_plugins.py 2008-10-21 14:08:31 +0000
@@ -412,8 +412,8 @@
self.assertContainsRe(help, '\[myplug\]')
finally:
# unregister command
- if bzrlib.commands.plugin_cmds.get('myplug', None):
- del bzrlib.commands.plugin_cmds['myplug']
+ if 'myplug' in bzrlib.commands.plugin_cmds:
+ bzrlib.commands.plugin_cmds.remove('myplug')
# remove the plugin 'myplug'
if getattr(bzrlib.plugins, 'myplug', None):
delattr(bzrlib.plugins, 'myplug')
=== modified file 'bzrlib/tests/test_store.py'
--- a/bzrlib/tests/test_store.py 2008-05-12 04:20:02 +0000
+++ b/bzrlib/tests/test_store.py 2008-10-21 14:08:31 +0000
@@ -26,6 +26,7 @@
from bzrlib.store.text import TextStore
from bzrlib.tests import TestCase, TestCaseInTempDir, TestCaseWithTransport
import bzrlib.store as store
+import bzrlib.store.versioned
import bzrlib.transactions as transactions
import bzrlib.transport as transport
from bzrlib.transport.memory import MemoryTransport
More information about the bazaar-commits
mailing list