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