changeset 1132:3bcb2d446397

fix: Correctly invalidate pages that use dirtied sources.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 16 Apr 2018 22:22:54 -0700
parents 32f71dbf5cb1
children fe0af94ca757
files piecrust/pipelines/_pagebaker.py piecrust/pipelines/page.py
diffstat 2 files changed, 33 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/pipelines/_pagebaker.py	Wed Feb 28 20:44:23 2018 -0800
+++ b/piecrust/pipelines/_pagebaker.py	Mon Apr 16 22:22:54 2018 -0700
@@ -69,12 +69,14 @@
         with open(out_path, 'w', encoding='utf8') as fp:
             fp.write(content)
 
-    def bake(self, page, prev_entry, force=False):
+    def bake(self, page, prev_entry,
+             force_segments=False, force_layout=False):
         cur_sub = 1
         has_more_subs = True
         app = self.app
         out_dir = self.out_dir
-        force_bake = self.force or force
+        force_segments = self.force or force_segments
+        force_layout = self.force or force_layout
         pretty_urls = page.config.get('pretty_urls', self.pretty_urls)
 
         rendered_subs = []
@@ -99,7 +101,8 @@
                     pass
 
             # Figure out if we need to bake this page.
-            bake_status = _get_bake_status(page, out_path, force_bake,
+            bake_status = _get_bake_status(page, out_path,
+                                           force_segments, force_layout,
                                            prev_sub_entry, cur_sub_entry)
 
             # If this page didn't bake because it's already up-to-date.
@@ -207,20 +210,19 @@
 STATUS_INVALIDATE_AND_BAKE = 2
 
 
-def _get_bake_status(page, out_path, force, prev_sub_entry, cur_sub_entry):
+def _get_bake_status(page, out_path, force_segments, force_layout,
+                     prev_sub_entry, cur_sub_entry):
+    # Easy tests.
+    if force_segments:
+        return STATUS_INVALIDATE_AND_BAKE
+    if force_layout:
+        return STATUS_BAKE
+
     # Figure out if we need to invalidate or force anything.
     status = _compute_force_flags(prev_sub_entry, cur_sub_entry)
     if status != STATUS_CLEAN:
         return status
 
-    # Easy test.
-    if force:
-        cur_sub_entry['flags'] |= \
-            SubPageFlags.FLAG_FORCED_BY_GENERAL_FORCE
-        # We need to invalidate any cache we have on this page because
-        # it's being forced, so something important has changed somehow.
-        return STATUS_INVALIDATE_AND_BAKE
-
     # Check for up-to-date outputs.
     in_path_time = page.content_mtime
     try:
--- a/piecrust/pipelines/page.py	Wed Feb 28 20:44:23 2018 -0800
+++ b/piecrust/pipelines/page.py	Mon Apr 16 22:22:54 2018 -0700
@@ -37,6 +37,7 @@
     def createJobs(self, ctx):
         pass_num = ctx.pass_num
         if pass_num == 0:
+            ctx.current_record.user_data['dirty_source_names'] = set()
             return self._createLoadJobs(ctx)
         if pass_num == 1:
             return self._createSecondPassJobs(ctx)
@@ -68,8 +69,6 @@
         history.build()
 
         pass_num = ctx.pass_num
-        record = ctx.current_record
-        record.user_data['dirty_source_names'] = set()
 
         for prev, cur in history.diffs:
             # Ignore pages that disappeared since last bake.
@@ -151,12 +150,16 @@
             if cur.was_any_sub_baked:
                 continue
             if prev:
-                if any(map(
-                        lambda usn: usn in dirty_source_names,
-                        prev.getAllUsedSourceNames()[0])):
+                usn1, usn2 = prev.getAllUsedSourceNames()
+                force_segments = any(map(lambda u: u in dirty_source_names,
+                                     usn1))
+                force_layout = any(map(lambda u: u in dirty_source_names,
+                                   usn2))
+                if force_segments or force_layout:
                     jobs.append(create_job(self, prev.item_spec,
                                            pass_num=pass_num,
-                                           force_bake=True))
+                                           force_segments=force_segments,
+                                           force_layout=force_layout))
                 else:
                     # This page uses other sources, but no source was dirty
                     # this time around (it was a null build, maybe). We
@@ -182,13 +185,17 @@
             new_entry.route_params = result['route_params']
             new_entry.timestamp = result['timestamp']
             ctx.record.addEntry(new_entry)
+
+            # If this page was modified, flag its entire source as "dirty",
+            # so any pages using that source can be re-baked.
+            if (new_entry.flags & PagePipelineRecordEntry.FLAG_SOURCE_MODIFIED):
+                ctx.record.user_data['dirty_source_names'].add(
+                    self.source.name)
         else:
             # Update the entry with the new information.
             existing = ctx.record_entry
             if not result.get('postponed', False):
                 merge_job_result_into_record_entry(existing, result)
-            if existing.was_any_sub_baked:
-                ctx.record.user_data['dirty_source_names'].add(self.source.name)
 
     def run(self, job, ctx, result):
         pass_num = job.get('pass_num', 0)
@@ -284,8 +291,10 @@
         logger.debug("Full render for: %s" % content_item.spec)
         page = self.app.getPage(self.source, content_item)
         prev_entry = ctx.previous_entry
-        rdr_subs = self._pagebaker.bake(page, prev_entry,
-                                        force=job.get('force_bake'))
+        rdr_subs = self._pagebaker.bake(
+            page, prev_entry,
+            force_segments=job.get('force_segments'),
+            force_layout=job.get('force_layout'))
 
         add_page_job_result(result)
         result['subs'] = rdr_subs