| exit_unclean = object() |
| exit_clean = object() |
| |
| |
| class Step(object): |
| provides = [] |
| |
| def __init__(self, logger): |
| self.logger = logger |
| |
| def run(self, step_index, state): |
| """Base class for state-creating steps. |
| |
| When a Step is run() the current state is checked to see |
| if the state from this step has already been created. If it |
| has the restore() method is invoked. Otherwise the create() |
| method is invoked with the state object. This is expected to |
| add items with all the keys in __class__.provides to the state |
| object. |
| """ |
| |
| name = self.__class__.__name__ |
| |
| try: |
| stored_step = state.steps[step_index] |
| except IndexError: |
| stored_step = None |
| |
| if stored_step == name: |
| self.restore(state) |
| elif stored_step is None: |
| self.create(state) |
| assert set(self.provides).issubset(set(state.keys())) |
| state.steps = state.steps + [name] |
| else: |
| raise ValueError("Expected a %s step, got a %s step" % (name, stored_step)) |
| |
| def create(self, data): |
| raise NotImplementedError |
| |
| def restore(self, state): |
| self.logger.debug("Step %s using stored state" % (self.__class__.__name__,)) |
| for key in self.provides: |
| assert key in state |
| |
| |
| class StepRunner(object): |
| steps = [] |
| |
| def __init__(self, logger, state): |
| """Class that runs a specified series of Steps with a common State""" |
| self.state = state |
| self.logger = logger |
| if "steps" not in state: |
| state.steps = [] |
| |
| def run(self): |
| rv = None |
| for step_index, step in enumerate(self.steps): |
| self.logger.debug("Starting step %s" % step.__name__) |
| rv = step(self.logger).run(step_index, self.state) |
| if rv in (exit_clean, exit_unclean): |
| break |
| |
| return rv |