Mercurial > piecrust2
diff piecrust/serving/server.py @ 555:daf8df5ade7d
serve: Refactor the server to make pieces usable by the debugging middleware.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 12 Aug 2015 23:04:46 -0700 |
parents | 155c7e20414f |
children | 657384f08ca3 |
line wrap: on
line diff
--- a/piecrust/serving/server.py Sat Aug 08 22:22:22 2015 -0700 +++ b/piecrust/serving/server.py Wed Aug 12 23:04:46 2015 -0700 @@ -10,11 +10,12 @@ from werkzeug.wrappers import Request, Response from jinja2 import FileSystemLoader, Environment from piecrust import CACHE_DIR, RESOURCES_DIR -from piecrust.app import PieCrust -from piecrust.rendering import QualifiedPage, PageRenderingContext, render_page -from piecrust.serving.util import content_type_map, make_wrapped_file_response -from piecrust.sources.base import MODE_PARSING -from piecrust.uriutil import split_sub_uri +from piecrust.rendering import PageRenderingContext, render_page +from piecrust.routing import RouteNotFoundError +from piecrust.serving.util import ( + content_type_map, make_wrapped_file_response, get_requested_page, + get_app_for_server) +from piecrust.sources.base import SourceNotFoundError logger = logging.getLogger(__name__) @@ -63,7 +64,7 @@ desc = '<p>' + self.description + '</p>' desc += '<p>' for nfe in self._nfes: - desc += '<li>' + escape(nfe.description) + '</li>' + desc += '<li>' + escape(str(nfe)) + '</li>' desc += '</p>' return desc @@ -107,11 +108,8 @@ return response # Create the app for this request. - app = PieCrust(root_dir=self.root_dir, debug=self.debug) - if self.sub_cache_dir: - app._useSubCacheDir(self.sub_cache_dir) - app.config.set('site/root', '/') - app.config.set('server/is_serving', True) + app = get_app_for_server(self.root_dir, debug=self.debug, + sub_cache_dir=self.sub_cache_dir) if (app.config.get('site/enable_debug_info') and self.enable_debug_info and '!debug' in request.args): @@ -168,33 +166,56 @@ return make_wrapped_file_response(environ, request, full_path) def _try_serve_page(self, app, environ, request): - # Try to find what matches the requested URL. - req_path, page_num = split_sub_uri(app, request.path) + # Find a matching page. + req_page = get_requested_page(app, request.path) - routes = find_routes(app.routes, req_path) - if len(routes) == 0: - raise RouteNotFoundError("Can't find route for: %s" % req_path) + # If we haven't found any good match, report all the places we didn't + # find it at. + qp = req_page.qualified_page + if qp is None: + msg = "Can't find path for '%s':" % request.path + raise MultipleNotFound(msg, req_page.not_found_errors) + + # We have a page, let's try to render it. + render_ctx = PageRenderingContext(qp, + page_num=req_page.page_num, + force_render=True) + if qp.route.taxonomy_name is not None: + taxonomy = app.getTaxonomy(qp.route.taxonomy_name) + tax_terms = qp.route.getTaxonomyTerms(qp.route_metadata) + render_ctx.setTaxonomyFilter(tax_terms, needs_slugifier=True) - rendered_page = None - not_found_errors = [] - for route, route_metadata in routes: - try: - logger.debug("Trying to render match from source '%s'." % - route.source_name) - rendered_page = self._try_render_page( - app, route, route_metadata, page_num, req_path) - if rendered_page is not None: - break - except NotFound as nfe: - not_found_errors.append(nfe) + # See if this page is known to use sources. If that's the case, + # just don't use cached rendered segments for that page (but still + # use them for pages that are included in it). + uri = qp.getUri() + entry = self._page_record.getEntry(uri, req_page.page_num) + if (qp.route.taxonomy_name is not None or entry is None or + entry.used_source_names): + cache_key = '%s:%s' % (uri, req_page.page_num) + app.env.rendered_segments_repository.invalidate(cache_key) + + # Render the page. + rendered_page = render_page(render_ctx) - # If we haven't found any good match, raise whatever exception we - # first got. Otherwise, raise a generic exception. - if rendered_page is None: - msg = ("Can't find path for '%s', looked in sources: %s" % - (req_path, - ', '.join([r.source_name for r, _ in routes]))) - raise MultipleNotFound(msg, not_found_errors) + # Check if this page is a taxonomy page that actually doesn't match + # anything. + if qp.route.taxonomy_name is not None: + paginator = rendered_page.data.get('pagination') + if (paginator and paginator.is_loaded and + len(paginator.items) == 0): + taxonomy = app.getTaxonomy(qp.route.taxonomy_name) + message = ("This URL matched a route for taxonomy '%s' but " + "no pages have been found to have it. This page " + "won't be generated by a bake." % taxonomy.name) + raise NotFound(message) + + # Remember stuff for next time. + if entry is None: + entry = ServeRecordPageEntry(req_page.req_path, req_page.page_num) + self._page_record.addEntry(entry) + for p, pinfo in render_ctx.render_passes.items(): + entry.used_source_names |= pinfo.used_source_names # Start doing stuff. page = rendered_page.page @@ -255,70 +276,6 @@ return response - def _try_render_page(self, app, route, route_metadata, page_num, req_path): - # Match the route to an actual factory. - taxonomy_info = None - source = app.getSource(route.source_name) - if route.taxonomy_name is None: - factory = source.findPageFactory(route_metadata, MODE_PARSING) - if factory is None: - raise NotFound("No path found for '%s' in source '%s'." % - (req_path, source.name)) - else: - taxonomy = app.getTaxonomy(route.taxonomy_name) - tax_terms = route.getTaxonomyTerms(route_metadata) - taxonomy_info = (taxonomy, tax_terms) - - tax_page_ref = taxonomy.getPageRef(source) - factory = tax_page_ref.getFactory() - - # Build the page. - page = factory.buildPage() - # We force the rendering of the page because it could not have - # changed, but include pages that did change. - qp = QualifiedPage(page, route, route_metadata) - render_ctx = PageRenderingContext(qp, - page_num=page_num, - force_render=True) - if taxonomy_info is not None: - _, tax_terms = taxonomy_info - render_ctx.setTaxonomyFilter(tax_terms, needs_slugifier=True) - - # See if this page is known to use sources. If that's the case, - # just don't use cached rendered segments for that page (but still - # use them for pages that are included in it). - uri = qp.getUri() - entry = self._page_record.getEntry(uri, page_num) - if (taxonomy_info is not None or entry is None or - entry.used_source_names): - cache_key = '%s:%s' % (uri, page_num) - app.env.rendered_segments_repository.invalidate(cache_key) - - # Render the page. - rendered_page = render_page(render_ctx) - - # Check if this page is a taxonomy page that actually doesn't match - # anything. - if taxonomy_info is not None: - paginator = rendered_page.data.get('pagination') - if (paginator and paginator.is_loaded and - len(paginator.items) == 0): - taxonomy = taxonomy_info[0] - message = ("This URL matched a route for taxonomy '%s' but " - "no pages have been found to have it. This page " - "won't be generated by a bake." % taxonomy.name) - raise NotFound(message) - - # Remember stuff for next time. - if entry is None: - entry = ServeRecordPageEntry(req_path, page_num) - self._page_record.addEntry(entry) - for p, pinfo in render_ctx.render_passes.items(): - entry.used_source_names |= pinfo.used_source_names - - # Ok all good. - return rendered_page - def _handle_error(self, exception, environ, start_response): code = 500 if isinstance(exception, HTTPException): @@ -354,27 +311,6 @@ return desc -class RouteNotFoundError(Exception): - pass - - -class SourceNotFoundError(Exception): - pass - - -def find_routes(routes, uri): - res = [] - tax_res = [] - for route in routes: - metadata = route.matchUri(uri) - if metadata is not None: - if route.is_taxonomy_route: - tax_res.append((route, metadata)) - else: - res.append((route, metadata)) - return res + tax_res - - class ErrorMessageLoader(FileSystemLoader): def __init__(self): base_dir = os.path.join(RESOURCES_DIR, 'messages')