Pythonrender.py -rwxr-xr-x 4.6 KiB
1#!/usr/bin/env python
2import argparse
3import os
4import sys
5import xml.etree.ElementTree as ET
6
7from datetime import datetime
8
9import markdown
10import yaml
11from jinja2 import Environment, FunctionLoader
12
13
14def _load_sitemap(path, current_path):
15 by_name = dict()
16 flattened = []
17 with open(path, "r") as fp:
18 _sitemap = yaml.safe_load(fp.read())
19
20 if not _sitemap["enabled"]:
21 return None
22
23 def _filter_entries(entries):
24 entries = list(
25 filter(lambda entry: "enabled"
26 not in entry or entry["enabled"] is True, entries))
27 for entry in entries:
28 if "others" in entry:
29 entry["others"] = _filter_entries(entry["others"])
30 return entries
31
32 entries = _filter_entries(_sitemap["entries"])
33
34 def _link(entries, parent=None):
35 for entry in entries:
36 flattened.append(entry)
37 entry["parent"] = parent
38 if "others" in entry:
39 _link(entry["others"], parent=entry)
40
41 def _make_url(link):
42 path = [link["name"]]
43 parent = link["parent"]
44 while parent is not None:
45 path.append(parent["name"])
46 parent = parent["parent"]
47 path.reverse()
48 return "/".join(path)
49
50 _link(entries, parent=None)
51
52 for entry in flattened:
53 target = "/" + _make_url(entry)
54 if target == current_path:
55 entry["active"] = True
56 else:
57 entry["active"] = False
58 entry["url"] = target
59 by_name[target] = entry
60
61 return dict(by_name=by_name, links=entries)
62
63
64def _make_tree(links):
65 def _populate(root, links):
66 for link in links:
67 elm = ET.Element("li")
68 if "directory" in link and link["directory"]:
69 elm.text = link["name"]
70 else:
71 lref = ET.Element("a", href=link["url"])
72 link_text = link["name"]
73 if "date" in link:
74 link_text = link_text + " [" + str(link["date"]) + "]"
75 lref.text = link_text
76 if link["active"]:
77 lref.text = lref.text + " <"
78 elm.append(lref)
79 if "others" in link:
80 others = link["others"]
81 ul = ET.Element("ul")
82 elm.append(ul)
83 _populate(root=ul, links=others)
84 root.append(elm)
85
86 params = {"class": "tree"}
87
88 root = ET.Element("ul", **params)
89 _populate(root=root, links=links)
90 return ET.tostring(root).decode()
91
92
93def generate(template, content_path, stylesheet, link, sitemap, devmode=False):
94 sm, tree = None, None
95 if sitemap:
96 sm = _load_sitemap(sitemap, current_path=link)
97 if sm:
98 tree = _make_tree(sm["links"])
99 with open(template, "r") as fp:
100 template = fp.read()
101 env = Environment(loader=FunctionLoader(lambda name: template))
102 base = env.get_template(template)
103 with open(stylesheet) as fp:
104 style = fp.read()
105 with open(content_path) as fp:
106 text = fp.read()
107 content = markdown.markdown(
108 text,
109 extensions=["fenced_code", "tables"],
110 )
111 env_content = Environment(loader=FunctionLoader(lambda name: content))
112 out = base.render({
113 "content": env_content.get_template("").render({
114 "sitemap": sm,
115 "tree": tree,
116 }),
117 "is_index": False,
118 "link": link,
119 "style": style,
120 "sitemap": sm,
121 "tree": tree,
122 "devmode": devmode,
123 "current_time": datetime.now(),
124 })
125 print(out)
126
127
128if __name__ == "__main__":
129 parser = argparse.ArgumentParser(description="static renderer")
130 parser.add_argument("-content",
131 required=True,
132 help="markdown file with content")
133 parser.add_argument("-template",
134 default="index.jinja",
135 help="jinja template file")
136 parser.add_argument("-stylesheet",
137 default="./assets/main.css",
138 help="style sheet")
139 parser.add_argument("-sitemap",
140 help="sitemap")
141 parser.add_argument("-link",
142 default="/",
143 help="current url")
144 parser.add_argument("-devmode",
145 action="store_true",
146 help="developer mode (websocket page refresh)")
147 args = parser.parse_args()
148 generate(
149 template=args.template,
150 content_path=args.content,
151 stylesheet=args.stylesheet,
152 link=args.link,
153 sitemap=args.sitemap,
154 devmode=args.devmode)