Add simple mechanism for fast re-render.
This commit is contained in:
parent
a8c4d6ef48
commit
57ed8fa15c
100
scripts/blog.py
100
scripts/blog.py
@ -17,12 +17,15 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import jinja2
|
|
||||||
import shutil
|
import shutil
|
||||||
|
import traceback
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
|
import jinja2
|
||||||
|
import inotify.adapters
|
||||||
import yaml
|
import yaml
|
||||||
import markdown
|
import markdown
|
||||||
import re
|
|
||||||
from unidecode import unidecode
|
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})$')
|
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),
|
loader=jinja2.FileSystemLoader(STATIC_PATH),
|
||||||
autoescape=jinja2.select_autoescape()
|
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):
|
def parse_nikola_date(match):
|
||||||
return datetime.datetime(year=int(match.group(3)),
|
return datetime.datetime(year=int(match.group(3)),
|
||||||
@ -53,9 +73,11 @@ def parse_nikola_date(match):
|
|||||||
hour=int(match.group(4)),
|
hour=int(match.group(4)),
|
||||||
minute=int(match.group(5)))
|
minute=int(match.group(5)))
|
||||||
|
|
||||||
|
|
||||||
def parse_complete_date(match):
|
def parse_complete_date(match):
|
||||||
return datetime.datetime.strptime(match.group(0), '%Y-%m-%d %H:%M:%S %Z%z')
|
return datetime.datetime.strptime(match.group(0), '%Y-%m-%d %H:%M:%S %Z%z')
|
||||||
|
|
||||||
|
|
||||||
def slugify(title):
|
def slugify(title):
|
||||||
"""
|
"""
|
||||||
Made for compatibility with Nikola's slugify within CodigoParaLlevar blog.
|
Made for compatibility with Nikola's slugify within CodigoParaLlevar blog.
|
||||||
@ -66,6 +88,7 @@ def slugify(title):
|
|||||||
|
|
||||||
return slug.strip()
|
return slug.strip()
|
||||||
|
|
||||||
|
|
||||||
def read_markdown(path):
|
def read_markdown(path):
|
||||||
with open(path, 'rt') as f:
|
with open(path, 'rt') as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
@ -112,7 +135,7 @@ def get_out_path(front_matter):
|
|||||||
def load_all(top_dir_relative):
|
def load_all(top_dir_relative):
|
||||||
top = os.path.abspath(top_dir_relative)
|
top = os.path.abspath(top_dir_relative)
|
||||||
|
|
||||||
docs = []
|
docs = {}
|
||||||
|
|
||||||
for root, dirs, files in os.walk(top):
|
for root, dirs, files in os.walk(top):
|
||||||
for name in files:
|
for name in files:
|
||||||
@ -124,29 +147,82 @@ def load_all(top_dir_relative):
|
|||||||
path = os.path.join(root, name)
|
path = os.path.join(root, name)
|
||||||
doc, front_matter = read_markdown(path)
|
doc, front_matter = read_markdown(path)
|
||||||
out_path = get_out_path(front_matter)
|
out_path = get_out_path(front_matter)
|
||||||
docs.append((doc, front_matter, out_path))
|
docs[path] = (doc, front_matter, out_path)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError('Unknown filetype: {}'.format(name))
|
raise NotImplementedError('Unknown filetype: {}'.format(name))
|
||||||
|
|
||||||
return docs
|
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)
|
f.write(result)
|
||||||
|
|
||||||
def main(source_top, dest_top):
|
def regen_all(source_top, dest_top, docs=None):
|
||||||
docs = load_all(source_top)
|
if docs is None:
|
||||||
for (doc, front_matter, out_path) in docs:
|
docs = load_all(source_top)
|
||||||
|
for (doc, front_matter, out_path) in docs.values():
|
||||||
doc_full_path = os.path.join(dest_top, out_path)
|
doc_full_path = os.path.join(dest_top, out_path)
|
||||||
os.makedirs(os.path.dirname(doc_full_path), exist_ok=True)
|
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:
|
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:
|
for src, dest in STATIC_RESOURCES:
|
||||||
target_dest = os.path.join(dest_top, dest)
|
target_dest = os.path.join(dest_top, dest)
|
||||||
os.makedirs(os.path.dirname(target_dest), exist_ok=True)
|
os.makedirs(os.path.dirname(target_dest), exist_ok=True)
|
||||||
shutil.copy(os.path.join(STATIC_PATH, src), target_dest)
|
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 __name__ == "__main__":
|
||||||
if len(sys.argv) != 3:
|
if len(sys.argv) != 3:
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
<link rel="stylesheet" href="../css/style.css" />
|
<link rel="stylesheet" href="../css/style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
|
<h2 class="post-title">{{ title }}</h2>
|
||||||
{{ content | safe }}
|
{{ content | safe }}
|
||||||
</article>
|
</article>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user