Index

joshstock.in / b2d3957

Source for serving and static templating/compiling of https://joshstock.in.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
8128 Mar 2020 23:26b2d3957Rewrite template engineJosh Stockin1190163G

Blob @ joshstock.in / root / compile.py

application/x-python6697 bytesdownload raw
1#!/usr/bin/env python3
2"""Open source template engine for compilation of the static joshstock.in"""
3
4import sys
5import os
6import shutil
7import json
8import markdown2
9import readtime
10
11
12def file_read(filename: str):
13 """Read text from file by filename"""
14 try:
15 with open(filename, "r") as file:
16 return file.read()
17 except FileNotFoundError:
18 print(f"[file_read] '{filename}' not found. exiting...")
19 exit(1)
20 except Exception as error:
21 print(f"[file_read] error while trying to read from '{filename}':")
22 print(error)
23 print("[file_read] exiting...")
24 exit(1)
25
26
27def file_write(filename: str, text: str):
28 """Write text to file by filename"""
29 try:
30 with open(filename, "w") as file:
31 file.write(text)
32 except Exception as error:
33 print(f"[file_write] error while trying to write to '{filename}':")
34 print(error)
35 print("[file_write] exiting...")
36 exit(1)
37
38
39def directory_empty(path: str):
40 """Clear file directory by path"""
41 for file in os.listdir(path):
42 filepath = os.path.join(path, file)
43 try:
44 if os.path.isfile(filepath):
45 os.unlink(filepath)
46 elif os.path.isdir(filepath):
47 shutil.rmtree(filepath)
48 except Exception as error:
49 print(f"[directory_empty] error while trying to empty directory {path}:")
50 print(error)
51 print("[directory_empty] exiting...")
52 exit(1)
53
54
55ROUTEMAP = {}
56TEMPLATES = {}
57
58
59def template_fill(template_string: str, template_keys: dict):
60 """Fills in all template key placeholders in template_string"""
61 global TEMPLATES
62 return_string = template_string
63 did_fill = False
64 for key in template_keys:
65 if f"${key}" in return_string:
66 return_string = return_string.replace(f"${key}", template_keys[key])
67 did_fill = True
68 for key in TEMPLATES:
69 if f"${key}" in return_string:
70 return_string = return_string.replace(f"${key}", TEMPLATES[key])
71 did_fill = True
72 if did_fill:
73 return_string = template_fill(return_string, template_keys)
74 return return_string
75
76
77def templates_load(templates_config: dict):
78 """Preload templates from their files"""
79 templates = {}
80 for temp in templates_config:
81 print(f"[templates_load] loading template '{temp}'")
82 templates[temp] = file_read(templates_config[temp])
83 return templates
84
85
86def template(output_path: str):
87 """The main template engine to generate the site's static content"""
88 global TEMPLATES
89 global ROUTEMAP
90 print("[template] emptying working directory")
91 directory_empty(output_path)
92
93 print("[template] reading config file at ./config.json")
94 config = json.loads(file_read("config.json"))
95
96 print("[template] copying static directory")
97 output_file = os.path.join(output_path, "static")
98 shutil.copytree(config["static_directory"], output_file)
99
100 print("[template] loading templates from config")
101 TEMPLATES = templates_load(config["templates"])
102
103 print("[template] running blog article generator")
104 blog_article_listings = ""
105 for article in config["articles"]:
106 article_url = f"/blog/{article['identifier']}"
107 print(f"[template/blog] creating article '{article['title']}' at {article_url}")
108
109 content = markdown2.markdown(file_read(article["markdown"]))
110 content_time = str(readtime.of_html(content))
111
112 # Create a new listing for the blog archive page
113 blog_article_listings += template_fill(
114 TEMPLATES["blog-listing"],
115 {
116 "title": article["title"],
117 "datestring": article["datestring"],
118 "readtime": content_time,
119 "banner": article["banner"],
120 "description": article["description"],
121 "permalink": article_url,
122 },
123 )
124
125 # Create blog article from template
126 blog_article = template_fill(
127 TEMPLATES["blog-article"],
128 {
129 "title": article["title"],
130 "datestring": article["datestring"],
131 "readtime": content_time,
132 "banner": article["banner"],
133 "description": article["description"],
134 "permalink": article_url,
135 "content": content,
136 },
137 )
138 output_file = os.path.join(output_path, f"blog-{article['identifier']}.html")
139 file_write(output_file, blog_article)
140 ROUTEMAP[f"{config['domain']}{article_url}"] = 0.7
141
142 TEMPLATES["@blog-listings"] = blog_article_listings
143
144 print("[template] running page generator")
145 for page in config["pages"]:
146 page_url = page["location"]
147 print(f"[template/page] creating page '{page['title']}' at {page_url}")
148 content = template_fill(
149 file_read(page["file"]),
150 {
151 "title": page["title"],
152 "description": page["description"],
153 "permalink": page_url,
154 },
155 )
156 output_file = os.path.join(output_path, page["destination"])
157 file_write(output_file, content)
158 ROUTEMAP[f"{config['domain']}{page_url}"] = page["priority"]
159
160 print("[template] copying custom static files")
161 for copy in config["copy"]:
162 print(f"[template/copy] copying file '{copy['file']}' to '{copy['location']}'")
163 output_file = os.path.join(output_path, copy["location"])
164 shutil.copy(copy["file"], output_file)
165
166 print("[template] compiling sitemap XML")
167 sitemap = TEMPLATES["sitemap"]
168 for route in ROUTEMAP:
169 sitemap += (
170 f"<url><loc>{route}</loc><priority>{ROUTEMAP[route]}</priority></url>"
171 )
172 sitemap += "</urlset>"
173 output_file = os.path.join(output_path, "sitemap.xml")
174 file_write(output_file, sitemap)
175
176 print("[template] finished")
177
178
179if __name__ == "__main__":
180 if len(sys.argv) < 2:
181 FOLDER_OUT = "/var/www/html"
182 else:
183 FOLDER_OUT = sys.argv[1]
184 print(f"[main] compile.py starting")
185 print(f"[main] changing active directory to script location")
186 os.chdir(sys.path[0])
187 if not os.path.isdir(FOLDER_OUT):
188 print(f"[main] {FOLDER_OUT} is not a valid folder location. exiting...")
189 exit(1)
190 OUTPUT_PATH = os.path.abspath(FOLDER_OUT)
191 print(f"[main] output path set to {OUTPUT_PATH}")
192 print(f"[main] running template engine routine")
193 template(OUTPUT_PATH)
194 print(f"[main] finished. exiting...")
195 exit(0)
196else:
197 print(f"[main] script is not __main__. exiting...")
198 exit(1)
199