Mercurial > piecrust2
comparison piecrust/pipelines/records.py @ 854:08e02c2a2a1a
core: Keep refactoring, this time to prepare for generator sources.
- Make a few APIs simpler.
- Content pipelines create their own jobs, so that generator sources can
keep aborting in `getContents`, but rely on their pipeline to generate
pages for baking.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 04 Jun 2017 23:34:28 -0700 |
parents | f070a4fc033c |
children | 448710d84121 |
comparison
equal
deleted
inserted
replaced
853:f070a4fc033c | 854:08e02c2a2a1a |
---|---|
7 | 7 |
8 | 8 |
9 logger = logging.getLogger(__name__) | 9 logger = logging.getLogger(__name__) |
10 | 10 |
11 | 11 |
12 class RecordEntry: | |
13 """ An entry in a record, for a specific content item. | |
14 """ | |
15 def __init__(self): | |
16 self.item_spec = None | |
17 self.errors = [] | |
18 | |
19 @property | |
20 def success(self): | |
21 return len(self.errors) == 0 | |
22 | |
23 def describe(self): | |
24 return {} | |
25 | |
26 def getAllOutputPaths(self): | |
27 return None | |
28 | |
29 def getAllErrors(self): | |
30 return self.errors | |
31 | |
32 | |
33 class Record: | |
34 """ A class that represents a 'record' of a bake operation on a | |
35 content source. | |
36 """ | |
37 def __init__(self, name): | |
38 self.name = name | |
39 self.deleted_out_paths = [] | |
40 self.success = True | |
41 self._entries = {} | |
42 | |
43 def addEntry(self, entry): | |
44 if entry.item_spec in self._entries: | |
45 raise ValueError("Entry '%s' is already in the record." % | |
46 entry.item_spec) | |
47 self._entries[entry.item_spec] = entry | |
48 | |
49 def getEntries(self): | |
50 return self._entries.values() | |
51 | |
52 def getEntry(self, item_spec): | |
53 return self._entries[item_spec] | |
54 | |
55 | |
12 class MultiRecord: | 56 class MultiRecord: |
13 """ A container that includes multiple `Record` instances. | 57 """ A container that includes multiple `Record` instances -- one for |
58 each content source that was baked. | |
14 """ | 59 """ |
15 RECORD_VERSION = 12 | 60 RECORD_VERSION = 12 |
16 | 61 |
17 def __init__(self): | 62 def __init__(self): |
18 self.records = [] | 63 self.records = [] |
47 logger.debug("Loading bake records from: %s" % path) | 92 logger.debug("Loading bake records from: %s" % path) |
48 with open(path, 'rb') as fp: | 93 with open(path, 'rb') as fp: |
49 return pickle.load(fp) | 94 return pickle.load(fp) |
50 | 95 |
51 | 96 |
52 class Record: | 97 def get_flag_descriptions(flags, flag_descriptions): |
53 """ A basic class that represents a 'record' of a bake operation on a | 98 res = [] |
54 content source. | 99 for k, v in flag_descriptions.items(): |
55 """ | 100 if flags & k: |
56 def __init__(self, name): | 101 res.append(v) |
57 self.name = name | 102 if res: |
58 self.entries = [] | 103 return ', '.join(res) |
59 self.deleted_out_paths = [] | 104 return 'none' |
60 self.success = True | |
61 | |
62 | |
63 class RecordEntry: | |
64 """ An entry in a record, for a specific content item. | |
65 """ | |
66 def __init__(self): | |
67 self.item_spec = None | |
68 self.out_paths = [] | |
69 self.errors = [] | |
70 | |
71 @property | |
72 def success(self): | |
73 return len(self.errors) == 0 | |
74 | |
75 def describe(self): | |
76 return {} | |
77 | 105 |
78 | 106 |
79 def _are_records_valid(multi_record): | 107 def _are_records_valid(multi_record): |
80 return (multi_record._app_version == APP_VERSION and | 108 return (multi_record._app_version == APP_VERSION and |
81 multi_record._record_version == MultiRecord.RECORD_VERSION) | 109 multi_record._record_version == MultiRecord.RECORD_VERSION) |
104 multi_record.invalidated = was_invalid | 132 multi_record.invalidated = was_invalid |
105 | 133 |
106 return multi_record | 134 return multi_record |
107 | 135 |
108 | 136 |
109 def _build_diff_key(item_spec): | 137 class RecordHistory: |
110 return hashlib.md5(item_spec.encode('utf8')).hexdigest() | 138 def __init__(self, previous, current): |
139 if previous is None or current is None: | |
140 raise ValueError() | |
141 | |
142 if previous.name != current.name: | |
143 raise Exception("The two records must have the same name! " | |
144 "Got '%s' and '%s'." % | |
145 (previous.name, current.name)) | |
146 | |
147 self._previous = previous | |
148 self._current = current | |
149 self._diffs = None | |
150 | |
151 @property | |
152 def name(self): | |
153 return self._current.name | |
154 | |
155 @property | |
156 def current(self): | |
157 return self._current | |
158 | |
159 @property | |
160 def previous(self): | |
161 return self._previous | |
162 | |
163 @property | |
164 def diffs(self): | |
165 if self._diffs is None: | |
166 raise Exception("This record history hasn't been built yet.") | |
167 return self._diffs.values() | |
168 | |
169 def getPreviousEntry(self, item_spec): | |
170 key = _build_diff_key(item_spec) | |
171 return self._diffs[key][0] | |
172 | |
173 def getCurrentEntry(self, item_spec): | |
174 key = _build_diff_key(item_spec) | |
175 return self._diffs[key][1] | |
176 | |
177 def build(self): | |
178 if self._diffs is not None: | |
179 raise Exception("This record history has already been built.") | |
180 | |
181 self._diffs = {} | |
182 if self._previous is not None: | |
183 for e in self._previous.getEntries(): | |
184 key = _build_diff_key(e.item_spec) | |
185 self._diffs[key] = (e, None) | |
186 | |
187 if self._current is not None: | |
188 for e in self._current.getEntries(): | |
189 key = _build_diff_key(e.item_spec) | |
190 diff = self._diffs.get(key) | |
191 if diff is None: | |
192 self._diffs[key] = (None, e) | |
193 elif diff[1] is None: | |
194 self._diffs[key] = (diff[0], e) | |
195 else: | |
196 raise Exception( | |
197 "A current record entry already exists for '%s' " | |
198 "(%s)" % (key, diff[1].item_spec)) | |
111 | 199 |
112 | 200 |
113 class MultiRecordHistory: | 201 class MultiRecordHistory: |
114 """ Tracks the differences between an 'old' and a 'new' record | 202 """ Tracks the differences between an 'old' and a 'new' record |
115 container. | 203 container. |
119 raise ValueError() | 207 raise ValueError() |
120 | 208 |
121 self.previous = previous | 209 self.previous = previous |
122 self.current = current | 210 self.current = current |
123 self.histories = [] | 211 self.histories = [] |
124 self._buildHistories(previous, current) | 212 self._linkHistories(previous, current) |
213 | |
214 def getPreviousRecord(self, record_name, auto_create=True): | |
215 return self.previous.getRecord(record_name, auto_create=auto_create) | |
216 | |
217 def getCurrentRecord(self, record_name): | |
218 return self.current.getRecord(record_name) | |
125 | 219 |
126 def getHistory(self, record_name): | 220 def getHistory(self, record_name): |
127 for h in self.histories: | 221 for h in self.histories: |
128 if h.name == record_name: | 222 if h.name == record_name: |
129 return h | 223 return h |
224 | |
130 rh = RecordHistory( | 225 rh = RecordHistory( |
131 Record(record_name), | 226 Record(record_name), |
132 Record(record_name)) | 227 Record(record_name)) |
133 self.histories.append(rh) | 228 self.histories.append(rh) |
134 self.previous.records.append(rh.previous) | 229 self.previous.records.append(rh.previous) |
135 self.current.records.append(rh.current) | 230 self.current.records.append(rh.current) |
136 return rh | 231 return rh |
137 | 232 |
138 def _buildHistories(self, previous, current): | 233 def _linkHistories(self, previous, current): |
139 pairs = {} | 234 pairs = {} |
140 if previous: | 235 if previous: |
141 for r in previous.records: | 236 for r in previous.records: |
142 pairs[r.name] = (r, None) | 237 pairs[r.name] = (r, None) |
143 if current: | 238 if current: |
156 c = Record(name) | 251 c = Record(name) |
157 current.records.append(c) | 252 current.records.append(c) |
158 self.histories.append(RecordHistory(p, c)) | 253 self.histories.append(RecordHistory(p, c)) |
159 | 254 |
160 | 255 |
161 class RecordHistory: | 256 def _build_diff_key(item_spec): |
162 def __init__(self, previous, current): | 257 return hashlib.md5(item_spec.encode('utf8')).hexdigest() |
163 if previous is None or current is None: | 258 |
164 raise ValueError() | |
165 | |
166 if previous.name != current.name: | |
167 raise Exception("The two records must have the same name! " | |
168 "Got '%s' and '%s'." % | |
169 (previous.name, current.name)) | |
170 | |
171 self._previous = previous | |
172 self._current = current | |
173 self._diffs = None | |
174 | |
175 @property | |
176 def name(self): | |
177 return self._current.name | |
178 | |
179 @property | |
180 def current(self): | |
181 return self._current | |
182 | |
183 @property | |
184 def previous(self): | |
185 return self._previous | |
186 | |
187 @property | |
188 def diffs(self): | |
189 if self._diffs is None: | |
190 raise Exception("This record history hasn't been built yet.") | |
191 return self._diffs.values() | |
192 | |
193 def build(self): | |
194 if self._diffs is not None: | |
195 raise Exception("This record history has already been built.") | |
196 | |
197 self._diffs = {} | |
198 if self._previous is not None: | |
199 for e in self._previous.entries: | |
200 key = _build_diff_key(e.item_spec) | |
201 self._diffs[key] = (e, None) | |
202 | |
203 if self._current is not None: | |
204 for e in self._current.entries: | |
205 key = _build_diff_key(e.item_spec) | |
206 diff = self._diffs.get(key) | |
207 if diff is None: | |
208 self._diffs[key] = (None, e) | |
209 elif diff[1] is None: | |
210 self._diffs[key] = (diff[0], e) | |
211 else: | |
212 raise Exception( | |
213 "A current record entry already exists for: %s" % key) | |
214 |