Rev 5101: (vila) Allow plugins to be disabled via BZR_DISABLE_PLUGINS in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Fri Mar 19 12:44:49 GMT 2010
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5101 [merge]
revision-id: pqm at pqm.ubuntu.com-20100319124448-8xooaqwyiwqhrq49
parent: pqm at pqm.ubuntu.com-20100319104730-5jdnpkz0ghxd96no
parent: v.ladeuil+lp at free.fr-20100319121028-ion6boda1uh4s5wu
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2010-03-19 12:44:48 +0000
message:
(vila) Allow plugins to be disabled via BZR_DISABLE_PLUGINS
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/help_topics/en/configuration.txt configuration.txt-20060314161707-868350809502af01
bzrlib/plugin.py plugin.py-20050622060424-829b654519533d69
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/test_plugins.py plugins.py-20050622075746-32002b55e5e943e9
=== modified file 'NEWS'
--- a/NEWS 2010-03-19 08:06:29 +0000
+++ b/NEWS 2010-03-19 12:10:28 +0000
@@ -51,6 +51,10 @@
treats backslash as an escape character on Windows. (Gordon Tyler,
#392248)
+* Plugins can be disabled by defining ``BZR_DISABLE_PLUGINS`` as
+ a list of plugin names separated by ':' (';' on windows).
+ (Vincent Ladeuil, #411413)
+
* Tree-shape conflicts can be resolved by providing ``--take-this`` and
``--take-other`` to the ``bzr resolve`` command. Just marking the conflict
as resolved is still accessible via the ``--done`` default action.
=== modified file 'bzrlib/help_topics/en/configuration.txt'
--- a/bzrlib/help_topics/en/configuration.txt 2010-01-03 03:33:10 +0000
+++ b/bzrlib/help_topics/en/configuration.txt 2010-03-19 12:09:05 +0000
@@ -98,24 +98,40 @@
used literally, they will be substituted by the corresponding,
platform specific, values.
-Examples:
-^^^^^^^^^
-
-The examples below uses ':' as the separator, windows users
+The examples below use ':' as the separator, windows users
should use ';'.
-Overriding the default user plugin directory:
-``BZR_PLUGIN_PATH='/path/to/my/other/plugins'``
-
-Disabling the site directory while retaining the user directory:
-``BZR_PLUGIN_PATH='-site:+user'``
-
-Disabling all plugins (better achieved with --no-plugins):
-``BZR_PLUGIN_PATH='-user:-core:-site'``
-
-Overriding the default site plugin directory:
-``BZR_PLUGIN_PATH='/path/to/my/site/plugins:-site':+user``
-
+Overriding the default user plugin directory::
+
+ BZR_PLUGIN_PATH='/path/to/my/other/plugins'
+
+Disabling the site directory while retaining the user directory::
+
+ BZR_PLUGIN_PATH='-site:+user'
+
+Disabling all plugins (better achieved with --no-plugins)::
+
+ BZR_PLUGIN_PATH='-user:-core:-site'
+
+Overriding the default site plugin directory::
+
+ BZR_PLUGIN_PATH='/path/to/my/site/plugins:-site':+user
+
+BZR_DISABLE_PLUGINS
+~~~~~~~~~~~~~~~~~~~
+
+Under special circumstances, it's better to disable a plugin (or
+several) rather than uninstalling them completely. Such plugins
+can be specified in the ``BZR_DISABLE_PLUGINS`` environment
+variable.
+
+In that case, ``bzr`` will stop loading the specified plugins and
+will raise an import error if they are explicitly imported (by
+another plugin that depends on them for example).
+
+Disabling ``myplugin`` and ``yourplugin`` is achieved by::
+
+ BZR_DISABLE_PLUGINS='myplugin:yourplugin'
BZRPATH
=== modified file 'bzrlib/plugin.py'
--- a/bzrlib/plugin.py 2010-03-12 13:41:08 +0000
+++ b/bzrlib/plugin.py 2010-03-17 07:16:32 +0000
@@ -91,6 +91,12 @@
if path is None:
path = get_standard_plugins_path()
_mod_plugins.__path__ = path
+ # Set up a blacklist for disabled plugins if any
+ PluginBlackListImporter.blacklist = {}
+ disabled_plugins = os.environ.get('BZR_DISABLE_PLUGINS', None)
+ if disabled_plugins is not None:
+ for name in disabled_plugins.split(os.pathsep):
+ PluginBlackListImporter.blacklist['bzrlib.plugins.' + name] = True
return path
@@ -183,8 +189,8 @@
try:
p = refs[p[1:]]
except KeyError:
- # Leave them untouched otherwise, user may have paths starting
- # with '+'...
+ # Leave them untouched so user can still use paths starting
+ # with '+'
pass
_append_new_path(paths, p)
@@ -202,7 +208,7 @@
files (and whatever other extensions are used in the platform,
such as *.pyd).
- load_from_dirs() provides the underlying mechanism and is called with
+ load_from_path() provides the underlying mechanism and is called with
the default directory list to provide the normal behaviour.
:param path: The list of paths to search for plugins. By default,
@@ -290,6 +296,8 @@
plugin_names.add(f)
for name in plugin_names:
+ if ('bzrlib.plugins.%s' % name) in PluginBlackListImporter.blacklist:
+ continue
try:
exec "import bzrlib.plugins.%s" % name in {}
except KeyboardInterrupt:
@@ -476,3 +484,19 @@
return version_string
__version__ = property(_get__version__)
+
+
+class _PluginBlackListImporter(object):
+
+ def __init__(self):
+ self.blacklist = {}
+
+ def find_module(self, fullname, parent_path=None):
+ if fullname in self.blacklist:
+ raise ImportError('%s is disabled' % fullname)
+ return None
+
+PluginBlackListImporter = _PluginBlackListImporter()
+sys.meta_path.append(PluginBlackListImporter)
+
+
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2010-03-17 05:36:11 +0000
+++ b/bzrlib/tests/__init__.py 2010-03-19 12:10:28 +0000
@@ -1519,6 +1519,7 @@
'BZR_PROGRESS_BAR': None,
'BZR_LOG': None,
'BZR_PLUGIN_PATH': None,
+ 'BZR_DISABLE_PLUGINS': None,
'BZR_CONCURRENCY': None,
# Make sure that any text ui tests are consistent regardless of
# the environment the test case is run in; you may want tests that
=== modified file 'bzrlib/tests/test_plugins.py'
--- a/bzrlib/tests/test_plugins.py 2010-03-15 11:17:44 +0000
+++ b/bzrlib/tests/test_plugins.py 2010-03-17 07:16:32 +0000
@@ -31,6 +31,7 @@
plugin,
plugins,
tests,
+ trace,
)
@@ -38,6 +39,25 @@
class TestPluginMixin(object):
+ def create_plugin(self, name, source='', dir='.', file_name=None):
+ if file_name is None:
+ file_name = name + '.py'
+ # 'source' must not fail to load
+ path = osutils.pathjoin(dir, file_name)
+ f = open(path, 'w')
+ self.addCleanup(os.unlink, path)
+ try:
+ f.write(source + '\n')
+ finally:
+ f.close()
+
+ def create_plugin_package(self, name, source='', dir='.'):
+ plugin_dir = osutils.pathjoin(dir, name)
+ os.mkdir(plugin_dir)
+ self.addCleanup(osutils.rmtree, plugin_dir)
+ self.create_plugin(name, source, dir=plugin_dir,
+ file_name='__init__.py')
+
def _unregister_plugin(self, name):
"""Remove the plugin from sys.modules and the bzrlib namespace."""
py_name = 'bzrlib.plugins.%s' % name
@@ -47,11 +67,11 @@
delattr(bzrlib.plugins, name)
def assertPluginUnknown(self, name):
- self.failIf(getattr(bzrlib.plugins, 'plugin', None) is not None)
+ self.failIf(getattr(bzrlib.plugins, name, None) is not None)
self.failIf('bzrlib.plugins.%s' % name in sys.modules)
def assertPluginKnown(self, name):
- self.failUnless(getattr(bzrlib.plugins, 'plugin', None) is not None)
+ self.failUnless(getattr(bzrlib.plugins, name, None) is not None)
self.failUnless('bzrlib.plugins.%s' % name in sys.modules)
@@ -723,3 +743,40 @@
self.check_path(['+foo', '-bar', self.core, self.site],
['+foo', '-bar'])
+
+class TestDisablePlugin(tests.TestCaseInTempDir, TestPluginMixin):
+
+ def setUp(self):
+ super(TestDisablePlugin, self).setUp()
+ self.create_plugin_package('test_foo')
+ # Make sure we don't pollute the plugins namespace
+ self.overrideAttr(plugins, '__path__')
+ # Be paranoid in case a test fail
+ self.addCleanup(self._unregister_plugin, 'test_foo')
+
+ def test_cannot_import(self):
+ osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
+ plugin.set_plugins_path(['.'])
+ try:
+ import bzrlib.plugins.test_foo
+ except ImportError:
+ pass
+ self.assertPluginUnknown('test_foo')
+
+ def test_regular_load(self):
+ self.overrideAttr(plugin, '_loaded', False)
+ plugin.load_plugins(['.'])
+ self.assertPluginKnown('test_foo')
+
+ def test_not_loaded(self):
+ self.warnings = []
+ def captured_warning(*args, **kwargs):
+ self.warnings.append((args, kwargs))
+ self.overrideAttr(trace, 'warning', captured_warning)
+ self.overrideAttr(plugin, '_loaded', False)
+ osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
+ plugin.load_plugins(plugin.set_plugins_path(['.']))
+ self.assertPluginUnknown('test_foo')
+ # Make sure we don't warn about the plugin ImportError since this has
+ # been *requested* by the user.
+ self.assertLength(0, self.warnings)
More information about the bazaar-commits
mailing list