diff options
Diffstat (limited to 'blog')
-rw-r--r-- | blog/__init__.py | 0 | ||||
-rw-r--r-- | blog/blog.py | 53 | ||||
-rw-r--r-- | blog/feed.py | 14 | ||||
-rw-r--r-- | blog/post.py | 71 | ||||
-rw-r--r-- | blog/render.py | 16 |
5 files changed, 154 insertions, 0 deletions
diff --git a/blog/__init__.py b/blog/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/blog/__init__.py diff --git a/blog/blog.py b/blog/blog.py new file mode 100644 index 0000000..cb6ab1e --- /dev/null +++ b/blog/blog.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -* + +import os +import shutil + +from jinja2 import Environment, FileSystemLoader, select_autoescape + +from post import Post +from feed import Feed + + +def recreate_workdir(basedir): + if os.path.exists(basedir): + shutil.rmtree(basedir) + os.makedirs(basedir) + + +def find_posts(template, basedir): + posts = [] + for subdir in os.listdir(basedir): + posts.append(Post(template, os.path.join(basedir, subdir))) + return posts + + +def generate_blog(include_drafts=False): + env = Environment(loader=FileSystemLoader(searchpath="templates"), + autoescape=select_autoescape()) + + posts = find_posts(env.get_template("post.html"), + os.path.join("posts", "public")) + + if include_drafts: + drafts = find_posts(env.get_template("post.html"), + os.path.join("posts", "drafts")) + posts.extend(drafts) + + workdir = "remote" + recreate_workdir(workdir) + + for post in posts: + post.generate(workdir) + + feed = Feed(env.get_template("feed.html"), posts) + feed.generate(workdir) + + +def main(): + generate_blog(include_drafts=True) + + +if __name__ == "__main__": + main() diff --git a/blog/feed.py b/blog/feed.py new file mode 100644 index 0000000..d8ffc8c --- /dev/null +++ b/blog/feed.py @@ -0,0 +1,14 @@ +import os + +import render + + +class Feed(object): + def __init__(self, template, posts): + self.template = template + self.posts = posts + + def generate(self, basedir): + index = os.path.join(basedir, "index.html") + rendered = self.template.render(posts=self.posts) + render.write_file_content(index, rendered) diff --git a/blog/post.py b/blog/post.py new file mode 100644 index 0000000..1d35b6c --- /dev/null +++ b/blog/post.py @@ -0,0 +1,71 @@ +import os +import shutil +import datetime +import functools + +import render + + +class Metadata(object): + __slots__ = ("title", "date", "status") + + def __init__(self, title, date, status): + self.title = title + self.date = date + self.status = status + + +class Post(object): + def __init__(self, template, directory): + self.template = template + self.directory = directory + self.name = os.path.basename(directory) + + @staticmethod + def _load_raw_metadata(filename): + data = {} + + with open(filename) as f: + for line in f: + k, v = line.strip().split(": ") + data[k] = v + + return data + + @functools.cached_property + def metadata(self): + raw = Post._load_raw_metadata(os.path.join(self.directory, + "metadata.txt")) + + title = raw["Title"] + date = raw.get("Date", datetime.date.today().strftime("%Y-%m-%d")) + status = raw.get("Status", "draft") + + return Metadata(title, date, status) + + def is_draft(self): + return self.metadata.status == "draft" + + def generate(self, basedir): + postdir = os.path.basename(self.directory) + workdir = os.path.join(basedir, postdir) + os.makedirs(workdir) + + md = None + for filename in os.listdir(self.directory): + source = os.path.join(self.directory, filename) + destination = os.path.join(workdir, filename) + + shutil.copy(source, destination) + + if filename.endswith(".md"): + md = source + + assert md, f"There is no markdown file in `{self.directory}`" + + body = render.to_html(md) + rendered = self.template.render(title=self.metadata.title, + date=self.metadata.date, + body=body) + render.write_file_content(os.path.join(workdir, "index.html"), + rendered) diff --git a/blog/render.py b/blog/render.py new file mode 100644 index 0000000..4e26318 --- /dev/null +++ b/blog/render.py @@ -0,0 +1,16 @@ +import markdown + + +def read_file_content(filename): + with open(filename) as f: + return f.read() + + +def write_file_content(filename, data): + with open(filename, mode='w') as f: + f.write(data) + + +def to_html(filename): + text = read_file_content(filename) + return markdown.markdown(text, extensions=["fenced_code", "footnotes"]) |