Mercurial > piecrust2
diff piecrust/records.py @ 120:133845647083
Better error management and removal support in baking/processing.
* Baker and processor pipeline now store errors in their records.
* They also support deleting output files that are no longer valid.
* The basic transitional record class implements more boilerplate code.
* The processor pipeline is run from the `bake` command directly.
* New unit tests.
* Unit test mocking now mocks `os.remove` too.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 09 Nov 2014 14:46:23 -0800 |
parents | e88e330eb8dc |
children | 9e4c2e68a129 |
line wrap: on
line diff
--- a/piecrust/records.py Wed Oct 29 08:19:58 2014 -0700 +++ b/piecrust/records.py Sun Nov 09 14:46:23 2014 -0800 @@ -2,6 +2,7 @@ import os.path import pickle import logging +from piecrust import APP_VERSION from piecrust.events import Event @@ -12,6 +13,12 @@ def __init__(self): self.entries = [] self.entry_added = Event() + self.app_version = APP_VERSION + self.record_version = self.__class__.RECORD_VERSION + + def hasLatestVersion(self): + return (self.app_version == APP_VERSION and + self.record_version == self.__class__.RECORD_VERSION) def addEntry(self, entry): self.entries.append(entry) @@ -31,9 +38,8 @@ return odict def __setstate__(self, state): - for k, v in state.items(): - setattr(self, k, v) - self.entry_added = Event() + state['entry_added'] = Event() + self.__dict__.update(state) @staticmethod def load(path): @@ -41,3 +47,65 @@ with open(path, 'rb') as fp: return pickle.load(fp) + +class TransitionalRecord(object): + def __init__(self, record_class, previous_path=None): + self._record_class = record_class + self.transitions = {} + self.incremental_count = 0 + self.current = record_class() + if previous_path: + self.loadPrevious(previous_path) + else: + self.previous = record_class() + self.current.entry_added += self._onCurrentEntryAdded + + def loadPrevious(self, previous_path): + previous_record_valid = True + try: + self.previous = self._record_class.load(previous_path) + except Exception as ex: + logger.debug("Error loading previous record: %s" % ex) + logger.debug("Will reset to an empty one.") + previous_record_valid = False + + if self.previous.record_version != self._record_class.RECORD_VERSION: + logger.debug("Previous record has old version %d." % + self.previous.record_version) + logger.debug("Will reset to an empty one.") + previous_record_valid = False + + if not previous_record_valid: + self.previous = self._record_class() + return + + for e in self.previous.entries: + key = self.getTransitionKey(e) + self.transitions[key] = (e, None) + + def clearPrevious(self): + self.previous = self._record_class() + + def saveCurrent(self, current_path): + self.current.save(current_path) + + def addEntry(self, entry): + self.current.addEntry(entry) + + def getTransitionKey(self, entry): + raise NotImplementedError() + + def _onCurrentEntryAdded(self, entry): + key = self.getTransitionKey(entry) + te = self.transitions.get(key) + if te is None: + logger.debug("Adding new record entry: %s" % key) + self.transitions[key] = (None, entry) + return + + if te[1] is not None: + raise Exception("A current entry already exists for: %s" % + key) + logger.debug("Setting current record entry: %s" % key) + self.transitions[key] = (te[0], entry) +