personal_website/main.py

239 lines
6.8 KiB
Python
Executable File

#!/usr/bin/env python
import yaml
from jinja2 import Template, FileSystemLoader, Environment
import jinja2
import os
import shutil
import xml
import xml.etree.ElementTree as ET
import html
import datetime
import numpy as np
from pathlib import Path
DOMAIN = "https://www.weissmann.pm"
def Se(parent, tag, **kwargs):
# mod = {k.replace("_", "-"): v for k, v in kwargs.items() if v is not None}
mod = {}
for k, v in kwargs.items():
if v is not None:
if isinstance(v, (int, float)):
v = str(v)
mod[k.replace("_", "-")] = v
return ET.SubElement(parent, tag, **mod)
def add_site(urlset, url, lastmod):
el = ET.SubElement(urlset, "url")
ET.SubElement(el, "loc").text = html.escape(DOMAIN + url)
ET.SubElement(el, "lastmod").text = datetime.datetime.utcfromtimestamp(
lastmod
).strftime("%Y-%m-%d")
def remove_prefix(str, prefix):
assert str.startswith(prefix)
return str[len(prefix) :]
def remove_suffix(str, prefix):
assert str.endswith(prefix)
return str[: len(str) - len(prefix)]
def read_conf_md(name):
url = "/" + name + "/"
content = (Path("content") / (name + ".md")).read_text()
secs = content.split("---")
yaml_conf = secs[1]
conf = yaml.safe_load(yaml_conf)
return {
"url": url,
"abstract": conf["abstract"],
"title": conf["title"],
}
def read_conf_mds(names):
return [read_conf_md(name) for name in names]
def gen_index():
programming_articles = ["julialang", "bugfix-newsflash-color", "test-surface-code-quality", "fail-early", "http-301-is-not-404"]
german_politics_articles = ["framing-manual"]
programming_articles = read_conf_mds(programming_articles)
german_politics_articles = read_conf_mds(german_politics_articles)
templateLoader = FileSystemLoader(searchpath="./")
templateEnv = Environment(loader=templateLoader, undefined=jinja2.StrictUndefined)
template = templateEnv.get_template("index.html")
out = template.render(
programming_articles=programming_articles,
german_politics_articles=german_politics_articles,
)
with open("build/index.html", "w") as outfile:
outfile.write(out)
def gen_sitemap():
# todo_: build sitemap from build directory
urlset = ET.Element(
"urlset",
**{
"xmlns": "http://www.sitemaps.org/schemas/sitemap/0.9",
"xmlns:xhtml": "http://www.w3.org/1999/xhtml",
},
)
add_site(urlset, "/", os.path.getmtime("index.html"))
for root, subdirs, files in os.walk("content"):
for file in files:
if not file.endswith(".md"):
continue
url = (
remove_suffix(remove_prefix(root, "content") + "/" + file, ".md") + "/"
)
add_site(urlset, url, os.path.getmtime(root + "/" + file))
with open("build/sitemap.xml", "wb") as outfile:
outfile.write(ET.tostring(urlset, encoding="utf8"))
def polyline(svg, posar):
pointstr = " ".join(map(lambda el: str(el[0]) + "," + str(el[1]), posar))
Se(
svg,
"polyline",
points=pointstr,
fill="none",
stroke="currentColor",
)
def arrow(svg, pos1, pos2):
pos1 = np.array(pos1)
pos2 = np.array(pos2)
direction = (pos2 - pos1) / np.linalg.norm(pos2 - pos1)
perp = np.array([direction[1], -direction[0]])
end1 = pos1 + direction * 5
end2 = pos2 - direction * 5
x1, y1 = end1
x2, y2 = end2
polyline(svg, [end1, end2])
polyline(
svg,
[end2 - direction * 10 + perp * 5, end2, end2 - direction * 10 - perp * 5],
)
def gen_svg1():
stepdist = 80
boxwidth = 100
boxheight = 20
middle = 125
fontsize = 14
abortstep = 4
yoffset = boxheight / 2 + 1
for imgnum in range(1, 3):
svg = ET.Element(
"svg",
version="1.1",
width="400",
height=str(yoffset + stepdist * 5 + boxheight / 2 + 1),
xmlns="http://www.w3.org/2000/svg",
**{"xmlns:xlink": "http://www.w3.org/1999/xlink"},
)
Se(
svg, "style"
).text = "@media(prefers-color-scheme:light){svg{fill:#000000;color:#000000;background-color:#FFFFFF;}}@media(prefers-color-scheme:dark){svg{fill:#FFFFFF;color:#FFFFFF;background-color:#000000;}}"
for i in range(6):
if imgnum > 1 and i == 1:
partcolor = "red"
else:
partcolor = None
if imgnum > 1 and i > 1:
cmdcolor = "red"
else:
cmdcolor = None
if i != 0 and (i <= abortstep or imgnum == 1):
arrow(
svg,
(middle, yoffset + stepdist * (i - 1) + boxheight / 2),
(middle, yoffset + stepdist * i - boxheight / 2),
)
Se(
svg,
"text",
x=middle + 5,
y=yoffset + stepdist * (i - 1 / 2) + fontsize / 3,
fill=cmdcolor,
font_size=fontsize,
text_anchor="left",
).text = "Command " + str(i)
Se(
svg,
"text",
x=middle,
y=yoffset + stepdist * i + fontsize / 3,
fill=partcolor,
font_size=fontsize,
text_anchor="middle",
).text = "Part " + str(i)
Se(
svg,
"rect",
x=middle - boxwidth / 2,
y=yoffset + stepdist * i - boxheight / 2,
width=boxwidth,
height=boxheight,
fill="none",
stroke="currentColor",
)
if imgnum == 2:
abortdist = 60
arrow(
svg,
(middle + boxwidth / 2, yoffset + stepdist * abortstep),
(middle + boxwidth / 2 + abortdist, yoffset + stepdist * abortstep),
)
Se(
svg,
"rect",
x=middle + boxwidth / 2 + abortdist,
y=yoffset + stepdist * abortstep - boxheight / 2,
width=boxwidth,
height=boxheight,
fill="none",
stroke="currentColor",
)
Se(
svg,
"text",
x=middle + boxwidth + abortdist,
y=yoffset + stepdist * abortstep + fontsize / 3,
font_size=fontsize,
text_anchor="middle",
).text = "abort"
with open(
"build/fail-early/code-chain-" + str(imgnum) + ".svg", "wb"
) as outfile:
outfile.write(ET.tostring(svg, encoding="utf8"))
gen_index()
gen_sitemap()
gen_svg1()