comparison piecrust/pipelines/_pagebaker.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 4850f8c21b6e
children 504ddb370df8
comparison
equal deleted inserted replaced
853:f070a4fc033c 854:08e02c2a2a1a
23 self.copy_assets = copy_assets 23 self.copy_assets = copy_assets
24 self.site_root = app.config.get('site/root') 24 self.site_root = app.config.get('site/root')
25 self.pretty_urls = app.config.get('site/pretty_urls') 25 self.pretty_urls = app.config.get('site/pretty_urls')
26 self._writer_queue = None 26 self._writer_queue = None
27 self._writer = None 27 self._writer = None
28 self._stats = app.env.stats
28 29
29 def startWriterQueue(self): 30 def startWriterQueue(self):
30 self._writer_queue = queue.Queue() 31 self._writer_queue = queue.Queue()
31 self._writer = threading.Thread( 32 self._writer = threading.Thread(
32 name='PageSerializer', 33 name='PageSerializer',
51 else: 52 else:
52 bake_path.append(decoded_uri) 53 bake_path.append(decoded_uri)
53 54
54 return os.path.normpath(os.path.join(*bake_path)) 55 return os.path.normpath(os.path.join(*bake_path))
55 56
56 def bake(self, qualified_page, prev_entry, dirty_source_names): 57 def bake(self, page, prev_entry, cur_entry, dirty_source_names):
57 # Start baking the sub-pages. 58 # Start baking the sub-pages.
58 cur_sub = 1 59 cur_sub = 1
59 has_more_subs = True 60 has_more_subs = True
60 sub_entries = [] 61 pretty_urls = page.config.get('pretty_urls', self.pretty_urls)
61 pretty_urls = qualified_page.config.get(
62 'pretty_urls', self.pretty_urls)
63 62
64 while has_more_subs: 63 while has_more_subs:
65 sub_page = qualified_page.getSubPage(cur_sub) 64 sub_uri = page.getUri(sub_num=cur_sub)
66 sub_uri = sub_page.uri
67 logger.debug("Baking '%s' [%d]..." % (sub_uri, cur_sub)) 65 logger.debug("Baking '%s' [%d]..." % (sub_uri, cur_sub))
68 66
69 out_path = self.getOutputPath(sub_uri, pretty_urls) 67 out_path = self.getOutputPath(sub_uri, pretty_urls)
70 68
71 # Create the sub-entry for the bake record. 69 # Create the sub-entry for the bake record.
72 sub_entry = SubPagePipelineRecordEntry(sub_uri, out_path) 70 sub_entry = SubPagePipelineRecordEntry(sub_uri, out_path)
73 sub_entries.append(sub_entry) 71 cur_entry.subs.append(sub_entry)
74 72
75 # Find a corresponding sub-entry in the previous bake record. 73 # Find a corresponding sub-entry in the previous bake record.
76 prev_sub_entry = None 74 prev_sub_entry = None
77 if prev_entry is not None: 75 if prev_entry is not None:
78 try: 76 try:
87 85
88 # Check for up-to-date outputs. 86 # Check for up-to-date outputs.
89 do_bake = True 87 do_bake = True
90 if not force_this_sub: 88 if not force_this_sub:
91 try: 89 try:
92 in_path_time = qualified_page.path_mtime 90 in_path_time = page.content_mtime
93 out_path_time = os.path.getmtime(out_path) 91 out_path_time = os.path.getmtime(out_path)
94 if out_path_time >= in_path_time: 92 if out_path_time >= in_path_time:
95 do_bake = False 93 do_bake = False
96 except OSError: 94 except OSError:
97 # File doesn't exist, we'll need to bake. 95 # File doesn't exist, we'll need to bake.
121 cache_key) 119 cache_key)
122 sub_entry.flags |= \ 120 sub_entry.flags |= \
123 SubPagePipelineRecordEntry.FLAG_FORMATTING_INVALIDATED 121 SubPagePipelineRecordEntry.FLAG_FORMATTING_INVALIDATED
124 122
125 logger.debug(" p%d -> %s" % (cur_sub, out_path)) 123 logger.debug(" p%d -> %s" % (cur_sub, out_path))
126 rp = self._bakeSingle(qualified_page, cur_sub, out_path) 124 rp = self._bakeSingle(page, cur_sub, out_path)
127 except Exception as ex: 125 except Exception as ex:
128 logger.exception(ex) 126 logger.exception(ex)
129 page_rel_path = os.path.relpath(qualified_page.path,
130 self.app.root_dir)
131 raise BakingError("%s: error baking '%s'." % 127 raise BakingError("%s: error baking '%s'." %
132 (page_rel_path, sub_uri)) from ex 128 (page.content_spec, sub_uri)) from ex
133 129
134 # Record what we did. 130 # Record what we did.
135 sub_entry.flags |= SubPagePipelineRecordEntry.FLAG_BAKED 131 sub_entry.flags |= SubPagePipelineRecordEntry.FLAG_BAKED
136 sub_entry.render_info = rp.copyRenderInfo() 132 sub_entry.render_info = rp.copyRenderInfo()
137 133
147 out_assets_dir = os.path.join(out_assets_dir, 143 out_assets_dir = os.path.join(out_assets_dir,
148 out_name_noext) 144 out_name_noext)
149 145
150 logger.debug("Copying page assets to: %s" % out_assets_dir) 146 logger.debug("Copying page assets to: %s" % out_assets_dir)
151 _ensure_dir_exists(out_assets_dir) 147 _ensure_dir_exists(out_assets_dir)
152 148 # TODO: copy assets to out dir
153 qualified_page.source.buildAssetor(qualified_page, sub_uri).copyAssets(out_assets_dir)
154 149
155 # Figure out if we have more work. 150 # Figure out if we have more work.
156 has_more_subs = False 151 has_more_subs = False
157 if sub_entry.anyPass(lambda p: p.pagination_has_more): 152 if sub_entry.anyPass(lambda p: p.pagination_has_more):
158 cur_sub += 1 153 cur_sub += 1
159 has_more_subs = True 154 has_more_subs = True
160 155
161 return sub_entries 156 def _bakeSingle(self, page, sub_num, out_path):
162 157 ctx = RenderingContext(page, sub_num=sub_num)
163 def _bakeSingle(self, qp, out_path): 158 page.source.prepareRenderContext(ctx)
164 ctx = RenderingContext(qp) 159
165 qp.source.prepareRenderContext(ctx) 160 with self._stats.timerScope("PageRender"):
166
167 with self.app.env.timerScope("PageRender"):
168 rp = render_page(ctx) 161 rp = render_page(ctx)
169 162
170 with self.app.env.timerScope("PageSerialize"): 163 with self._stats.timerScope("PageSerialize"):
171 if self._writer_queue is not None: 164 if self._writer_queue is not None:
172 self._writer_queue.put_nowait((out_path, rp.content)) 165 self._writer_queue.put_nowait((out_path, rp.content))
173 else: 166 else:
174 with open(out_path, 'w', encoding='utf8') as fp: 167 with open(out_path, 'w', encoding='utf8') as fp:
175 fp.write(rp.content) 168 fp.write(rp.content)