aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/live-rules/manage.py
blob: fbe047c167e9045996fdefdfdadde8ab4a5c594f (plain)
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
#!/usr/bin/env python3
"""Build/test the shared Zig core or serve the local experiment. No Python dependencies."""
import argparse
from datetime import datetime, timezone
from functools import partial
import hashlib
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
import json
from pathlib import Path
import shutil
import subprocess

ROOT = Path(__file__).resolve().parent
VERSION = "0.15.2"


def digest(path):
    return hashlib.sha256(path.read_bytes()).hexdigest()


def build(zig):
    compiler = shutil.which(zig)
    if compiler is None:
        raise SystemExit("Zig 0.15.2가 필요합니다. ziglang.org/download 또는 --zig /path/to/zig를 사용하세요.")
    version = subprocess.check_output([compiler, "version"], text=True).strip()
    if version != VERSION:
        raise SystemExit(f"이 실험은 Zig {VERSION}로 고정했습니다. 현재: {version}")
    build_dir = ROOT / "build"
    build_dir.mkdir(exist_ok=True)
    cache = ["--cache-dir", str(build_dir / "cache"),
             "--global-cache-dir", str(build_dir / "global-cache")]
    source = ROOT / "core.zig"
    native = [compiler, "test", str(source), *cache]
    print("Checking native core…", flush=True)
    checked = subprocess.run(native, capture_output=True, text=True)
    print(checked.stdout + checked.stderr, end="", flush=True)
    checked.check_returncode()
    wasm = ROOT / "web" / "core.wasm"
    wasm.parent.mkdir(exist_ok=True)
    flags = ["-target", "wasm32-freestanding", "-O", "ReleaseSafe", "-fno-entry",
             "-rdynamic", "--export-memory", "--stack", "16384",
             "--initial-memory=65536", "--max-memory=65536"]
    command = [compiler, "build-exe", str(source), *flags, f"-femit-bin={wasm}", *cache]
    subprocess.run(command, check=True)
    (build_dir / "build.json").write_text(json.dumps({
        "built_utc": datetime.now(timezone.utc).isoformat(),
        "zig_version": version, "flags": flags,
        "source_sha256": digest(source), "wasm_sha256": digest(wasm),
        "wasm_file_bytes": wasm.stat().st_size,
        "native_test_output": checked.stdout + checked.stderr,
    }, ensure_ascii=False, indent=2) + "\n")
    print(f"Built {wasm} ({wasm.stat().st_size:,} bytes)")


class Handler(SimpleHTTPRequestHandler):
    extensions_map = {**SimpleHTTPRequestHandler.extensions_map, ".wasm": "application/wasm"}

    def end_headers(self):
        self.send_header("Cache-Control", "no-store")
        super().end_headers()


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    sub = parser.add_subparsers(dest="action", required=True)
    compile_cmd = sub.add_parser("build", help="native tests + WebAssembly build")
    compile_cmd.add_argument("--zig", default="zig")
    serve = sub.add_parser("serve", help="serve web/ on loopback only")
    serve.add_argument("--port", type=int, default=8765)
    args = parser.parse_args()
    if args.action == "build":
        build(args.zig)
        return
    if not 1 <= args.port <= 65535:
        parser.error("port must be between 1 and 65535")
    if not (ROOT / "web" / "core.wasm").is_file():
        parser.error("먼저 manage.py build를 실행하세요.")
    handler = partial(Handler, directory=str(ROOT / "web"))
    with ThreadingHTTPServer(("127.0.0.1", args.port), handler) as server:
        print(f"Pure: http://127.0.0.1:{args.port} (Ctrl+C to stop)", flush=True)
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            pass


if __name__ == "__main__":
    main()