Mercurial > piecrust2
comparison 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 |
comparison
equal
deleted
inserted
replaced
119:0811f92cbdc7 | 120:133845647083 |
---|---|
1 import os | 1 import os |
2 import os.path | 2 import os.path |
3 import pickle | 3 import pickle |
4 import logging | 4 import logging |
5 from piecrust import APP_VERSION | |
5 from piecrust.events import Event | 6 from piecrust.events import Event |
6 | 7 |
7 | 8 |
8 logger = logging.getLogger(__name__) | 9 logger = logging.getLogger(__name__) |
9 | 10 |
10 | 11 |
11 class Record(object): | 12 class Record(object): |
12 def __init__(self): | 13 def __init__(self): |
13 self.entries = [] | 14 self.entries = [] |
14 self.entry_added = Event() | 15 self.entry_added = Event() |
16 self.app_version = APP_VERSION | |
17 self.record_version = self.__class__.RECORD_VERSION | |
18 | |
19 def hasLatestVersion(self): | |
20 return (self.app_version == APP_VERSION and | |
21 self.record_version == self.__class__.RECORD_VERSION) | |
15 | 22 |
16 def addEntry(self, entry): | 23 def addEntry(self, entry): |
17 self.entries.append(entry) | 24 self.entries.append(entry) |
18 self.entry_added.fire(entry) | 25 self.entry_added.fire(entry) |
19 | 26 |
29 odict = self.__dict__.copy() | 36 odict = self.__dict__.copy() |
30 del odict['entry_added'] | 37 del odict['entry_added'] |
31 return odict | 38 return odict |
32 | 39 |
33 def __setstate__(self, state): | 40 def __setstate__(self, state): |
34 for k, v in state.items(): | 41 state['entry_added'] = Event() |
35 setattr(self, k, v) | 42 self.__dict__.update(state) |
36 self.entry_added = Event() | |
37 | 43 |
38 @staticmethod | 44 @staticmethod |
39 def load(path): | 45 def load(path): |
40 logger.debug("Loading bake record from: %s" % path) | 46 logger.debug("Loading bake record from: %s" % path) |
41 with open(path, 'rb') as fp: | 47 with open(path, 'rb') as fp: |
42 return pickle.load(fp) | 48 return pickle.load(fp) |
43 | 49 |
50 | |
51 class TransitionalRecord(object): | |
52 def __init__(self, record_class, previous_path=None): | |
53 self._record_class = record_class | |
54 self.transitions = {} | |
55 self.incremental_count = 0 | |
56 self.current = record_class() | |
57 if previous_path: | |
58 self.loadPrevious(previous_path) | |
59 else: | |
60 self.previous = record_class() | |
61 self.current.entry_added += self._onCurrentEntryAdded | |
62 | |
63 def loadPrevious(self, previous_path): | |
64 previous_record_valid = True | |
65 try: | |
66 self.previous = self._record_class.load(previous_path) | |
67 except Exception as ex: | |
68 logger.debug("Error loading previous record: %s" % ex) | |
69 logger.debug("Will reset to an empty one.") | |
70 previous_record_valid = False | |
71 | |
72 if self.previous.record_version != self._record_class.RECORD_VERSION: | |
73 logger.debug("Previous record has old version %d." % | |
74 self.previous.record_version) | |
75 logger.debug("Will reset to an empty one.") | |
76 previous_record_valid = False | |
77 | |
78 if not previous_record_valid: | |
79 self.previous = self._record_class() | |
80 return | |
81 | |
82 for e in self.previous.entries: | |
83 key = self.getTransitionKey(e) | |
84 self.transitions[key] = (e, None) | |
85 | |
86 def clearPrevious(self): | |
87 self.previous = self._record_class() | |
88 | |
89 def saveCurrent(self, current_path): | |
90 self.current.save(current_path) | |
91 | |
92 def addEntry(self, entry): | |
93 self.current.addEntry(entry) | |
94 | |
95 def getTransitionKey(self, entry): | |
96 raise NotImplementedError() | |
97 | |
98 def _onCurrentEntryAdded(self, entry): | |
99 key = self.getTransitionKey(entry) | |
100 te = self.transitions.get(key) | |
101 if te is None: | |
102 logger.debug("Adding new record entry: %s" % key) | |
103 self.transitions[key] = (None, entry) | |
104 return | |
105 | |
106 if te[1] is not None: | |
107 raise Exception("A current entry already exists for: %s" % | |
108 key) | |
109 logger.debug("Setting current record entry: %s" % key) | |
110 self.transitions[key] = (te[0], entry) | |
111 |