~kris/9p

krisyotam.net

ref: 8bfa4b74cf61e74b5d7c8df7d0b0bceefe2569fe krisyotam.net/scripts/build_static.py -rwxr-xr-x 3.3 KiB
8bfa4b74 — Kris Yotam ci: declare SourceHut source for push builds a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python3
"""Render the krisyotam.net Werc tree into a Vercel-ready static directory."""

from __future__ import annotations

import os
from pathlib import Path
import shutil
import subprocess
import sys


def route_for(markdown_file: Path, site_root: Path) -> str:
    relative = markdown_file.relative_to(site_root)
    if relative.name == "index.md":
        parent = relative.parent.as_posix()
        return "/" if parent == "." else f"/{parent}/"
    return f"/{relative.with_suffix('').as_posix()}"


def output_for(route: str, output_root: Path) -> Path:
    if route == "/":
        return output_root / "index.html"
    return output_root / route.strip("/") / "index.html"


def render(repo: Path, route: str) -> bytes:
    plan9 = Path("/usr/lib/plan9")
    environment = os.environ.copy()
    environment.update(
        {
            "PLAN9": str(plan9),
            "PATH": ":".join(
                [
                    str(plan9 / "bin"),
                    str(repo / "bin"),
                    str(repo / "bin" / "contrib"),
                    "/bin",
                    "/usr/bin",
                ]
            ),
            "SERVER_NAME": "plan9.krisyotam.com",
            "SERVER_PORT": "443",
            "REQUEST_METHOD": "GET",
            "REQUEST_URI": route,
            "PATH_INFO": route,
            "QUERY_STRING": "",
            "HTTP_COOKIE": "",
            "HTTP_HOST": "plan9.krisyotam.com",
            "HTTPS": "on",
        }
    )
    result = subprocess.run(
        [str(plan9 / "bin" / "rc"), "./werc.rc"],
        cwd=repo / "bin",
        env=environment,
        capture_output=True,
        check=True,
        timeout=20,
    )
    if b"\n\n" not in result.stdout:
        raise RuntimeError(f"No CGI header separator while rendering {route}")
    _, body = result.stdout.split(b"\n\n", 1)
    return body


def main() -> int:
    if len(sys.argv) != 3:
        print(f"usage: {sys.argv[0]} REPOSITORY OUTPUT", file=sys.stderr)
        return 2

    repo = Path(sys.argv[1]).resolve()
    output_root = Path(sys.argv[2]).resolve()
    site_root = repo / "sites" / "plan9.krisyotam.com"

    if output_root.exists():
        shutil.rmtree(output_root)
    output_root.mkdir(parents=True)

    markdown_files = sorted(
        path
        for path in site_root.rglob("*.md")
        if "_werc" not in path.relative_to(site_root).parts
    )
    routes = [route_for(path, site_root) for path in markdown_files]
    routes.extend(["/images/", "/sitemap"])

    for route in routes:
        destination = output_for(route, output_root)
        destination.parent.mkdir(parents=True, exist_ok=True)
        destination.write_bytes(render(repo, route))
        print(f"rendered {route} -> {destination.relative_to(output_root)}")

    (output_root / "404.html").write_bytes(render(repo, "/__not_found__"))
    shutil.copytree(repo / "pub", output_root / "pub")
    shutil.copytree(
        repo / "images",
        output_root / "images",
        ignore=shutil.ignore_patterns("images"),
        dirs_exist_ok=True,
    )
    shutil.copy2(repo / "pub" / "favicon.ico", output_root / "favicon.ico")
    shutil.copy2(site_root / "sitemap.txt", output_root / "sitemap.txt")
    print(f"rendered {len(routes)} content routes and copied static assets")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())