workspace_compile.py (4031B)
1 #!/usr/bin/env python3 2 """Haskell-only real-compiler workspace acceptance; no retained build artifacts. 3 Usage: python3 test/workspace_compile.py /absolute/path/to/tricu 4 """ 5 from pathlib import Path 6 import re 7 import shutil 8 import subprocess 9 import sys 10 import tempfile 11 12 13 def main(): 14 host = str(Path(sys.argv[1]).resolve()) 15 with tempfile.TemporaryDirectory(prefix="tricu-workspace-acceptance-") as tmp: 16 root = Path(tmp) 17 project = root / "project" 18 app = project / "apps" 19 lib = project / "lib" 20 app.mkdir(parents=True) 21 lib.mkdir() 22 entry = app / "main.tri" 23 entry.write_text("!import facade as F\n!export main\nmain = F.answer\n") 24 (lib / "facade-source.tri").write_text("!export * from numbers\n") 25 (lib / "numbers-source.tri").write_text("!export answer\nanswer = 42\n") 26 declaration = project / "tricu.workspace" 27 declaration.write_text("tricu.workspace.v1\nfacade\tlib/facade-source.tri\nnumbers\tlib/numbers-source.tri\n") 28 29 def run(*args, success=True): 30 p = subprocess.run([host, *map(str, args), "+RTS", "-N1", "-RTS"], 31 cwd=root, text=True, capture_output=True, timeout=180) 32 assert (p.returncode == 0) == success, (args, p.stdout, p.stderr) 33 return p.stdout 34 35 store = root / "store" 36 assert run("eval", entry, "--store", store, "--format", "number").strip() == "42" 37 mapped_bundle = root / "mapped.arboricx" 38 run("arboricx", "compile", "--file", entry, "--store", store, "--output", mapped_bundle) 39 flat = root / "flat" 40 flat.mkdir() 41 shutil.copyfile(entry, flat / "main.tri") 42 shutil.copyfile(lib / "facade-source.tri", flat / "facade.tri") 43 shutil.copyfile(lib / "numbers-source.tri", flat / "numbers.tri") 44 flat_bundle = root / "flat.arboricx" 45 run("arboricx", "compile", "--file", flat / "main.tri", "--store", root / "flat-store", "--output", flat_bundle) 46 assert mapped_bundle.read_bytes() == flat_bundle.read_bytes(), "location changed bundle identity" 47 # Capture shares the location resolver; replay is isolated even under a 48 # parent declaration that would otherwise conflict with retained sources. 49 tools = root / "tools" 50 shipped = Path(__file__).resolve().parent.parent / "bootstrap/build-stable.arboricx" 51 imported = run("arboricx", "import", "--file", shipped, "--store", tools) 52 compiler = re.search(r"Created module alias .* -> ([0-9a-f]{64})", imported)[1] 53 run("arboricx", "compile", "--file", entry, "--store", store, 54 "--toolchain", compiler, "--tool-store", tools, "--output", mapped_bundle) 55 pack = root / "inputs" 56 captured = run("provenance", "capture", "--file", entry, "--store", store, 57 "--toolchain", compiler, "--tool-store", tools, "--output", pack) 58 pin = re.search(r"Retained build inputs: ([0-9a-f]{64})", captured)[1] 59 run("provenance", "rebuild", "--pack", pack, "--pin", pin, 60 "--trust-compiler", compiler, "--output", project / "replayed") 61 # Cache must observe source edits, not just declaration paths. 62 (lib / "numbers-source.tri").write_text("!export answer\nanswer = 7\n") 63 assert run("eval", entry, "--store", store, "--format", "number").strip() == "7" 64 # Ordinary compiler controls remain in force through the mapped route. 65 (lib / "numbers-source.tri").write_text("!import facade as F\n!export answer\nanswer = F.answer\n") 66 run("eval", entry, "--store", store, success=False) 67 (lib / "numbers-source.tri").write_text("!import absent as A\n!export answer\nanswer = A.answer\n") 68 run("eval", entry, "--store", store, success=False) 69 (app / "facade.tri").write_text("!export answer\nanswer = 99\n") 70 run("eval", entry, "--store", store, success=False) 71 print("workspace compile acceptance passed") 72 73 74 if __name__ == "__main__": 75 main()