changeset 3831:4a3c996f2d5f

plugins: allow multiple plugin paths
author Johannes Berg <johannes AT sipsolutions DOT net>
date Fri, 11 Jul 2008 16:19:34 +0200
parents 3af779616368
children 682fd34b9422
files MoinMoin/config/multiconfig.py MoinMoin/wikiutil.py
diffstat 2 files changed, 54 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/config/multiconfig.py	Fri Jul 11 16:15:25 2008 +0200
+++ b/MoinMoin/config/multiconfig.py	Fri Jul 11 16:19:34 2008 +0200
@@ -526,35 +526,43 @@
                 raise error.ConfigurationError(msg)
 
     def _loadPluginModule(self):
-        """ import plugin module under configname.plugin
+        """
+        import all plugin modules
 
         To be able to import plugin from arbitrary path, we have to load
         the base package once using imp.load_module. Later, we can use
         standard __import__ call to load plugins in this package.
 
-        Since each wiki has unique plugins, we load the plugin package
-        under the wiki configuration module, named self.siteid.
+        Since each configured plugin path has unique plugins, we load the
+        plugin packages as "moin_plugin_<sha1(path)>.plugin".
         """
-        import imp
+        import imp, sha
 
-        name = self.siteid + '.plugin'
+        plugin_dirs = [self.plugin_dir] + self.plugin_dirs
+        self._plugin_modules = []
+
         try:
             # Lock other threads while we check and import
             imp.acquire_lock()
             try:
-                # If the module is not loaded, try to load it
-                if not name in sys.modules:
-                    # Find module on disk and try to load - slow!
-                    plugin_parent_dir = os.path.abspath(os.path.join(self.plugin_dir, '..'))
-                    fp, path, info = imp.find_module('plugin', [plugin_parent_dir])
-                    try:
-                        # Load the module and set in sys.modules
-                        module = imp.load_module(name, fp, path, info)
-                        sys.modules[self.siteid].plugin = module
-                    finally:
-                        # Make sure fp is closed properly
-                        if fp:
-                            fp.close()
+                for pdir in plugin_dirs:
+                    csum = 'p_%s' % sha.new(pdir).hexdigest()
+                    modname = '%s.%s' % (self.siteid, csum)
+                    # If the module is not loaded, try to load it
+                    if not modname in sys.modules:
+                        # Find module on disk and try to load - slow!
+                        abspath = os.path.abspath(pdir)
+                        parent_dir, pname = os.path.split(abspath)
+                        fp, path, info = imp.find_module(pname, [parent_dir])
+                        try:
+                            # Load the module and set in sys.modules
+                            module = imp.load_module(modname, fp, path, info)
+                            setattr(sys.modules[self.siteid], 'csum', module)
+                            self._plugin_modules.append(modname)
+                        finally:
+                            # Make sure fp is closed properly
+                            if fp:
+                                fp.close()
             finally:
                 imp.release_lock()
         except ImportError, err:
@@ -844,7 +852,8 @@
     ('data_underlay_dir', './underlay/', "Path to the underlay directory containing distribution system and help pages."),
     ('cache_dir', None, "Directory for caching, by default computed from `data_dir`/cache."),
     ('user_dir', None, "Directory for user storage, by default computed to be `data_dir`/user."),
-    ('plugin_dir', None, "Plugin directory, by default computed to be `data_dir`/user."),
+    ('plugin_dir', None, "Plugin directory, by default computed to be `data_dir`/plugin."),
+    ('plugin_dirs', [], "Additional plugin directories."),
 
     ('docbook_html_dir', r"/usr/share/xml/docbook/stylesheet/nwalsh/html/",
      'Path to the directory with the Docbook to HTML XSLT files (optional, used by the docbook parser). The default value is correct for Debian Etch.'),
--- a/MoinMoin/wikiutil.py	Fri Jul 11 16:15:25 2008 +0200
+++ b/MoinMoin/wikiutil.py	Fri Jul 11 16:19:34 2008 +0200
@@ -1114,9 +1114,11 @@
 
     See importPlugin docstring.
     """
-    if not name in wikiPlugins(kind, cfg):
-        raise PluginMissingError
-    moduleName = '%s.plugin.%s.%s' % (cfg.siteid, kind, name)
+    plugins = wikiPlugins(kind, cfg)
+    modname = plugins.get(name, None)
+    if modname is None:
+        raise PluginMissingError()
+    moduleName = '%s.%s' % (modname, name)
     return importNameFromPlugin(moduleName, function)
 
 
@@ -1168,31 +1170,35 @@
 
 
 def wikiPlugins(kind, cfg):
-    """ Gets a list of modules in data/plugin/'kind'
+    """
+    Gets a dict containing the names of all plugins of @kind
+    as the key and the containing module name as the value.
 
     @param kind: what kind of modules we look for
-    @rtype: list
-    @return: module names
+    @rtype: dict
+    @return: plugin name to containing module name mapping  
     """
-    # Wiki plugins are located in wikiconfig.plugin module
-    modulename = '%s.plugin' % (cfg.siteid, )
-
-    # short-cut if we've loaded the list already
+    # short-cut if we've loaded the dict already
     # (or already failed to load it)
     if kind in cfg._site_plugin_lists:
         return cfg._site_plugin_lists[kind]
 
-    import sys
-    try:
-        module = pysupport.importName(modulename, kind)
-        packagepath = os.path.dirname(module.__file__)
-        plugins = pysupport.getPluginModules(packagepath)
+    result = {}
 
-        cfg._site_plugin_lists[kind] = plugins
-        return plugins
-    except AttributeError:
-        cfg._site_plugin_lists[kind] = []
-        return []
+    for modname in cfg._plugin_modules:
+        try:
+            module = pysupport.importName(modname, kind)
+            packagepath = os.path.dirname(module.__file__)
+            plugins = pysupport.getPluginModules(packagepath)
+
+            for p in plugins:
+                if not p in result:
+                    result[p] = '%s.%s' % (modname, kind)
+        except AttributeError:
+            pass
+
+    cfg._site_plugin_lists[kind] = result
+    return result
 
 
 def getPlugins(kind, cfg):