def _solve(self, node, depends): "" for otherpluginid in depends: # check if required plugin is present if otherpluginid not in self._nodes: if self._nodes[otherpluginid].state == PluginState.Unloaded: return exceptions.PluginError( node, "A required plugin failed to load: {}".format(otherpluginid)) elif self._nodes[otherpluginid].state == PluginState.Disabled: return exceptions.PluginError( node, "A required plugin has been disabled: {}".format(otherpluginid)) else: return exceptions.PluginError( node, "A required plugin is not present: {}".format(otherpluginid)) vers = depends[otherpluginid] other_node = self._nodes[otherpluginid] # compare versions other_version = other_node.plugin.VERSION if not vers[0] <= other_version: return exceptions.PluginError( node, "A required plugin does not meet version requirement {} <= {}: {}".format( vers[0], other_version, otherpluginid)) if not vers[1] == (0, 0, 0) and not vers[1] > other_version: return exceptions.PluginError( node, "A required plugin does not meet version requirement {} > {}: {}".format( vers[1], other_version, otherpluginid)) return True
def _plugin_load(module_name_or_class, path, *args, _logger=None, **kwargs): """ Imports plugin module and registers its main class Returns: PluginNode """ plugclass = None if isinstance(module_name_or_class, str): mod = importlib.import_module(module_name_or_class) mod = importlib.reload(mod) plugmembers = inspect.getmembers(mod) for name, m_object in plugmembers: if name == "HPlugin": plugclass = m_object break elif inspect.isclass(module_name_or_class): plugclass = module_name_or_class if plugclass is None: raise exceptions.PluginError( "Plugin loader", "No main entry class named 'HPlugin' found in '{}'".format(path)) log.i("Loading", plugclass.__name__) cls = HPluginMeta( plugclass.__name__, plugclass.__bases__, dict( plugclass.__dict__)) if not _logger: _logger = get_plugin_logger(cls.NAME, path) return registered.register(cls, _logger, *args, **kwargs)
def _init_plugin(self, pluginid): "" if pluginid in self._nodes: node = self._nodes[pluginid] try: self._ensure_valid_signature(node) node.instanced = node.plugin(*node.args, **node.kwargs) except Exception as e: self.disable_plugin(pluginid) if not isinstance(e, exceptions.PluginError): raise exceptions.PluginError(node, "{}".format(e)) raise node.state = PluginState.Enabled else: raise exceptions.CoreError( utils.this_function(), "Plugin node has not been registered with this manager")
def register(self, plugin, logger, *args, **kwargs): """ Registers a plugin Params: - plugin -- main plugin class - logger -- plugin logger - *args -- additional arguments for plugin - **kwargs -- additional keyword arguments for plugin Returns: PluginNode """ assert isinstance(plugin, HPluginMeta) if plugin.ID in self._nodes: raise exceptions.PluginError( plugin.NAME, "Plugin ID already exists") node = PluginNode(plugin, logger, *args, **kwargs) self._nodes[plugin.ID] = node return node
def _ensure_before_init(self, node): "" assert isinstance(node, PluginNode) if not node.state == PluginState.Init: raise exceptions.PluginError( node, "This method should be called in __init__")
def _ensure_ready(self, node): "" assert isinstance(node, PluginNode) if not node.state == PluginState.Enabled: raise exceptions.PluginError(node, "This plugin is not ready")
def _solve(self, nodes): """ Returns a tuple of: - An ordered list of node, in the order they should be initiated in - Nodes that failed the dependency resolving {node:exception} """ failed = {} universal = [] inverse = [] provides = {} # solve hard requirements for node in nodes: for otherpluginid in node.depends: formatted = format_plugin(otherpluginid) # check if required plugin is present e = None if otherpluginid in self._nodes: if self._nodes[ otherpluginid].state == PluginState.Unloaded: e = exceptions.PluginError( node, "A required plugin failed to load: {}".format( formatted)) elif self._nodes[ otherpluginid].state == PluginState.Disabled: e = exceptions.PluginError( node, "A required plugin has been disabled: {}".format( formatted)) else: e = exceptions.PluginError( node, "A required plugin is not present: {}".format( formatted)) if not e: vers = node.depends[otherpluginid] other_node = self._nodes[otherpluginid] # compare versions other_version = other_node.plugin.VERSION if not vers[0] <= other_version: e = exceptions.PluginError( node, "A required plugin does not meet version requirement {} <= {}: {}" .format(vers[0], other_version, formatted)) if not vers[1] == (0, 0, 0) and not vers[1] > other_version: e = exceptions.PluginError( node, "A required plugin does not meet version requirement {} > {}: {}" .format(vers[1], other_version, formatted)) if e: failed[node] = e break else: provides[node.plugin.ID] = node provides[node.plugin.SHORTNAME] = node if node.load_order == "first": universal.append(node) elif node.load_order == "last": inverse.append(node) # build initial graph dependencies = {} for node in nodes: reqs = set(node.depends.keys()) dependencies[node] = set(provides[x] for x in reqs) if universal and node not in universal: dependencies[node].update(universal) if inverse and node in inverse: dependencies[node].update(set(nodes).difference(inverse)) # solver dependencies = robust_topological_sort(dependencies) node_order = [] for node in dependencies: # circular reference if len(node) > 1: for n in node: failed[n] = exceptions.PluginError( "Circular dependency found: {}".format(node)) continue node_order.append(node[0]) node_order.reverse() return node_order, failed