Mercurial > piecrust2
comparison piecrust/pipelines/records.py @ 853:f070a4fc033c
core: Continue PieCrust3 refactor, simplify pages.
The asset pipeline is still the only function pipeline at this point.
* No more `QualifiedPage`, and several other pieces of code deleted.
* Data providers are simpler and more focused. For instance, the page iterator
doesn't try to support other types of items.
* Route parameters are proper known source metadata to remove the confusion
between the two.
* Make the baker and pipeline more correctly manage records and record
histories.
* Add support for record collapsing and deleting stale outputs in the asset
pipeline.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 21 May 2017 00:06:59 -0700 |
parents | 4850f8c21b6e |
children | 08e02c2a2a1a |
comparison
equal
deleted
inserted
replaced
852:4850f8c21b6e | 853:f070a4fc033c |
---|---|
8 | 8 |
9 logger = logging.getLogger(__name__) | 9 logger = logging.getLogger(__name__) |
10 | 10 |
11 | 11 |
12 class MultiRecord: | 12 class MultiRecord: |
13 """ A container that includes multiple `Record` instances. | |
14 """ | |
13 RECORD_VERSION = 12 | 15 RECORD_VERSION = 12 |
14 | 16 |
15 def __init__(self): | 17 def __init__(self): |
16 self.records = [] | 18 self.records = [] |
17 self.success = True | 19 self.success = True |
26 for r in self.records: | 28 for r in self.records: |
27 if r.name == record_name: | 29 if r.name == record_name: |
28 return r | 30 return r |
29 if not auto_create: | 31 if not auto_create: |
30 return None | 32 return None |
31 record = Record() | 33 record = Record(record_name) |
32 self.records.append(record) | 34 self.records.append(record) |
33 return record | 35 return record |
34 | 36 |
35 def save(self, path): | 37 def save(self, path): |
36 path_dir = os.path.dirname(path) | 38 path_dir = os.path.dirname(path) |
46 with open(path, 'rb') as fp: | 48 with open(path, 'rb') as fp: |
47 return pickle.load(fp) | 49 return pickle.load(fp) |
48 | 50 |
49 | 51 |
50 class Record: | 52 class Record: |
51 def __init__(self): | 53 """ A basic class that represents a 'record' of a bake operation on a |
52 self.name = None | 54 content source. |
55 """ | |
56 def __init__(self, name): | |
57 self.name = name | |
53 self.entries = [] | 58 self.entries = [] |
54 self.stats = {} | 59 self.deleted_out_paths = [] |
55 self.out_dir = None | |
56 self.success = True | 60 self.success = True |
57 | 61 |
58 | 62 |
59 class RecordEntry: | 63 class RecordEntry: |
64 """ An entry in a record, for a specific content item. | |
65 """ | |
60 def __init__(self): | 66 def __init__(self): |
61 self.item_spec = None | 67 self.item_spec = None |
68 self.out_paths = [] | |
62 self.errors = [] | 69 self.errors = [] |
63 | 70 |
64 @property | 71 @property |
65 def success(self): | 72 def success(self): |
66 return len(self.errors) == 0 | 73 return len(self.errors) == 0 |
74 | |
75 def describe(self): | |
76 return {} | |
67 | 77 |
68 | 78 |
69 def _are_records_valid(multi_record): | 79 def _are_records_valid(multi_record): |
70 return (multi_record._app_version == APP_VERSION and | 80 return (multi_record._app_version == APP_VERSION and |
71 multi_record._record_version == MultiRecord.RECORD_VERSION) | 81 multi_record._record_version == MultiRecord.RECORD_VERSION) |
99 def _build_diff_key(item_spec): | 109 def _build_diff_key(item_spec): |
100 return hashlib.md5(item_spec.encode('utf8')).hexdigest() | 110 return hashlib.md5(item_spec.encode('utf8')).hexdigest() |
101 | 111 |
102 | 112 |
103 class MultiRecordHistory: | 113 class MultiRecordHistory: |
114 """ Tracks the differences between an 'old' and a 'new' record | |
115 container. | |
116 """ | |
104 def __init__(self, previous, current): | 117 def __init__(self, previous, current): |
105 if previous is None or current is None: | 118 if previous is None or current is None: |
106 raise ValueError() | 119 raise ValueError() |
107 | 120 |
108 self.previous = previous | 121 self.previous = previous |
112 | 125 |
113 def getHistory(self, record_name): | 126 def getHistory(self, record_name): |
114 for h in self.histories: | 127 for h in self.histories: |
115 if h.name == record_name: | 128 if h.name == record_name: |
116 return h | 129 return h |
117 return None | 130 rh = RecordHistory( |
131 Record(record_name), | |
132 Record(record_name)) | |
133 self.histories.append(rh) | |
134 self.previous.records.append(rh.previous) | |
135 self.current.records.append(rh.current) | |
136 return rh | |
118 | 137 |
119 def _buildHistories(self, previous, current): | 138 def _buildHistories(self, previous, current): |
120 pairs = {} | 139 pairs = {} |
121 if previous: | 140 if previous: |
122 for r in previous.records: | 141 for r in previous.records: |
126 p = pairs.get(r.name, (None, None)) | 145 p = pairs.get(r.name, (None, None)) |
127 if p[1] is not None: | 146 if p[1] is not None: |
128 raise Exception("Got several records named: %s" % r.name) | 147 raise Exception("Got several records named: %s" % r.name) |
129 pairs[r.name] = (p[0], r) | 148 pairs[r.name] = (p[0], r) |
130 | 149 |
131 for p, c in pairs.values(): | 150 for name, pair in pairs.items(): |
151 p, c = pair | |
152 if p is None: | |
153 p = Record(name) | |
154 previous.records.append(p) | |
155 if c is None: | |
156 c = Record(name) | |
157 current.records.append(c) | |
132 self.histories.append(RecordHistory(p, c)) | 158 self.histories.append(RecordHistory(p, c)) |
133 | 159 |
134 | 160 |
135 class RecordHistory: | 161 class RecordHistory: |
136 def __init__(self, previous, current): | 162 def __init__(self, previous, current): |
137 self._diffs = {} | 163 if previous is None or current is None: |
138 self._previous = previous | 164 raise ValueError() |
139 self._current = current | 165 |
140 | 166 if previous.name != current.name: |
141 if previous and current and previous.name != current.name: | |
142 raise Exception("The two records must have the same name! " | 167 raise Exception("The two records must have the same name! " |
143 "Got '%s' and '%s'." % | 168 "Got '%s' and '%s'." % |
144 (previous.name, current.name)) | 169 (previous.name, current.name)) |
145 | 170 |
146 self._buildDiffs() | 171 self._previous = previous |
172 self._current = current | |
173 self._diffs = None | |
147 | 174 |
148 @property | 175 @property |
149 def name(self): | 176 def name(self): |
150 return self._current.name | 177 return self._current.name |
151 | 178 |
157 def previous(self): | 184 def previous(self): |
158 return self._previous | 185 return self._previous |
159 | 186 |
160 @property | 187 @property |
161 def diffs(self): | 188 def diffs(self): |
189 if self._diffs is None: | |
190 raise Exception("This record history hasn't been built yet.") | |
162 return self._diffs.values() | 191 return self._diffs.values() |
163 | 192 |
164 def _buildDiffs(self): | 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 = {} | |
165 if self._previous is not None: | 198 if self._previous is not None: |
166 for e in self._previous.entries: | 199 for e in self._previous.entries: |
167 key = _build_diff_key(e.item_spec) | 200 key = _build_diff_key(e.item_spec) |
168 self._diffs[key] = (e, None) | 201 self._diffs[key] = (e, None) |
169 | 202 |