changeset 999:46025a1b5434

plugins: Support multiple customizable plugins directories. Also add support for specifying the theme directory in some customizable paths.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 21 Nov 2017 09:54:56 -0800
parents a49e6846e0da
children 68f799dc4680
files piecrust/app.py piecrust/plugins/base.py piecrust/processing/util.py
diffstat 3 files changed, 24 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/app.py	Tue Nov 21 09:54:00 2017 -0800
+++ b/piecrust/app.py	Tue Nov 21 09:54:56 2017 -0800
@@ -16,6 +16,7 @@
 from piecrust.plugins.base import PluginLoader
 from piecrust.routing import Route
 from piecrust.sources.base import REALM_THEME
+from piecrust.uriutil import multi_replace
 
 
 logger = logging.getLogger(__name__)
@@ -112,8 +113,8 @@
             return None
 
         # See if there's a theme we absolutely want.
-        td = self._get_dir(THEME_DIR)
-        if td is not None:
+        td = os.path.join(self.root_dir, THEME_DIR)
+        if os.path.isdir(td):
             return td
 
         # Try to load a theme specified in the configuration.
@@ -127,8 +128,8 @@
         return os.path.join(RESOURCES_DIR, 'theme')
 
     @cached_property
-    def plugins_dir(self):
-        return self._get_dir(PLUGINS_DIR)
+    def plugins_dirs(self):
+        return self._get_configurable_dirs(PLUGINS_DIR, 'site/plugins_dirs')
 
     @cached_property
     def cache_dir(self):
@@ -240,11 +241,9 @@
                 return pub
         return None
 
-    def _get_dir(self, default_rel_dir):
-        abs_dir = os.path.join(self.root_dir, default_rel_dir)
-        if os.path.isdir(abs_dir):
-            return abs_dir
-        return None
+    def resolvePath(self, path):
+        path = multi_replace(path, {'%theme_dir%': self.theme_dir})
+        return os.path.join(self.root_dir, path)
 
     def _get_configurable_dirs(self, default_rel_dir, conf_name):
         dirs = []
@@ -253,9 +252,9 @@
         conf_dirs = self.config.get(conf_name)
         if conf_dirs is not None:
             if isinstance(conf_dirs, str):
-                dirs.append(os.path.join(self.root_dir, conf_dirs))
+                dirs.append(self.resolvePath(conf_dirs))
             else:
-                dirs += [os.path.join(self.root_dir, p) for p in conf_dirs]
+                dirs += [self.resolvePath(p) for p in conf_dirs]
 
         # Add the default directory if it exists.
         default_dir = os.path.join(self.root_dir, default_rel_dir)
--- a/piecrust/plugins/base.py	Tue Nov 21 09:54:00 2017 -0800
+++ b/piecrust/plugins/base.py	Tue Nov 21 09:54:56 2017 -0800
@@ -117,7 +117,8 @@
         if to_install:
             for name in to_install:
                 plugin = self._loadPlugin(name)
-                self._plugins.append(plugin)
+                if plugin is not None:
+                    self._plugins.append(plugin)
 
         for plugin in self._plugins:
             plugin.initialize(self.app)
@@ -131,18 +132,20 @@
             mod = None
 
         if mod is None:
-            # Import as a loose Python file from the plugins dir.
-            pfile = os.path.join(self.app.plugins_dir, plugin_name + '.py')
-            if os.path.isfile(pfile):
-                spec = importlib.util.spec_from_file_location(plugin_name,
-                                                              pfile)
-                mod = importlib.util.module_from_spec(spec)
-                spec.loader.exec_module(mod)
-                sys.modules[mod_name] = mod
+            # Import as a loose Python file from the plugins dirs.
+            for plugins_dir in self.app.plugins_dirs:
+                pfile = os.path.join(plugins_dir, plugin_name + '.py')
+                if os.path.isfile(pfile):
+                    spec = importlib.util.spec_from_file_location(plugin_name,
+                                                                  pfile)
+                    mod = importlib.util.module_from_spec(spec)
+                    spec.loader.exec_module(mod)
+                    sys.modules[mod_name] = mod
+                    break
 
         if mod is None:
             logger.error("Failed to load plugin '%s'." % plugin_name)
-            logger.error(ex)
+            logger.error("Looking in: %s" % self.app.plugins_dirs)
             return
 
         plugin_class = getattr(mod, '__piecrust_plugin__', None)
--- a/piecrust/processing/util.py	Tue Nov 21 09:54:00 2017 -0800
+++ b/piecrust/processing/util.py	Tue Nov 21 09:54:56 2017 -0800
@@ -74,8 +74,7 @@
             dirname, _ = os.path.split(path)
             info.files = [os.path.join(dirname, f) for f in info.files]
         elif path_mode == 'absolute':
-            info.files = [os.path.join(self.app.root_dir, f)
-                          for f in info.files]
+            info.files = [self.app.resolvePath(f) for f in info.files]
         else:
             raise Exception("Unknown path mode: %s" % path_mode)