diff options
Diffstat (limited to 'template.py')
-rwxr-xr-x | template.py | 369 |
1 files changed, 295 insertions, 74 deletions
diff --git a/template.py b/template.py index 94dac8cf..a5b3119b 100755 --- a/template.py +++ b/template.py | |||
@@ -19,7 +19,7 @@ | |||
19 | # | 19 | # |
20 | # We import unicode_literals until people have understood how unicode | 20 | # We import unicode_literals until people have understood how unicode |
21 | # with bytes and strings changed in python2->python3. | 21 | # with bytes and strings changed in python2->python3. |
22 | from __future__ import unicode_literals | 22 | # from __future__ import unicode_literals |
23 | import os | 23 | import os |
24 | import os.path | 24 | import os.path |
25 | import sys | 25 | import sys |
@@ -29,6 +29,8 @@ import glob | |||
29 | import codecs | 29 | import codecs |
30 | import jinja2 | 30 | import jinja2 |
31 | import i18nfix | 31 | import i18nfix |
32 | from pathlib import Path | ||
33 | import hashlib | ||
32 | 34 | ||
33 | # TODO: Turn repetition into a class. | 35 | # TODO: Turn repetition into a class. |
34 | 36 | ||
@@ -51,93 +53,312 @@ langs_full = { | |||
51 | "de": "Deutsch" | 53 | "de": "Deutsch" |
52 | } | 54 | } |
53 | 55 | ||
54 | for in_file in glob.glob("template/*.j2"): | 56 | # A construction has: |
55 | name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups() | 57 | # symlinks (dict) |
56 | tmpl = env.get_template(in_file) | 58 | # staticfiles (dict) |
59 | # robot.txt files (list) | ||
60 | # locales (list) | ||
61 | # shells out to siteindex (todo: python siteindex) | ||
62 | # generation_directories: the one we are building right now | ||
63 | # the one we will be replacing | ||
64 | # other directories get trashed upon successful build | ||
57 | 65 | ||
58 | def self_localized(other_locale): | 66 | symlinks = { |
59 | """ | 67 | "frontpage.html": "frontpage", |
60 | Return URL for the current page in another locale. | 68 | "gsoc.html": "gsoc", |
61 | """ | 69 | "about.html": "philosophy", |
62 | return "../" + other_locale + "/" + in_file.replace('template/', | 70 | "gns.html": "gns", |
63 | '').rstrip(".j2") | 71 | "node/about.html": "397" |
72 | } | ||
64 | 73 | ||
65 | def url_localized(filename): | 74 | # Mostly from static/ to rendered/ |
66 | return "../" + locale + "/" + filename | 75 | staticfiles = { |
76 | "favicon.ico": "favicon.ico", | ||
77 | "moved.html": "frontpage.html", | ||
78 | "robots.txt": ["static", "dist", list(langs_full)], | ||
79 | "moved_gsoc.html": "gsoc.html", | ||
80 | "moved_about.html": "about.html", | ||
81 | "moved_gns.html": "gns.html" | ||
82 | } | ||
67 | 83 | ||
68 | def svg_localized(filename): | 84 | |
69 | lf = filename + "." + locale + ".svg" | 85 | def localized(filename, locale, *args): |
70 | if locale == "en" or not os.path.isfile(lf): | 86 | if len(args) == 0: |
71 | return "../" + filename + ".svg" | 87 | return "../" + locale + "/" + filename |
88 | ext = kwargs.get('ext', None) | ||
89 | if ext is not None: | ||
90 | lf = filename + "." + locale + "." + ext | ||
91 | lp = Path(lf) | ||
92 | if locale == "en" or not lp.is_file(): | ||
93 | return "../" + filename + "." + ext | ||
72 | else: | 94 | else: |
73 | return "../" + lf | 95 | return "../" + lf |
74 | 96 | ||
75 | def url(x): | ||
76 | # TODO: look at the app root environment variable | ||
77 | # TODO: check if file exists | ||
78 | return "../" + x | ||
79 | 97 | ||
80 | for l in glob.glob("locale/*/"): | 98 | def fileop(infile, outfile, action): |
81 | locale = os.path.basename(l[:-1]) | 99 | """ |
100 | infile: inputfile, Path object | ||
101 | outfile: outputfile, Path object | ||
102 | action: action if any, String | ||
103 | """ | ||
104 | i = Path(infile) | ||
105 | o = Path(outfile) | ||
106 | outdir = Path("rendered") | ||
107 | if i.is_file() is not False: | ||
108 | if action == "copy": | ||
109 | # Write content of i to o. | ||
110 | o.write_text(i.read_text()) | ||
111 | if action == "link": | ||
112 | o.symlink_to(i) | ||
82 | 113 | ||
83 | tr = gettext.translation("messages", | ||
84 | localedir="locale", | ||
85 | languages=[locale]) | ||
86 | 114 | ||
87 | tr.gettext = i18nfix.wrap_gettext(tr.gettext) | 115 | def write_name(filename, infile, locale, replacer): |
116 | return "./rendered/" + locale + "/" + infile.replace(replacer, | ||
117 | '').rstrip(".j2") | ||
88 | 118 | ||
89 | env.install_gettext_translations(tr, newstyle=True) | ||
90 | 119 | ||
91 | content = tmpl.render(lang=locale, | 120 | def sha256sum(_): |
92 | lang_full=langs_full[locale], | 121 | sha256 = hashlib.sha256() |
93 | url=url, | 122 | with io.open(_, mode="rb") as fd: |
94 | self_localized=self_localized, | 123 | content = fd.read() |
95 | url_localized=url_localized, | 124 | sha256.update(content) |
96 | svg_localized=svg_localized, | 125 | return sha256.hexdigest() |
97 | filename=name + "." + ext) | ||
98 | out_name = "./rendered/" + locale + "/" + in_file.replace( | ||
99 | 'template/', '').rstrip(".j2") | ||
100 | os.makedirs("./rendered/" + locale, exist_ok=True) | ||
101 | with codecs.open(out_name, "w", encoding='utf-8') as f: | ||
102 | f.write(content) | ||
103 | 126 | ||
104 | 127 | ||
105 | for in_file in glob.glob("news/*.j2"): | 128 | def walksum(_): |
106 | name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups() | 129 | sha256 = hashlib.sha256() |
107 | tmpl = env.get_template(in_file) | 130 | x = Path(_) |
131 | if not x.exists(): | ||
132 | return -1 | ||
133 | try: | ||
134 | for root, directories, files in os.walk(_): | ||
135 | for names in sorted(files): | ||
136 | filepath = os.path.join(root, names) | ||
137 | try: | ||
138 | fl = open(filepath, 'rb') | ||
139 | except: | ||
140 | fl.close() | ||
141 | continue | ||
142 | while 1: | ||
143 | buf = fl.read(4096) | ||
144 | if not buf: | ||
145 | break | ||
146 | sha256.update(hashlib.sha256(buf).hexdigest()) | ||
147 | fl.close() | ||
148 | except: | ||
149 | import traceback | ||
150 | traceback.print_exc() | ||
151 | return -2 | ||
152 | return sha256.hexdigest() | ||
108 | 153 | ||
109 | def self_localized(other_locale): | ||
110 | """ | ||
111 | Return URL for the current page in another locale. | ||
112 | """ | ||
113 | return "../" + other_locale + "/" + in_file.replace('news/', | ||
114 | '').rstrip(".j2") | ||
115 | 154 | ||
116 | def url_localized(filename): | 155 | def rm_rf(directory): |
117 | return "../" + locale + "/" + filename | 156 | directory = Path(directory) |
118 | 157 | for child in directory.glob('*'): | |
119 | def svg_localized(filename): | 158 | if child.is_file(): |
120 | lf = filename + "." + locale + ".svg" | 159 | child.unlink() |
121 | if locale == "en" or not os.path.isfile(lf): | ||
122 | return "../" + filename + ".svg" | ||
123 | else: | 160 | else: |
124 | return "../" + lf | 161 | rm_rf(child) |
162 | directory.rmdir() | ||
163 | |||
164 | |||
165 | # This generates and switches sites generations, preventing | ||
166 | # in-place modification of the website. | ||
167 | # * save old generation directory name | ||
168 | # * jinja2 creates content in "rendered" (happened before calling this function) | ||
169 | # * calculate sum of "rendered" | ||
170 | # * move "rendered" to out/$sum | ||
171 | # * remove symlink "html_dir" | ||
172 | # * symlink out/$sum to "html_dir" | ||
173 | # * delete old generation directory | ||
174 | def generation_dir(htmldir): | ||
175 | oldgen = Path(htmldir).resolve() | ||
176 | # precondition: jinja2 has created the files in "rendered". | ||
177 | newgen = Path("rendered") | ||
178 | newgen_sum = walksum(newgen) | ||
179 | outdir = Path("out") | ||
180 | outdir.mkdir(parents=True, exist_ok=True) | ||
181 | newgen_target = Path("out") / newgen_sum | ||
182 | newgen.rename(newgen_target) | ||
183 | html = Path(htmldir) | ||
184 | html.unlink() | ||
185 | fileop(newgen, html, "link") | ||
186 | rm_rf(oldgen) | ||
187 | |||
188 | |||
189 | def copy_static (locale, indict): | ||
190 | for key, value in indict.items(): | ||
191 | print(locale + "/" + key + " ...to... " + locale + "/" + value) | ||
192 | # fileop(in, out, "copy") | ||
193 | |||
194 | # At this moment in time, constructing this list dynamically would be | ||
195 | # too much pointless code. In fact all of what we use in jinja is | ||
196 | # no real use of jinja yet and furthermore we would be better off | ||
197 | # just using static html + css + some awk and other base tools. | ||
198 | newsposts = [ | ||
199 | {'page': '2019-0.11.8.html', 'date': '2019-10-30', 'title': 'GNUnet 0.11.8'}, | ||
200 | {'page': '2019-0.11.7.html', 'date': '2019-10-27', 'title': 'GNUnet 0.11.7'}, | ||
201 | {'page': '2019-10-ICANNPanel.html', 'date': '2019-10-20', 'title': 'ICANN Panel'}, | ||
202 | {'page': '2019-10-GNSSpec1.html', 'date': '2019-10-04', 'title': 'GNS Spec 1'}, | ||
203 | {'page': '2019-0.11.6.html', 'date': '2019-07-24', 'title': 'GNUnet 0.11.6'}, | ||
204 | {'page': '2019-07-GHM_Aug_2019.html', 'date': '2019-07-17', 'title': 'GNUnet Hacker Meeting 2019'}, | ||
205 | {'page': '2019-06-DSTJ.html', 'date': '2019-06-28', 'title': 'DSTJ'}, | ||
206 | {'page': '2019-0.11.5.html', 'date': '2019-06-05', 'title': 'GNUnet 0.11.5'}, | ||
207 | {'page': '2019-06.html', 'date': '2019-06-01', 'title': '2019-06'}, | ||
208 | {'page': '2019-0.11.4.html', 'date': '2019-05-12', 'title': 'GNUnet 0.11.4'}, | ||
209 | {'page': '2019-0.11.3.html', 'date': '2019-04-07', 'title': 'GNUnet 0.11.3'}, | ||
210 | {'page': '2019-0.11.2.html', 'date': '2019-04-04', 'title': 'GNUnet 0.11.2'}, | ||
211 | {'page': '2019-0.11.1.html', 'date': '2019-04-03', 'title': 'GNUnet 0.11.1'}, | ||
212 | {'page': '2019-0.11.0.html', 'date': '2019-02-28', 'title': 'GNUnet 0.11.0'}, | ||
213 | {'page': '2019-02.html', 'date': '2019-02-01', 'title': 'Google Summer of Code 2019'}, | ||
214 | ] | ||
215 | |||
216 | |||
217 | def generate_site(root): | ||
218 | for in_file in glob.glob(root + "/*.j2"): | ||
219 | name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups() | ||
220 | tmpl = env.get_template(in_file) | ||
221 | |||
222 | def self_localized(other_locale): | ||
223 | """ | ||
224 | Return URL for the current page in another locale. | ||
225 | """ | ||
226 | return "../" + other_locale + "/" + in_file.replace( | ||
227 | root + '/', '').rstrip(".j2") | ||
228 | |||
229 | def url_localized(filename): | ||
230 | if root == "news": | ||
231 | return "../../" + locale + "/" + filename | ||
232 | else: | ||
233 | return "../" + locale + "/" + filename | ||
234 | |||
235 | def url_static (filename): | ||
236 | if root == "news": | ||
237 | return "../../static/" + filename | ||
238 | else: | ||
239 | return "../static/" + filename | ||
240 | |||
241 | def url_dist (filename): | ||
242 | if root == "news": | ||
243 | return "../../dist/" + filename | ||
244 | else: | ||
245 | return "../dist/" + filename | ||
246 | |||
247 | def svg_localized(filename): | ||
248 | lf = filename + "." + locale + ".svg" | ||
249 | if locale == "en" or not os.path.isfile(lf): | ||
250 | return "../" + filename + ".svg" | ||
251 | else: | ||
252 | return "../" + lf | ||
253 | |||
254 | def url(x): | ||
255 | # TODO: look at the app root environment variable | ||
256 | # TODO: check if file exists | ||
257 | #if root == "news": | ||
258 | # return "../" + "../" + x | ||
259 | #else: | ||
260 | # return "../" + x | ||
261 | return "../" + x | ||
262 | |||
263 | |||
264 | for l in glob.glob("locale/*/"): | ||
265 | locale = os.path.basename(l[:-1]) | ||
266 | |||
267 | tr = gettext.translation("messages", | ||
268 | localedir="locale", | ||
269 | languages=[locale]) | ||
270 | |||
271 | tr.gettext = i18nfix.wrap_gettext(tr.gettext) | ||
272 | |||
273 | env.install_gettext_translations(tr, newstyle=True) | ||
274 | |||
275 | content = tmpl.render(lang=locale, | ||
276 | lang_full=langs_full[locale], | ||
277 | url=url, | ||
278 | newsdata=newsposts, | ||
279 | self_localized=self_localized, | ||
280 | url_localized=url_localized, | ||
281 | url_static=url_static, | ||
282 | url_dist=url_dist, | ||
283 | svg_localized=svg_localized, | ||
284 | filename=name + "." + ext) | ||
285 | |||
286 | if root == "news": | ||
287 | out_name = "./rendered/" + locale + "/" + root + "/" + in_file.replace( | ||
288 | root + '/', '').rstrip(".j2") | ||
289 | else: | ||
290 | out_name = "./rendered/" + locale + "/" + in_file.replace( | ||
291 | root + '/', '').rstrip(".j2") | ||
292 | |||
293 | outdir = Path("rendered") | ||
294 | |||
295 | if root == "news": | ||
296 | langdir = outdir / locale / root | ||
297 | else: | ||
298 | langdir = outdir / locale | ||
299 | |||
300 | langdir.mkdir(parents=True, exist_ok=True) | ||
301 | # os.makedirs("./rendered/" + locale, exist_ok=True) | ||
302 | with codecs.open(out_name, "w", encoding='utf-8') as f: | ||
303 | f.write(content) | ||
304 | |||
305 | |||
306 | def main(): | ||
307 | # rm_rf("rendered") | ||
308 | print("generating template") | ||
309 | generate_site("template") | ||
310 | print("generating news") | ||
311 | generate_site("news") | ||
312 | # for l in glob.glob("locale/*/"): | ||
313 | # locale = os.path.basename(l[:-1]) | ||
314 | # copy_static (locale, staticfiles) | ||
315 | # generate_rss | ||
316 | #print("running generation") | ||
317 | #generation_dir | ||
318 | |||
319 | |||
320 | if __name__ == "__main__": | ||
321 | main() | ||
322 | |||
323 | # for in_file in glob.glob("news/*.j2"): | ||
324 | # name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups() | ||
325 | # tmpl = env.get_template(in_file) | ||
326 | |||
327 | # def self_localized(other_locale): | ||
328 | # """ | ||
329 | # Return URL for the current page in another locale. | ||
330 | # """ | ||
331 | # return "../" + other_locale + "/" + in_file.replace('news/', | ||
332 | # '').rstrip(".j2") | ||
333 | |||
334 | # def url_localized(filename): | ||
335 | # return "../" + locale + "/" + filename | ||
336 | |||
337 | # def svg_localized(filename): | ||
338 | # lf = filename + "." + locale + ".svg" | ||
339 | # if locale == "en" or not os.path.isfile(lf): | ||
340 | # return "../" + filename + ".svg" | ||
341 | # else: | ||
342 | # return "../" + lf | ||
343 | |||
344 | # def url(x): | ||
345 | # # TODO: look at the app root environment variable | ||
346 | # # TODO: check if file exists | ||
347 | # return "../" + x | ||
125 | 348 | ||
126 | def url(x): | 349 | # for f in glob.glob("locale/*/"): |
127 | # TODO: look at the app root environment variable | 350 | # locale = os.path.basename(f[:-1]) |
128 | # TODO: check if file exists | 351 | # content = tmpl.render(lang=locale, |
129 | return "../" + x | 352 | # lang_full=langs_full[locale], |
130 | 353 | # url=url, | |
131 | for f in glob.glob("locale/*/"): | 354 | # self_localized=self_localized, |
132 | locale = os.path.basename(f[:-1]) | 355 | # url_localized=url_localized, |
133 | content = tmpl.render(lang=locale, | 356 | # svg_localized=svg_localized, |
134 | lang_full=langs_full[locale], | 357 | # filename=name + "." + ext) |
135 | url=url, | 358 | # out_name = "./rendered/" + locale + "/news/" + in_file.replace('news/', '').rstrip(".j2") |
136 | self_localized=self_localized, | 359 | # outdir = Path("rendered") |
137 | url_localized=url_localized, | 360 | # langdir = outdir / locale / "news" |
138 | svg_localized=svg_localized, | 361 | # langdir.mkdir(parents=True, exist_ok=True) |
139 | filename=name + "." + ext) | 362 | # # os.makedirs("./rendered/" + locale + "/news/", exist_ok=True) |
140 | out_name = "./rendered/" + locale + "/news/" + in_file.replace('news/', '').rstrip(".j2") | 363 | # with codecs.open(out_name, "w", encoding='utf-8') as f: |
141 | os.makedirs("./rendered/" + locale + "/news/", exist_ok=True) | 364 | # f.write(content) |
142 | with codecs.open(out_name, "w", encoding='utf-8') as f: | ||
143 | f.write(content) | ||