#!/usr/bin/env python import argparse import os import sys import xml.etree.ElementTree as ET from datetime import datetime import markdown import yaml from jinja2 import Environment, FunctionLoader def _load_sitemap(path, current_path): by_name = dict() flattened = [] with open(path, "r") as fp: _sitemap = yaml.safe_load(fp.read()) if not _sitemap["enabled"]: return None def _filter_entries(entries): entries = list( filter(lambda entry: "enabled" not in entry or entry["enabled"] is True, entries)) for entry in entries: if "others" in entry: entry["others"] = _filter_entries(entry["others"]) return entries entries = _filter_entries(_sitemap["entries"]) def _link(entries, parent=None): for entry in entries: flattened.append(entry) entry["parent"] = parent if "others" in entry: _link(entry["others"], parent=entry) def _make_url(link): path = [link["name"]] parent = link["parent"] while parent is not None: path.append(parent["name"]) parent = parent["parent"] path.reverse() return "/".join(path) _link(entries, parent=None) for entry in flattened: target = "/" + _make_url(entry) if target == current_path: entry["active"] = True else: entry["active"] = False entry["url"] = target by_name[target] = entry return dict(by_name=by_name, links=entries) def _make_tree(links): def _populate(root, links): for link in links: elm = ET.Element("li") if "directory" in link and link["directory"]: elm.text = link["name"] else: lref = ET.Element("a", href=link["url"]) link_text = link["name"] if "date" in link: link_text = link_text + " [" + str(link["date"]) + "]" lref.text = link_text if link["active"]: lref.text = lref.text + " <" elm.append(lref) if "others" in link: others = link["others"] ul = ET.Element("ul") elm.append(ul) _populate(root=ul, links=others) root.append(elm) params = {"class": "tree"} root = ET.Element("ul", **params) _populate(root=root, links=links) return ET.tostring(root).decode() def generate(template, content_path, stylesheet, link, sitemap, devmode=False): sm, tree = None, None if sitemap: sm = _load_sitemap(sitemap, current_path=link) if sm: tree = _make_tree(sm["links"]) with open(template, "r") as fp: template = fp.read() env = Environment(loader=FunctionLoader(lambda name: template)) base = env.get_template(template) with open(stylesheet) as fp: style = fp.read() with open(content_path) as fp: text = fp.read() content = markdown.markdown( text, extensions=["fenced_code", "tables"], ) env_content = Environment(loader=FunctionLoader(lambda name: content)) out = base.render({ "content": env_content.get_template("").render({ "sitemap": sm, "tree": tree, }), "is_index": False, "link": link, "style": style, "sitemap": sm, "tree": tree, "devmode": devmode, "current_time": datetime.now(), }) print(out) if __name__ == "__main__": parser = argparse.ArgumentParser(description="static renderer") parser.add_argument("-content", required=True, help="markdown file with content") parser.add_argument("-template", default="index.jinja", help="jinja template file") parser.add_argument("-stylesheet", default="./assets/main.css", help="style sheet") parser.add_argument("-sitemap", help="sitemap") parser.add_argument("-link", default="/", help="current url") parser.add_argument("-devmode", action="store_true", help="developer mode (websocket page refresh)") args = parser.parse_args() generate( template=args.template, content_path=args.content, stylesheet=args.stylesheet, link=args.link, sitemap=args.sitemap, devmode=args.devmode)