diff options
author | Martin Sivak <msivak@redhat.com> | 2008-01-02 10:54:03 +0100 |
---|---|---|
committer | Martin Sivak <msivak@redhat.com> | 2008-01-02 10:54:03 +0100 |
commit | 2a4335b0c2e5e071190afe24d24e5ea99c7553b5 (patch) | |
tree | 29f88afd281ae48e2ede4e428f0c92b387353bd5 | |
parent | 5b1aab4ce3ceaf7075f620083078eaa32b59d7df (diff) | |
download | firstaidkit-2a4335b0c2e5e071190afe24d24e5ea99c7553b5.tar.gz firstaidkit-2a4335b0c2e5e071190afe24d24e5ea99c7553b5.tar.xz firstaidkit-2a4335b0c2e5e071190afe24d24e5ea99c7553b5.zip |
Add dependency system into plugins. Use the require/provide model to control it.
-rw-r--r-- | tasker/interpret.py | 39 | ||||
-rw-r--r-- | tasker/plugins.py | 34 |
2 files changed, 61 insertions, 12 deletions
diff --git a/tasker/interpret.py b/tasker/interpret.py index b7a2339..7bd0061 100644 --- a/tasker/interpret.py +++ b/tasker/interpret.py @@ -17,15 +17,31 @@ from log import Logger from plugins import PluginSystem -from reporting import Reports +from reporting import Reports, TASKER +import logging +import copy + +class RunDependencies(object): + """Encapsulate flags used to control the dependencies between plugins""" + def __init__(self): + self._provide = set() + + def provide(self, id): + """Add flag""" + self._provide.add(id) + + def require(self, id): + """Return True if flag is present, otherwise false""" + return id in self._provide class Tasker: """The main interpret of tasks described in Config object""" def __init__(self, cfg): + self._provide = RunDependencies() self._config = cfg self._reporting = Reports() - self.pluginSystem = PluginSystem(reporting = self._reporting) + self.pluginSystem = PluginSystem(reporting = self._reporting, dependencies = self._provide) def reporting(self): return self._reporting @@ -41,12 +57,23 @@ class Tasker: pluginSystem = self.pluginSystem if self._config.operation.mode == "auto": - for plugin in pluginSystem.list(): - pluginSystem.autorun(plugin) + oldlist = set() + actlist = set(pluginSystem.list()) + #iterate through plugins until there is no plugin left or no action performed during whole iteration + while len(actlist)>0 and oldlist!=actlist: + oldlist = copy.copy(actlist) + for plugin in oldlist: + if pluginSystem.autorun(plugin): #False when dependencies are not met + actlist.remove(plugin) + for plugin in aclist: + self._reporting.info("Plugin %s was not called because of unsatisfied dependencies" % (plugin,), origin = TASKER, importance = logging.WARNING) elif self._config.operation.mode == "flow": - pluginSystem.autorun(self._config.operation.plugin, flow = self._config.operation.flow) + try: + pluginSystem.autorun(self._config.operation.plugin, flow = self._config.operation.flow, dependencies = False) + except InvalidFlowNameException, e: + pass elif self._config.operation.mode == "plugin": - pluginSystem.autorun(self._config.operation.plugin) + pluginSystem.autorun(self._config.operation.plugin, dependencies = False) elif self._config.operation.mode == "task": pass else: diff --git a/tasker/plugins.py b/tasker/plugins.py index 251cc43..53d8c79 100644 --- a/tasker/plugins.py +++ b/tasker/plugins.py @@ -79,11 +79,12 @@ class Plugin(object): "clean" : {ReturnValueTrue: final} }, description="The default, fully automated, fixing sequence") - def __init__(self, flow, reporting): + def __init__(self, flow, reporting, dependencies): """ Initialize the instance. flow -- Name of the flow to be used with this instance. reporting -- object used to report information to the user + dependencies -- object encapsulating the inter-plugin dependency API (require, provide) The flow is defined in the __init__ so we don't have to worry about changing it. """ @@ -137,6 +138,11 @@ class Plugin(object): raise InvalidFlowNameException(flow) @classmethod + def getDeps(cls): + """Return list of conditions required to be set before automated run can be done""" + return set() + + @classmethod def getFlows(cls): """Return a set with the names of all possible flows.""" fatherf = Plugin._defflows.keys() @@ -253,9 +259,10 @@ class Plugin(object): class PluginSystem(object): """Encapsulate all plugin detection and import stuff""" - def __init__(self, reporting, config = Config): + def __init__(self, reporting, dependencies, config = Config): self._path = Config.plugin.path self._reporting = reporting + self._deps = dependencies self._plugins = {} #create list of potential modules in the path @@ -293,11 +300,16 @@ class PluginSystem(object): """Return the list of imported plugins""" return self._plugins.keys() - def autorun(self, plugin, flow = None): - """Perform automated run of plugin""" + def autorun(self, plugin, flow = None, dependencies = True): + """Perform automated run of plugin with condition checking +returns - True if conditions are fully satisfied + False if there is something missing + exception when some other error happens""" + pklass = self._plugins[plugin].get_plugin() #get top level class of plugin Logger.info("Plugin information...") Logger.info("name:%s , version:%s , author:%s " % pklass.info()) + flows = pklass.getFlows() Logger.info("Provided flows : %s " % flows) if flow==None: @@ -308,13 +320,23 @@ class PluginSystem(object): Logger.info("Using %s flow" % flowName) if flowName not in flows: Logger.error("Flow %s does not exist in plugin %s", flowName, plugin) - return + raise InvalidFlowNameException(d) + + if dependencies: + deps = pklass.getDeps() + Logger.info("depends on: %s" % (", ".join(deps),)) + for d in deps: + if not self._deps.require(d): + Logger.info("depends on usatisfied condition: %s" % (d,)) + return False - p = pklass(flowName, reporting = self._reporting) + p = pklass(flowName, reporting = self._reporting, dependencies = self._deps) for (step, rv) in p: #autorun all the needed steps Logger.info("Running step %s in plugin %s ...", step, plugin) Logger.info("%s is current step and %s is result of that step." % (step, rv)) + return True + def getplugin(self, plugin): """Get instance of plugin, so we can call the steps manually""" return self._plugins[plugin].get_plugin() |