diff piecrust/sources/blogarchives.py @ 857:d231a10d18f9

refactor: Make the data providers and blog archives source functional. Also, because of a behaviour change in Jinja, the blog archives sources is now offering monthly archives by itself.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 08 Jun 2017 08:49:33 -0700
parents 9bb22bbe093c
children 504ddb370df8
line wrap: on
line diff
--- a/piecrust/sources/blogarchives.py	Tue Jun 06 01:23:25 2017 -0700
+++ b/piecrust/sources/blogarchives.py	Thu Jun 08 08:49:33 2017 -0700
@@ -1,5 +1,7 @@
+import time
 import logging
 import datetime
+import collections
 from piecrust.data.filters import PaginationFilter, IFilterClause
 from piecrust.dataproviders.pageiterator import (
     PageIterator, HardCodedFilterIterator, DateSortIterator)
@@ -11,6 +13,7 @@
 from piecrust.routing import RouteParameter
 from piecrust.sources.base import ContentItem
 from piecrust.sources.generator import GeneratorSourceBase
+from piecrust.sources.list import ListSource
 
 
 logger = logging.getLogger(__name__)
@@ -67,22 +70,8 @@
         it._wrapAsSort(DateSortIterator, reverse=False)
         ctx.custom_data['archives'] = it
 
-    def _bakeDirtyYears(self, ctx, all_years, dirty_years):
-        route = self.app.getGeneratorRoute(self.name)
-        if route is None:
-            raise Exception(
-                "No routes have been defined for generator: %s" %
-                self.name)
-
-        logger.debug("Using archive page: %s" % self.page_ref)
-        fac = self.page_ref.getFactory()
-
-        for y in dirty_years:
-            extra_route_metadata = {'year': y}
-
-            logger.debug("Queuing: %s [%s]" % (fac.ref_spec, y))
-            ctx.queueBakeJob(fac, route, extra_route_metadata, str(y))
-        ctx.runJobQueue()
+        ctx.custom_data['monthly_archives'] = _MonthlyArchiveData(
+            self.inner_source, year)
 
 
 class IsFromYearFilterClause(IFilterClause):
@@ -93,8 +82,56 @@
         return (page.datetime.year == self.year)
 
 
-def _date_sorter(it):
-    return sorted(it, key=lambda x: x.datetime)
+class _MonthlyArchiveData(collections.abc.Mapping):
+    def __init__(self, inner_source, year):
+        self._inner_source = inner_source
+        self._year = year
+        self._months = None
+
+    def __iter__(self):
+        self._load()
+        return iter(self._months)
+
+    def __len__(self):
+        self._load()
+        return len(self._months)
+
+    def __getitem__(self, i):
+        self._load()
+        return self._months[i]
+
+    def _load(self):
+        if self._months is not None:
+            return
+
+        month_index = {}
+        src = self._inner_source
+        app = src.app
+        for item in self._inner_source.getAllContents():
+            page = app.getPage(src, item)
+
+            if page.datetime.year != self._year:
+                continue
+
+            month = page.datetime.month
+
+            posts_this_month = month_index.get(month)
+            if posts_this_month is None:
+                posts_this_month = []
+                month_index[month] = posts_this_month
+            posts_this_month.append(page.content_item)
+
+        self._months = []
+        for m, ptm in month_index.items():
+            timestamp = time.mktime((self._year, m, 1, 0, 0, 0, 0, 0, -1))
+
+            it = PageIterator(ListSource(self._inner_source, ptm))
+            it._wrapAsSort(DateSortIterator, reverse=False)
+
+            self._months.append({
+                'timestamp': timestamp,
+                'posts': it
+            })
 
 
 class BlogArchivesPipelineRecordEntry(PagePipelineRecordEntry):