summaryrefslogtreecommitdiff
path: root/buildstream/plugin.py
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2016-11-08 18:07:25 +0900
committerTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2016-11-08 18:17:47 +0900
commita77219b5a2b409bc01dafa81e47549f1de422524 (patch)
tree3b4f0c671b9a9989540c6cf672300f2f041704eb /buildstream/plugin.py
parentbb76dc5105f68f333eb0f37f12bc4840837d0fea (diff)
downloadbuildstream-a77219b5a2b409bc01dafa81e47549f1de422524.tar.gz
Adding plugin module
This provides the internal _PluginContext class used as a base class for Source and Element factories. This supports loading Element and Source plugins from multiple sources, and allows the pipeline to keep separate contexts of loaded plugins, so that recursive pipeline builds can work with separate plugin contexts.
Diffstat (limited to 'buildstream/plugin.py')
-rw-r--r--buildstream/plugin.py98
1 files changed, 98 insertions, 0 deletions
diff --git a/buildstream/plugin.py b/buildstream/plugin.py
new file mode 100644
index 000000000..ef9148504
--- /dev/null
+++ b/buildstream/plugin.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2016 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors:
+# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
+
+from pluginbase import PluginBase
+
+class _PluginError(Exception):
+ """Raised when initializing plugins"""
+ pass
+
+# A Context for loading plugin types
+#
+# Args:
+# plugin_base (PluginBase): The main PluginBase object to work with
+# base_type (type): A base object type for this context
+# searchpath (list): A list of paths to search for plugins
+#
+# Since multiple pipelines can be processed recursively
+# within the same interpretor, it's important that we have
+# one context associated to the processing of a given pipeline,
+# this way sources and element types which are particular to
+# a given BuildStream project are isolated to their respective
+# Pipelines.
+#
+class _PluginContext():
+
+ def __init__(self, plugin_base, base_type, searchpath=None):
+
+ if not searchpath:
+ raise _PluginError ("Cannot create plugin context without any searchpath")
+
+ self.base_type = base_type; # The expected base class which plugins are to derive from
+ self.source = None # The PluginSource object
+ self.types = {} # Dictionary to lookup plugin types by their kind
+
+ self.load_plugins(plugin_base, searchpath)
+
+ # lookup():
+ #
+ # Fetches a type loaded from a plugin in this plugin context
+ #
+ # Args:
+ # kind (str): The kind of Plugin to create
+ #
+ # Returns: the type associated with the given kind
+ #
+ # Raises: _PluginError
+ #
+ def lookup(self, kind):
+ if not kind in self.types:
+ raise _PluginError ("No %s type registered for kind '%s'" %
+ (self.base_type.__name__, kind))
+
+ return self.types[kind]
+
+ def load_plugins(self, base, searchpath):
+ self.source = base.make_plugin_source(searchpath=searchpath)
+ for kind in self.source.list_plugins():
+ self.load_plugin(kind)
+
+ def load_plugin(self, kind):
+
+ plugin = self.source.load_plugin(kind)
+ plugin_type = plugin.setup()
+
+ self.assert_plugin (kind, plugin_type)
+
+ print ("Registering %s plugin %s for kind %s" %
+ (self.base_type.__name__, plugin_type.__name__, kind))
+ self.types[kind] = plugin_type
+
+ def assert_plugin(self, kind, plugin_type):
+ if kind in self.types:
+ raise _PluginError ("Tried to register %s plugin for existing kind '%s' (already registered %s)" %
+ (self.base_type.__name__, kind, self.types[kind].__name__))
+ try:
+ if not issubclass(plugin_type, self.base_type):
+ raise _PluginError ("%s plugin '%s' returned type '%s', which is not a subclass of Plugin" %
+ (self.base_type.__name__, kind, plugin_type.__name__))
+ except TypeError as e:
+ raise _PluginError ("%s plugin '%s' returned something that is not an Plugin subclass" %
+ (self.base_type.__name__, kind)) from e