From 57ed8fa15c6332a5692985902721276e4014c6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Mon, 27 Jun 2022 21:02:33 +0200 Subject: [PATCH] Add simple mechanism for fast re-render. --- scripts/blog.py | 100 ++++++++++++++++++++++++++++++++++----- static/article.tmpl.html | 2 +- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/scripts/blog.py b/scripts/blog.py index 2e1510c..fa88c17 100644 --- a/scripts/blog.py +++ b/scripts/blog.py @@ -17,12 +17,15 @@ import logging import sys import os import datetime -import jinja2 import shutil +import traceback +import time +import re +import jinja2 +import inotify.adapters import yaml import markdown -import re from unidecode import unidecode NIKOLA_DATE_RE = re.compile(r'^([0-2]\d|30|31)\.(0\d|1[012])\.(\d{4}), (\d{1,2}):(\d{2})$') @@ -44,7 +47,24 @@ JINJA_ENV = jinja2.Environment( loader=jinja2.FileSystemLoader(STATIC_PATH), autoescape=jinja2.select_autoescape() ) -ARTICLE_TEMPLATE = JINJA_ENV.get_template(ARTICLE_TEMPLATE_NAME) + +def update_statics(): + global ARTICLE_TEMPLATE + ARTICLE_TEMPLATE = JINJA_ENV.get_template(ARTICLE_TEMPLATE_NAME) + +update_statics() + +MONITORED_EVENT_TYPES = ( + 'IN_CREATE', + # 'IN_MODIFY', + 'IN_CLOSE_WRITE', + 'IN_DELETE', + 'IN_MOVED_FROM', + 'IN_MOVED_TO', + 'IN_DELETE_SELF', + 'IN_MOVE_SELF', +) + def parse_nikola_date(match): return datetime.datetime(year=int(match.group(3)), @@ -53,9 +73,11 @@ def parse_nikola_date(match): hour=int(match.group(4)), minute=int(match.group(5))) + def parse_complete_date(match): return datetime.datetime.strptime(match.group(0), '%Y-%m-%d %H:%M:%S %Z%z') + def slugify(title): """ Made for compatibility with Nikola's slugify within CodigoParaLlevar blog. @@ -66,6 +88,7 @@ def slugify(title): return slug.strip() + def read_markdown(path): with open(path, 'rt') as f: data = f.read() @@ -112,7 +135,7 @@ def get_out_path(front_matter): def load_all(top_dir_relative): top = os.path.abspath(top_dir_relative) - docs = [] + docs = {} for root, dirs, files in os.walk(top): for name in files: @@ -124,29 +147,82 @@ def load_all(top_dir_relative): path = os.path.join(root, name) doc, front_matter = read_markdown(path) out_path = get_out_path(front_matter) - docs.append((doc, front_matter, out_path)) + docs[path] = (doc, front_matter, out_path) else: raise NotImplementedError('Unknown filetype: {}'.format(name)) return docs -def render_article(doc, f): - result = ARTICLE_TEMPLATE.render(content=doc) + +def load_doc(filepath): + doc, front_matter = read_markdown(filepath) + out_path = get_out_path(front_matter) + return (doc, front_matter, out_path) + + +def render_article(doc, front_matter, f): + result = ARTICLE_TEMPLATE.render(content=doc, title=front_matter['title']) f.write(result) -def main(source_top, dest_top): - docs = load_all(source_top) - for (doc, front_matter, out_path) in docs: +def regen_all(source_top, dest_top, docs=None): + if docs is None: + docs = load_all(source_top) + for (doc, front_matter, out_path) in docs.values(): doc_full_path = os.path.join(dest_top, out_path) os.makedirs(os.path.dirname(doc_full_path), exist_ok=True) - print("==", doc_full_path) + # print("==", doc_full_path) with open(doc_full_path + '.html', 'wt') as f: - render_article(doc, f) + render_article(doc, front_matter, f) for src, dest in STATIC_RESOURCES: target_dest = os.path.join(dest_top, dest) os.makedirs(os.path.dirname(target_dest), exist_ok=True) shutil.copy(os.path.join(STATIC_PATH, src), target_dest) + return docs + + +def main(source_top, dest_top): + notifier = inotify.adapters.InotifyTrees([source_top, STATIC_PATH]) + + ## Initial load + t0 = time.time() + logging.info("Initial load...") + docs = regen_all(source_top, dest_top) + logging.info("Initial load completed in {:.2f}s".format(time.time() - t0)) + + ## Updating + for event in notifier.event_gen(yield_nones=False): + (ev, types, directory, file) = event + if not any([type in MONITORED_EVENT_TYPES for type in types]): + continue + filepath = os.path.join(directory, file) + if filepath.startswith(STATIC_PATH): + t0 = time.time() + update_statics() + for src, dest in STATIC_RESOURCES: + target_dest = os.path.join(dest_top, dest) + os.makedirs(os.path.dirname(target_dest), exist_ok=True) + shutil.copy(os.path.join(STATIC_PATH, src), target_dest) + docs = regen_all(source_top, dest_top, docs) + logging.info("Updated all in {:.2f}s".format(time.time() - t0)) + + else: + try: + (doc, front_matter, out_path) = load_doc(filepath) + except: + logging.error(traceback.format_exc()) + logging.error("Skipping update 😿") + continue + + t0 = time.time() + docs[filepath] = (doc, front_matter, out_path) + doc_full_path = os.path.join(dest_top, out_path) + os.makedirs(os.path.dirname(doc_full_path), exist_ok=True) + # print("==", doc_full_path) + with open(doc_full_path + '.html', 'wt') as f: + render_article(doc, front_matter, f) + logging.info("Updated all in {:.2f}s".format(time.time() - t0)) + if __name__ == "__main__": if len(sys.argv) != 3: diff --git a/static/article.tmpl.html b/static/article.tmpl.html index d535fbf..b73f5dd 100644 --- a/static/article.tmpl.html +++ b/static/article.tmpl.html @@ -7,8 +7,8 @@ -
+

{{ title }}

{{ content | safe }}