1 | #!/usr/bin/env python
|
2 | import argparse
|
3 | import os
|
4 | import sys
|
5 | import xml.etree.ElementTree as ET
|
6 |
|
7 | from datetime import datetime
|
8 |
|
9 | import markdown
|
10 | import yaml
|
11 | from jinja2 import Environment, FunctionLoader
|
12 |
|
13 |
|
14 | def _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 |
|
64 | def _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 |
|
93 | def 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 |
|
128 | if __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)
|