import logging from twisted.internet import defer log = logging.getLogger(__name__) class ComponentManager(object): components = set() @classmethod def sort_components(cls, reverse=False): """ Sort components by requirements """ steps = [] staged = set() components = set(cls.components) # components with no requirements step = [] for component in set(components): if not component.depends_on: step.append(component) staged.add(component.component_name) components.remove(component) if step: steps.append(step) while components: step = [] to_stage = set() for component in set(components): reqs_met = 0 for needed in component.depends_on: if needed in staged: reqs_met += 1 if reqs_met == len(component.depends_on): step.append(component) to_stage.add(component.component_name) components.remove(component) if step: staged.update(to_stage) steps.append(step) elif components: raise SyntaxError("components cannot be started: %s" % components) if reverse: steps.reverse() return steps @classmethod @defer.inlineCallbacks def setup(cls): """ Start Components in sequence sorted by requirements :return: (defer.Deferred) """ stages = cls.sort_components() for stage in stages: yield defer.DeferredList([component._setup() for component in stage]) @classmethod @defer.inlineCallbacks def stop(cls): """ Stop Components in reversed startup order :return: (defer.Deferred) """ stages = cls.sort_components(reverse=True) for stage in stages: yield defer.DeferredList([component._stop() for component in stage]) @classmethod def all_components_running(cls, *component_names): """ :return: (bool) True if all specified components are running """ c = {component.component_name: component for component in cls.components} for component in component_names: if component not in c: raise NameError("%s is not a known Component" % component) if not c[component].running: return False return True @classmethod def get_component(cls, component_name): for component in cls.components: if component.component_name == component_name: return component raise NameError(component_name)