Mercurial > piecrust2
comparison piecrust/sources/blogarchives.py @ 852:4850f8c21b6e
core: Start of the big refactor for PieCrust 3.0.
* Everything is a `ContentSource`, including assets directories.
* Most content sources are subclasses of the base file-system source.
* A source is processed by a "pipeline", and there are 2 built-in pipelines,
one for assets and one for pages. The asset pipeline is vaguely functional,
but the page pipeline is completely broken right now.
* Rewrite the baking process as just running appropriate pipelines on each
content item. This should allow for better parallelization.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 17 May 2017 00:11:48 -0700 |
parents | |
children | f070a4fc033c |
comparison
equal
deleted
inserted
replaced
851:2c7e57d80bba | 852:4850f8c21b6e |
---|---|
1 import logging | |
2 import datetime | |
3 from piecrust.chefutil import format_timed_scope | |
4 from piecrust.data.filters import PaginationFilter, IFilterClause | |
5 from piecrust.data.iterators import PageIterator | |
6 from piecrust.routing import RouteParameter | |
7 from piecrust.sources.base import ContentSource, GeneratedContentException | |
8 | |
9 | |
10 logger = logging.getLogger(__name__) | |
11 | |
12 | |
13 class BlogArchivesSource(ContentSource): | |
14 SOURCE_NAME = 'blog_archives' | |
15 | |
16 def __init__(self, app, name, config): | |
17 super().__init__(app, name, config) | |
18 | |
19 def getContents(self, group): | |
20 raise GeneratedContentException() | |
21 | |
22 def prepareRenderContext(self, ctx): | |
23 ctx.pagination_source = self.source | |
24 | |
25 year = ctx.page.route_metadata.get('year') | |
26 if year is None: | |
27 raise Exception( | |
28 "Can't find the archive year in the route metadata") | |
29 if type(year) is not int: | |
30 raise Exception( | |
31 "The route for generator '%s' should specify an integer " | |
32 "parameter for 'year'." % self.name) | |
33 | |
34 flt = PaginationFilter() | |
35 flt.addClause(IsFromYearFilterClause(year)) | |
36 ctx.pagination_filter = flt | |
37 | |
38 ctx.custom_data['year'] = year | |
39 | |
40 flt2 = PaginationFilter() | |
41 flt2.addClause(IsFromYearFilterClause(year)) | |
42 it = PageIterator(self.source, pagination_filter=flt2, | |
43 sorter=_date_sorter) | |
44 ctx.custom_data['archives'] = it | |
45 | |
46 def bake(self, ctx): | |
47 if not self.page_ref.exists: | |
48 logger.debug( | |
49 "No page found at '%s', skipping %s archives." % | |
50 (self.page_ref, self.source_name)) | |
51 return | |
52 | |
53 logger.debug("Baking %s archives...", self.source_name) | |
54 with format_timed_scope(logger, 'gathered archive years', | |
55 level=logging.DEBUG, colored=False): | |
56 all_years, dirty_years = self._buildDirtyYears(ctx) | |
57 | |
58 with format_timed_scope(logger, "baked %d %s archives." % | |
59 (len(dirty_years), self.source_name)): | |
60 self._bakeDirtyYears(ctx, all_years, dirty_years) | |
61 | |
62 def _getSource(self): | |
63 return self.app.getSource(self.config['source']) | |
64 | |
65 def _buildDirtyYears(self, ctx): | |
66 logger.debug("Gathering dirty post years.") | |
67 all_years = set() | |
68 dirty_years = set() | |
69 for _, cur_entry in ctx.getAllPageRecords(): | |
70 if cur_entry and cur_entry.source_name == self.source_name: | |
71 dt = datetime.datetime.fromtimestamp(cur_entry.timestamp) | |
72 all_years.add(dt.year) | |
73 if cur_entry.was_any_sub_baked: | |
74 dirty_years.add(dt.year) | |
75 return all_years, dirty_years | |
76 | |
77 def _bakeDirtyYears(self, ctx, all_years, dirty_years): | |
78 route = self.app.getGeneratorRoute(self.name) | |
79 if route is None: | |
80 raise Exception( | |
81 "No routes have been defined for generator: %s" % | |
82 self.name) | |
83 | |
84 logger.debug("Using archive page: %s" % self.page_ref) | |
85 fac = self.page_ref.getFactory() | |
86 | |
87 for y in dirty_years: | |
88 extra_route_metadata = {'year': y} | |
89 | |
90 logger.debug("Queuing: %s [%s]" % (fac.ref_spec, y)) | |
91 ctx.queueBakeJob(fac, route, extra_route_metadata, str(y)) | |
92 ctx.runJobQueue() | |
93 | |
94 # Create bake entries for the years that were *not* dirty. | |
95 # Otherwise, when checking for deleted pages, we would not find any | |
96 # outputs and would delete those files. | |
97 all_str_years = [str(y) for y in all_years] | |
98 for prev_entry, cur_entry in ctx.getAllPageRecords(): | |
99 if prev_entry and not cur_entry: | |
100 try: | |
101 y = ctx.getSeedFromRecordExtraKey(prev_entry.extra_key) | |
102 except InvalidRecordExtraKey: | |
103 continue | |
104 if y in all_str_years: | |
105 logger.debug( | |
106 "Creating unbaked entry for year %s archive." % y) | |
107 ctx.collapseRecord(prev_entry) | |
108 else: | |
109 logger.debug( | |
110 "No page references year %s anymore." % y) | |
111 | |
112 def getSupportedRouteParameters(self): | |
113 return [RouteParameter('year', RouteParameter.TYPE_INT4)] | |
114 | |
115 | |
116 class IsFromYearFilterClause(IFilterClause): | |
117 def __init__(self, year): | |
118 self.year = year | |
119 | |
120 def pageMatches(self, fil, page): | |
121 return (page.datetime.year == self.year) | |
122 | |
123 | |
124 def _date_sorter(it): | |
125 return sorted(it, key=lambda x: x.datetime) | |
126 |