#!/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())