diff piecrust/serving.py @ 371:c2ca72fb7f0b 2.0.0a8

caching: Use separate caches for config variants and other contexts. * The `_cache` directory is now organized in multiple "sub-caches" for different contexts. * A new context is created when config variants or overrides are applied. * `serve` context uses a different context that the other commends, to prevent the `bake` command's output from messing up the preview server (e.g. with how asset URLs are generated differently between the two). * Fix a few places where the cache directory was referenced directly.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 03 May 2015 23:59:46 -0700
parents 4b1019bb2533
children
line wrap: on
line diff
--- a/piecrust/serving.py	Sun May 03 23:45:32 2015 -0700
+++ b/piecrust/serving.py	Sun May 03 23:59:46 2015 -0700
@@ -66,9 +66,11 @@
 
 class Server(object):
     def __init__(self, root_dir,
-                 debug=False, use_reloader=False, static_preview=True):
+                 debug=False, sub_cache_dir=None,
+                 use_reloader=False, static_preview=True):
         self.root_dir = root_dir
         self.debug = debug
+        self.sub_cache_dir = sub_cache_dir
         self.use_reloader = use_reloader
         self.static_preview = static_preview
         self._out_dir = None
@@ -80,7 +82,8 @@
         # Bake all the assets so we know what we have, and so we can serve
         # them to the client. We need a temp app for this.
         app = PieCrust(root_dir=self.root_dir, debug=self.debug)
-        self._out_dir = os.path.join(app.cache_dir, 'server')
+        app._useSubCacheDir(self.sub_cache_dir)
+        self._out_dir = os.path.join(app.sub_cache_dir, 'server')
         self._page_record = ServeRecord()
 
         if (not self.use_reloader or
@@ -129,6 +132,7 @@
 
         # Create the app for this request.
         app = PieCrust(root_dir=self.root_dir, debug=self.debug)
+        app._useSubCacheDir(self.sub_cache_dir)
         app.config.set('site/root', '/')
         app.config.set('server/is_serving', True)
         if (app.config.get('site/enable_debug_info') and
@@ -226,67 +230,35 @@
         if len(routes) == 0:
             raise RouteNotFoundError("Can't find route for: %s" % req_path)
 
-        taxonomy = None
-        tax_terms = None
+        rendered_page = None
+        first_not_found = None
         for route, route_metadata in routes:
-            source = app.getSource(route.source_name)
-            if route.taxonomy_name is None:
-                factory = source.findPageFactory(route_metadata, MODE_PARSING)
-                if factory is not None:
+            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
-            else:
-                taxonomy = app.getTaxonomy(route.taxonomy_name)
-                route_terms = route_metadata.get(taxonomy.term_name)
-                if route_terms is not None:
-                    tax_page_ref = taxonomy.getPageRef(source.name)
-                    factory = tax_page_ref.getFactory()
-                    tax_terms = route.unslugifyTaxonomyTerm(route_terms)
-                    factory.metadata[taxonomy.term_name] = tax_terms
-                    break
+            except NotFound as nfe:
+                if first_not_found is None:
+                    first_not_found = nfe
         else:
             raise SourceNotFoundError(
                     "Can't find path for: %s (looked in: %s)" %
                     (req_path, [r.source_name for r, _ in routes]))
 
-        # 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 is not None:
-            render_ctx.setTaxonomyFilter(taxonomy, tax_terms)
+        # If we haven't found any good match, raise whatever exception we
+        # first got. Otherwise, raise a generic exception.
+        if rendered_page is None:
+            first_not_found = first_not_found or NotFound(
+                    "This page couldn't be found.")
+            raise first_not_found
 
-        # 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).
-        entry = self._page_record.getEntry(req_path, page_num)
-        if (taxonomy is not None or entry is None or
-                entry.used_source_names):
-            cache_key = '%s:%s' % (req_path, page_num)
-            app.env.rendered_segments_repository.invalidate(cache_key)
-
-        # Render the page.
-        rendered_page = render_page(render_ctx)
+        # Start doing stuff.
+        page = rendered_page.page
         rp_content = rendered_page.content
 
-        if taxonomy is not None:
-            paginator = rendered_page.data.get('pagination')
-            if (paginator and paginator.is_loaded and
-                    len(paginator.items) == 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)
-
-        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
-
         # Profiling.
         if app.config.get('site/show_debug_info'):
             now_time = time.clock()
@@ -341,6 +313,74 @@
 
         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:
+                return None
+        else:
+            taxonomy = app.getTaxonomy(route.taxonomy_name)
+            route_terms = route_metadata.get(taxonomy.term_name)
+            if route_terms is None:
+                return None
+
+            tax_page_ref = taxonomy.getPageRef(source.name)
+            factory = tax_page_ref.getFactory()
+            tax_terms = route.unslugifyTaxonomyTerm(route_terms)
+            route_metadata[taxonomy.term_name] = tax_terms
+            taxonomy_info = (taxonomy, tax_terms)
+
+        # 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:
+            taxonomy, tax_terms = taxonomy_info
+            render_ctx.setTaxonomyFilter(taxonomy, tax_terms)
+
+        # 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()
+        assert uri == req_path
+        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 _make_wrapped_file_response(self, environ, request, path):
         logger.debug("Serving %s" % path)