comparison piecrust/sources/taxonomy.py @ 989:8adc27285d93

bake: Big pass on bake performance. - Reduce the amount of data passed between processes. - Make inter-process data simple objects to make it easier to test with alternatives to pickle. - Make sources have the basic requirement to be able to find a content item from an item spec (path). - Make Hoedown the default Markdown formatter.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 19 Nov 2017 14:29:17 -0800
parents 45ad976712ec
children 1857dbd4580f
comparison
equal deleted inserted replaced
988:f83ae0a5d793 989:8adc27285d93
5 from piecrust.configuration import ConfigurationError 5 from piecrust.configuration import ConfigurationError
6 from piecrust.data.filters import ( 6 from piecrust.data.filters import (
7 PaginationFilter, SettingFilterClause) 7 PaginationFilter, SettingFilterClause)
8 from piecrust.page import Page 8 from piecrust.page import Page
9 from piecrust.pipelines._pagebaker import PageBaker 9 from piecrust.pipelines._pagebaker import PageBaker
10 from piecrust.pipelines._pagerecords import PagePipelineRecordEntry 10 from piecrust.pipelines._pagerecords import (
11 PagePipelineRecordEntry,
12 add_page_job_result, merge_job_result_into_record_entry)
11 from piecrust.pipelines.base import ( 13 from piecrust.pipelines.base import (
12 ContentPipeline, get_record_name_for_source) 14 ContentPipeline, get_record_name_for_source,
15 create_job, content_item_from_job)
13 from piecrust.pipelines.records import RecordHistory 16 from piecrust.pipelines.records import RecordHistory
14 from piecrust.routing import RouteParameter 17 from piecrust.routing import RouteParameter
15 from piecrust.sources.base import ContentItem 18 from piecrust.sources.base import ContentItem
16 from piecrust.sources.generator import GeneratorSourceBase 19 from piecrust.sources.generator import GeneratorSourceBase
17 20
81 param_type = (RouteParameter.TYPE_PATH if self.taxonomy.is_multiple 84 param_type = (RouteParameter.TYPE_PATH if self.taxonomy.is_multiple
82 else RouteParameter.TYPE_STRING) 85 else RouteParameter.TYPE_STRING)
83 return [RouteParameter(name, param_type, 86 return [RouteParameter(name, param_type,
84 variadic=self.taxonomy.is_multiple)] 87 variadic=self.taxonomy.is_multiple)]
85 88
86 def findContent(self, route_params): 89 def findContentFromRoute(self, route_params):
87 slugified_term = route_params[self.taxonomy.term_name] 90 slugified_term = route_params[self.taxonomy.term_name]
88 spec = '_index' 91 spec = '_index'
89 metadata = {'term': slugified_term, 92 metadata = {'term': slugified_term,
90 'record_entry_spec': '_index[%s]' % slugified_term,
91 'route_params': { 93 'route_params': {
92 self.taxonomy.term_name: slugified_term} 94 self.taxonomy.term_name: slugified_term}
93 } 95 }
94 return ContentItem(spec, metadata) 96 return ContentItem(spec, metadata)
95 97
172 slugified_values = self.slugify(str(values)) 174 slugified_values = self.slugify(str(values))
173 route_val = slugified_values 175 route_val = slugified_values
174 176
175 # We need to register this use of a taxonomy term. 177 # We need to register this use of a taxonomy term.
176 rcs = self.app.env.render_ctx_stack 178 rcs = self.app.env.render_ctx_stack
177 cpi = rcs.current_ctx.current_pass_info 179 ri = rcs.current_ctx.render_info
178 if cpi: 180 utt = ri.get('used_taxonomy_terms')
179 utt = cpi.getCustomInfo('used_taxonomy_terms') 181 if utt is None:
180 if utt is None: 182 utt = set()
181 utt = set() 183 utt.add(slugified_values)
182 utt.add(slugified_values) 184 ri['used_taxonomy_terms'] = utt
183 cpi.setCustomInfo('used_taxonomy_terms', utt) 185 else:
184 else: 186 utt.add(slugified_values)
185 utt.add(slugified_values)
186 187
187 # Put the slugified values in the route metadata so they're used to 188 # Put the slugified values in the route metadata so they're used to
188 # generate the URL. 189 # generate the URL.
189 route_params[self.taxonomy.term_name] = route_val 190 route_params[self.taxonomy.term_name] = route_val
190 191
285 286
286 logger.debug("Queuing %d '%s' jobs." % 287 logger.debug("Queuing %d '%s' jobs." %
287 (len(self._analyzer.dirty_slugified_terms), 288 (len(self._analyzer.dirty_slugified_terms),
288 self.taxonomy.name)) 289 self.taxonomy.name))
289 jobs = [] 290 jobs = []
291 rec_fac = self.createRecordEntry
292 current_record = ctx.current_record
293
290 for slugified_term in self._analyzer.dirty_slugified_terms: 294 for slugified_term in self._analyzer.dirty_slugified_terms:
291 item = ContentItem( 295 item_spec = '_index'
292 '_index', 296 record_entry_spec = '_index[%s]' % slugified_term
293 {'term': slugified_term, 297
294 'record_entry_spec': '_index[%s]' % slugified_term, 298 jobs.append(create_job(self, item_spec,
295 'route_params': { 299 term=slugified_term,
296 self.taxonomy.term_name: slugified_term} 300 record_entry_spec=record_entry_spec))
297 }) 301
298 jobs.append(self.createJob(item)) 302 entry = rec_fac(record_entry_spec)
303 current_record.addEntry(entry)
304
299 if len(jobs) > 0: 305 if len(jobs) > 0:
300 return jobs 306 return jobs
301 return None 307 return None
302 308
303 def run(self, job, ctx, result): 309 def run(self, job, ctx, result):
304 content_item = job.content_item 310 term = job['term']
311 content_item = ContentItem('_index',
312 {'term': term,
313 'route_params': {
314 self.taxonomy.term_name: term}
315 })
316 page = Page(self.source, content_item)
317
305 logger.debug("Rendering '%s' page: %s" % 318 logger.debug("Rendering '%s' page: %s" %
306 (self.taxonomy.name, content_item.metadata['term'])) 319 (self.taxonomy.name, page.source_metadata['term']))
307
308 page = Page(self.source, job.content_item)
309 prev_entry = ctx.previous_entry 320 prev_entry = ctx.previous_entry
310 cur_entry = result.record_entry 321 rdr_subs = self._pagebaker.bake(page, prev_entry)
311 cur_entry.term = content_item.metadata['term'] 322
312 self._pagebaker.bake(page, prev_entry, cur_entry) 323 add_page_job_result(result)
324 result['subs'] = rdr_subs
325 result['term'] = page.source_metadata['term']
326
327 def handleJobResult(self, result, ctx):
328 existing = ctx.record_entry
329 merge_job_result_into_record_entry(existing, result)
330 existing.term = result['term']
313 331
314 def postJobRun(self, ctx): 332 def postJobRun(self, ctx):
315 # We create bake entries for all the terms that were *not* dirty. 333 # We create bake entries for all the terms that were *not* dirty.
316 # This is because otherwise, on the next incremental bake, we wouldn't 334 # This is because otherwise, on the next incremental bake, we wouldn't
317 # find any entry for those things, and figure that we need to delete 335 # find any entry for those things, and figure that we need to delete
379 self._addTerms( 397 self._addTerms(
380 slugifier, cur_entry.item_spec, cur_terms) 398 slugifier, cur_entry.item_spec, cur_terms)
381 399
382 # Re-bake all taxonomy terms that include new or changed pages, by 400 # Re-bake all taxonomy terms that include new or changed pages, by
383 # marking them as 'dirty'. 401 # marking them as 'dirty'.
384 previous_records = self.record_histories.previous 402 history = self.record_histories.getHistory(record_name).copy()
385 prev_rec = previous_records.getRecord(record_name)
386 history = RecordHistory(prev_rec, cur_rec)
387 history.build() 403 history.build()
388 for prev_entry, cur_entry in history.diffs: 404 for prev_entry, cur_entry in history.diffs:
389 entries = [cur_entry] 405 entries = [cur_entry]
390 if prev_entry: 406 if prev_entry:
391 entries.append(prev_entry) 407 entries.append(prev_entry)
460 476
461 477
462 def _get_all_entry_taxonomy_terms(entry): 478 def _get_all_entry_taxonomy_terms(entry):
463 res = set() 479 res = set()
464 for o in entry.subs: 480 for o in entry.subs:
465 for pinfo in o.render_info: 481 pinfo = o['render_info']
466 if pinfo: 482 terms = pinfo.get('used_taxonomy_terms')
467 terms = pinfo.getCustomInfo('used_taxonomy_terms') 483 if terms:
468 if terms: 484 res |= set(terms)
469 res |= set(terms)
470 return res 485 return res
471 486
472 487
473 class _Slugifier(object): 488 class _Slugifier(object):
474 def __init__(self, taxonomy, mode): 489 def __init__(self, taxonomy, mode):