Commit 3de17dec49

3de17dec498be2ba9b8875cba443243a7d759d0c

parent: 2848cb0b99

Verified · cmc

cmc <hello@cleberg.net> · 2026-03-11 05:07 UTC

Update build.py post-processing pipeline

Layout: unified · split

build.py +55 −8
@@ -183,13 +183,16 @@ def get_recent_posts_html(content_dir="./content/blog", num_posts=3):
183183
184184 # Build HTML lines
185185 lines = []
186 current_year = None
186187 for post in recent:
187 lines.append('\t<div class="post">')
188 lines.append(
189 f'\t\t<time datetime="{post["date_str"]}">{post["date_full"]}</time>'
190 )
191 lines.append(f'\t\t\t<a href="/blog/{post["slug"]}.html">{post["title"]}</a>')
192 lines.append("\t</div>")
188 year = post["date_obj"].year
189 if year != current_year:
190 current_year = year
191 lines.append(f'\t<li class="post-list-year">{year}</li>')
192 lines.append('\t<li class="post-list-item">')
193 lines.append(f'\t\t<a href="/blog/{post["slug"]}.html">{post["title"]}</a>')
194 lines.append(f'\t\t<time datetime="{post["date_str"]}">{post["date_full"]}</time>')
195 lines.append("\t</li>")
193196
194197 return "\n".join(lines)
195198
@@ -259,12 +262,12 @@ def run_emacs_publish(dev_mode=True):
259262 print(result.stderr, file=sys.stderr)
260263 sys.exit(1)
261264
262 annoying_file = Path(".build/cleberg-net.html")
265 annoying_file = Path(".build/seijaku.html")
263266 if annoying_file.exists():
264267 os.remove(annoying_file)
265268 else:
266269 print(
267 "Warning: .build/cleberg-net.html not found, but Emacs exited successfully."
270 "Warning: .build/seijaku.html not found, but Emacs exited successfully."
268271 )
269272
270273
@@ -336,6 +339,48 @@ def generate_sitemap(build_dir=".build", base_url="https://cleberg.net"):
336339 print(f"Sitemap generated at {sitemap_path} with {len(sitemap_entries)} entries.")
337340
338341
342def inject_blog_year_separators(blog_index_path="./.build/blog/index.html"):
343 """
344 Post-processes the rendered blog index to inject year separator <li> elements
345 between groups of posts. Weblorg/templatel doesn't support mutable loop state,
346 so this runs after the HTML is generated.
347
348 Finds each <li class="post-list-item"> that contains a <time datetime="YYYY-MM-DD">,
349 and inserts <li class="post-list-year">YYYY</li> before the first post of each year.
350 """
351 path = Path(blog_index_path)
352 if not path.exists():
353 print(f"Warning: {blog_index_path} not found, skipping year separators.")
354 return
355
356 content = path.read_text(encoding="utf-8")
357
358 # Match each post list item, capturing the date and the full element
359 item_pattern = re.compile(
360 r'(<li class="post-list-item">.*?</li>)',
361 re.DOTALL,
362 )
363 date_pattern = re.compile(r"datetime=['\"]?(\d{4})-\d{2}-\d{2}['\"]?")
364
365 current_year = None
366 def replace_item(m):
367 nonlocal current_year
368 item_html = m.group(1)
369 date_match = date_pattern.search(item_html)
370 if not date_match:
371 return item_html
372 year = date_match.group(1)
373 if year != current_year:
374 current_year = year
375 separator = f'<li class="post-list-year">{year}</li>'
376 return f"{separator}\n{item_html}"
377 return item_html
378
379 new_content = item_pattern.sub(replace_item, content)
380 path.write_text(new_content, encoding="utf-8")
381 print(f"Blog year separators injected into {blog_index_path}")
382
383
339384def deploy_to_server(build_dir, server):
340385 remote_path = f"{server}:/var/www/cleberg.net/"
341386 print(f"Deploying .build/ → {remote_path}")
@@ -384,6 +429,7 @@ def main():
384429 run_emacs_publish(dev_mode=False)
385430 copy_org_sources()
386431 update_index_html(html_snippet)
432 inject_blog_year_separators()
387433 minify_html("./.build/index.html", "./.build/index.html")
388434 generate_sitemap()
389435 if deploy:
@@ -398,6 +444,7 @@ def main():
398444 run_emacs_publish(dev_mode=True)
399445 copy_org_sources()
400446 update_index_html(html_snippet)
447 inject_blog_year_separators()
401448 minify_html("./.build/index.html", "./.build/index.html")
402449 generate_sitemap()
403450 if deploy: