diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index 1fee98a10f3..55914987462 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -5,12 +5,16 @@ import logging from inspect import isclass from itertools import chain +from operator import itemgetter from pkg_resources import iter_entry_points + from pyutilib.component.core import PluginGlobals, implements -from pyutilib.component.core import ExtensionPoint as PluginImplementations +from pyutilib.component.core import ExtensionPoint from pyutilib.component.core import SingletonPlugin as _pca_SingletonPlugin from pyutilib.component.core import Plugin as _pca_Plugin +from pylons import config + from ckan.plugins.interfaces import IPluginObserver __all__ = [ @@ -29,6 +33,31 @@ # not need to be explicitly enabled by the user) SYSTEM_PLUGINS_ENTRY_POINT_GROUP = "ckan.system_plugins" +# _plugins_info and _plugins_index are used in ordering plugins +_plugins_info = {} +_plugins_index = 0 + + +class PluginImplementations(ExtensionPoint): + ''' This is a cusomised version of pyutilib ExtensionPoint that + returns the plugins in the order specified by the ckan config. + + Usage:: + + >>> plugins = PluginImplementations(IMapper) + ... # plugins is a list of plugins implementing IMapper + + ''' + + def extensions(self, all=False, key=None): + plugins = super(PluginImplementations, self) \ + .extensions(all=all, key=key) + ordered = [] + for plugin in plugins: + ordered.append([plugin, _plugins_info[plugin.__class__]]) + ordered = [x[0] for x in sorted(ordered, key=itemgetter(1, 0))] + return ordered + class PluginNotFoundException(Exception): """ @@ -90,6 +119,12 @@ def load_all(config): """ Load all plugins listed in the 'ckan.plugins' config directive. """ + + global _plugins_info + _plugins_info = {} + global _plugins_index + _plugins_index = 0 + plugins = chain( find_system_plugins(), find_user_plugins(config) @@ -108,7 +143,6 @@ def reset(): """ Clear and reload all configured plugins """ - from pylons import config load_all(config) @@ -157,6 +191,9 @@ def find_user_plugins(config): Return all plugins specified by the user in the 'ckan.plugins' config directive. """ + global _plugins_index + global _plugins_info + plugins = [] for name in config.get('ckan.plugins', '').split(): entry_points = list( @@ -164,7 +201,11 @@ def find_user_plugins(config): ) if not entry_points: raise PluginNotFoundException(name) - plugins.extend(ep.load() for ep in entry_points) + loaded_plugins = (ep.load() for ep in entry_points) + for x in loaded_plugins: + plugins.append(x) + _plugins_info[x] = _plugins_index + _plugins_index += 1 return plugins @@ -175,7 +216,14 @@ def find_system_plugins(): These are essential for operation and therefore cannot be enabled/disabled through the configuration file. """ - return ( - ep.load() - for ep in iter_entry_points(group=SYSTEM_PLUGINS_ENTRY_POINT_GROUP) - ) + global _plugins_index + global _plugins_info + + plugins = [] + entry_points = iter_entry_points(group=SYSTEM_PLUGINS_ENTRY_POINT_GROUP) + loaded_plugins = (ep.load() for ep in entry_points) + for x in loaded_plugins: + plugins.append(x) + _plugins_info[x] = _plugins_index + _plugins_index += 1 + return plugins