comparison piecrust/generation/blogarchives.py @ 724:09115f0900f0

bake: Add blog archives generator.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 29 May 2016 20:20:19 -0700
parents ab5c6a8ae90a
children e35407c60e00
comparison
equal deleted inserted replaced
723:606f6d57b5df 724:09115f0900f0
1 import logging
2 import datetime
3 from piecrust.data.filters import PaginationFilter, IFilterClause
1 from piecrust.generation.base import PageGenerator 4 from piecrust.generation.base import PageGenerator
5
6
7 logger = logging.getLogger(__name__)
2 8
3 9
4 class BlogArchivesPageGenerator(PageGenerator): 10 class BlogArchivesPageGenerator(PageGenerator):
5 GENERATOR_NAME = 'blog_archives' 11 GENERATOR_NAME = 'blog_archives'
6 12
7 def bake(self, ctx): 13 def __init__(self, app, name, config):
14 super(BlogArchivesPageGenerator, self).__init__(app, name, config)
15
16 def onRouteFunctionUsed(self, route, route_metadata):
8 pass 17 pass
9 18
19 def prepareRenderContext(self, ctx):
20 ctx.pagination_source = self.source
21
22 year = ctx.page.route_metadata.get('year')
23 if year is None:
24 raise Exception(
25 "Can't find the archive year in the route metadata")
26 if type(year) is not int:
27 raise Exception(
28 "The route for generator '%s' should specify an integer "
29 "parameter for 'year'." % self.name)
30
31 flt = PaginationFilter()
32 flt.addClause(IsFromYearFilterClause(year))
33 ctx.pagination_filter = flt
34
35 ctx.custom_data['year'] = year
36
37 def bake(self, ctx):
38 if not self.page_ref.exists:
39 logger.debug(
40 "No page found at '%s', skipping %s archives." %
41 (self.page_ref, self.source_name))
42 return
43
44 logger.debug("Baking %s archives...", self.source_name)
45 with format_timed_scope(logger, 'gathered archive years',
46 level=logging.DEBUG, colored=False):
47 all_years, dirty_years = self._buildDirtyYears(ctx)
48
49 with format_timed_scope(logger, "baked %d %s archives." %
50 (len(dirty_years), self.source_name)):
51 self._bakeDirtyYears(ctx, all_years, dirty_years)
52
53 def _buildDirtyYears(self, ctx):
54 logger.debug("Gathering dirty post years.")
55 all_years = set()
56 dirty_years = set()
57 for _, cur_entry in ctx.getAllPageRecords():
58 if cur_entry.source_name == self.source_name:
59 dt = datetime.datetime.fromtimestamp(cur_entry.timestamp)
60 all_years.add(dt.year)
61 if cur_entry.was_any_sub_baked:
62 dirty_years.add(dt.year)
63 return all_years, dirty_years
64
65 def _bakeDirtyYears(self, ctx, all_years, dirty_years):
66 route = self.app.getGeneratorRoute(self.name)
67 if route is None:
68 raise Exception(
69 "No routes have been defined for generator: %s" %
70 self.name)
71
72 logger.debug("Using archive page: %s" % self.page_ref)
73 fac = self.page_ref.getFactory()
74
75 for y in dirty_years:
76 extra_route_metadata = {'year': y}
77
78 logger.debug("Queuing: %s [%s]" % (fac.ref_spec, y))
79 ctx.queueBakeJob(fac, route, extra_route_metadata, str(y))
80 ctx.runJobQueue()
81
82 # Create bake entries for the years that were *not* dirty.
83 # Otherwise, when checking for deleted pages, we would not find any
84 # outputs and would delete those files.
85 for prev_entry, cur_entry in ctx.getAllPageRecords():
86 if prev_entry and not cur_entry:
87 try:
88 y = ctx.getSeedFromRecordExtraKey(prev_entry.extra_key)
89 except InvalidRecordExtraKey:
90 continue
91 if y in all_years:
92 logger.debug("Creating unbaked entry for %d archive." % y)
93 ctx.collapseRecord(prev_entry)
94 else:
95 logger.debug("No page references year %d anymore." % y)
96
97
98 class IsFromYearFilterClause(IFilterClause):
99 def __init__(self, year):
100 self.year = year
101
102 def pageMatches(self, fil, page):
103 return (page.datetime.year == self.year)
104