Mercurial > piecrust2
comparison piecrust/serving.py @ 133:9e4c2e68a129
Optimize server for files that already exist.
* Only try to find new assets if no previously existing asset or page
could be used.
* Tidy up a bit the API for passing and returning bake/process records.
* Put the process record in its place.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 18 Nov 2014 21:32:04 -0800 |
parents | 7f81c84f7ddb |
children | 50b65c700c96 |
comparison
equal
deleted
inserted
replaced
132:3834e2ef0cf2 | 133:9e4c2e68a129 |
---|---|
14 from jinja2 import FileSystemLoader, Environment | 14 from jinja2 import FileSystemLoader, Environment |
15 from piecrust.app import PieCrust | 15 from piecrust.app import PieCrust |
16 from piecrust.data.filters import (PaginationFilter, HasFilterClause, | 16 from piecrust.data.filters import (PaginationFilter, HasFilterClause, |
17 IsFilterClause) | 17 IsFilterClause) |
18 from piecrust.environment import StandardEnvironment | 18 from piecrust.environment import StandardEnvironment |
19 from piecrust.page import Page | |
20 from piecrust.processing.base import ProcessorPipeline | 19 from piecrust.processing.base import ProcessorPipeline |
21 from piecrust.rendering import PageRenderingContext, render_page | 20 from piecrust.rendering import PageRenderingContext, render_page |
22 from piecrust.sources.base import PageFactory, MODE_PARSING | 21 from piecrust.sources.base import PageFactory, MODE_PARSING |
23 | 22 |
24 | 23 |
123 # It's not an asset we know of... let's see if it can be a page asset. | 122 # It's not an asset we know of... let's see if it can be a page asset. |
124 response = self._try_serve_page_asset(app, environ, request) | 123 response = self._try_serve_page_asset(app, environ, request) |
125 if response is not None: | 124 if response is not None: |
126 return response(environ, start_response) | 125 return response(environ, start_response) |
127 | 126 |
128 # Nope. Let's hope it's an actual page. | 127 # Nope. Let's see if it's an actual page. |
128 # We trap any exception that says "there's no such page" so we can | |
129 # try another thing before bailing out. But we let any exception | |
130 # that says "something's wrong" through. | |
131 exc = None | |
129 try: | 132 try: |
130 response = self._try_serve_page(app, environ, request) | 133 response = self._try_serve_page(app, environ, request) |
131 return response(environ, start_response) | 134 return response(environ, start_response) |
132 except HTTPException as ex: | |
133 raise | |
134 except (RouteNotFoundError, SourceNotFoundError) as ex: | 135 except (RouteNotFoundError, SourceNotFoundError) as ex: |
135 logger.exception(ex) | 136 logger.exception(ex) |
136 raise NotFound() | 137 exc = NotFound(str(ex)) |
138 except NotFound as ex: | |
139 exc = ex | |
140 except HTTPException: | |
141 raise | |
137 except Exception as ex: | 142 except Exception as ex: |
138 if app.debug: | 143 if app.debug: |
139 logger.exception(ex) | 144 logger.exception(ex) |
140 raise | 145 raise |
141 msg = str(ex) | 146 msg = str(ex) |
142 logger.error(msg) | 147 logger.error(msg) |
143 raise InternalServerError(msg) | 148 raise InternalServerError(msg) |
144 | 149 |
150 # Nothing worked so far... let's see if there's a new asset. | |
151 response = self._try_serve_new_asset(app, environ, request) | |
152 if response is not None: | |
153 return response(environ, start_response) | |
154 | |
155 # Nope. Raise the exception we had in store. | |
156 raise exc | |
157 | |
145 def _try_serve_asset(self, app, environ, request): | 158 def _try_serve_asset(self, app, environ, request): |
146 logger.debug("Searching for asset with path: %s" % request.path) | 159 logger.debug("Searching %d entries for asset with path: %s" % |
160 (len(self._asset_record.entries), request.path)) | |
147 rel_req_path = request.path.lstrip('/').replace('/', os.sep) | 161 rel_req_path = request.path.lstrip('/').replace('/', os.sep) |
148 entry = self._asset_record.previous.findEntry(rel_req_path) | 162 entry = self._asset_record.findEntry(rel_req_path) |
149 do_synchronous_process = True | 163 if entry is None: |
164 # We don't know any asset that could have created this path. | |
165 # It could be a new asset that the user just created, but we'll | |
166 # check for that later. | |
167 return None | |
168 | |
169 # Yep, we know about this URL because we processed an asset that | |
170 # maps to it... make sure it's up to date by re-processing it | |
171 # before serving. | |
150 mounts = app.assets_dirs | 172 mounts = app.assets_dirs |
151 if entry is None: | 173 asset_in_path = entry.path |
152 # We don't know any asset that could have created this path, | 174 asset_out_path = os.path.join(self._out_dir, rel_req_path) |
153 # but we'll see if there's a new asset that could fit. | 175 |
176 if self.synchronous_asset_pipeline: | |
177 logger.debug("Making sure '%s' is up-to-date." % asset_in_path) | |
154 pipeline = ProcessorPipeline( | 178 pipeline = ProcessorPipeline( |
155 app, mounts, self._out_dir, | 179 app, mounts, self._out_dir, |
156 skip_patterns=self._skip_patterns, | 180 skip_patterns=self._skip_patterns, |
157 force_patterns=self._force_patterns) | 181 force_patterns=self._force_patterns, |
158 record = pipeline.run(new_only=True) | 182 num_workers=1) |
159 entry = record.current.findEntry(rel_req_path) | 183 r = pipeline.run(asset_in_path, delete=False, save_record=False, |
160 if entry is None: | 184 previous_record=self._asset_record) |
161 return None | 185 assert len(r.entries) == 1 |
162 | 186 self._asset_record.replaceEntry(r.entries[0]) |
163 logger.debug("Found new asset: %s" % entry.path) | 187 |
164 self._asset_record.addEntry(entry) | 188 logger.debug("Serving %s" % asset_out_path) |
165 do_synchronous_process = False | 189 wrapper = wrap_file(environ, open(asset_out_path, 'rb')) |
166 | 190 response = Response(wrapper) |
167 # Yep, we know about this URL because we processed an asset that | 191 _, ext = os.path.splitext(rel_req_path) |
168 # maps to it... make sure it's up to date by re-processing it | 192 response.mimetype = self._mimetype_map.get( |
169 # before serving. | 193 ext.lstrip('.'), 'text/plain') |
170 asset_in_path = entry.path | 194 return response |
195 | |
196 def _try_serve_new_asset(self, app, environ, request): | |
197 logger.debug("Searching for a new asset with path: %s" % request.path) | |
198 mounts = app.assets_dirs | |
199 pipeline = ProcessorPipeline( | |
200 app, mounts, self._out_dir, | |
201 skip_patterns=self._skip_patterns, | |
202 force_patterns=self._force_patterns) | |
203 r = pipeline.run(new_only=True, delete=False, save_record=False, | |
204 previous_record=self._asset_record) | |
205 for e in r.entries: | |
206 self._asset_record.addEntry(e) | |
207 | |
208 rel_req_path = request.path.lstrip('/').replace('/', os.sep) | |
209 entry = self._asset_record.findEntry(rel_req_path) | |
210 if entry is None: | |
211 return None | |
212 | |
171 asset_out_path = os.path.join(self._out_dir, rel_req_path) | 213 asset_out_path = os.path.join(self._out_dir, rel_req_path) |
172 | 214 logger.debug("Found new asset: %s" % entry.path) |
173 if self.synchronous_asset_pipeline and do_synchronous_process: | |
174 pipeline = ProcessorPipeline( | |
175 app, mounts, self._out_dir, | |
176 skip_patterns=self._skip_patterns, | |
177 force_patterns=self._force_patterns) | |
178 pipeline.run(asset_in_path) | |
179 | |
180 logger.debug("Serving %s" % asset_out_path) | 215 logger.debug("Serving %s" % asset_out_path) |
181 wrapper = wrap_file(environ, open(asset_out_path, 'rb')) | 216 wrapper = wrap_file(environ, open(asset_out_path, 'rb')) |
182 response = Response(wrapper) | 217 response = Response(wrapper) |
183 _, ext = os.path.splitext(rel_req_path) | 218 _, ext = os.path.splitext(rel_req_path) |
184 response.mimetype = self._mimetype_map.get( | 219 response.mimetype = self._mimetype_map.get( |