"""The package managers' entries for a release of `wai`, as wai/quickstart/formulae.py writes
them, held to the archive build.sh packs:
python3 -I wai/quickstart/test/formulae_test.py
It runs formulae.py against a stand-in for the forge's release API on 127.0.0.1 (a release
with every platform's archive and its .sha256 attached), and checks what it writes:
- the Homebrew formula installs every binary build.sh packs but wai-quantum, and depends on
wai-quantum's own formula, which wai/wai-quantum-cli/release/formulae.py writes into the same
tap: installed by both, the one command would belong to two formulae, and the second's link
would fail;
- the Scoop manifest names the same binaries, each in the zip the Windows job packs, and
depends on wai-quantum's own manifest, so the two never share a shim;
- the archive's wai-quantum is built with the features wai-quantum's own release builds it
with on each platform (metal on macOS), so the program install.sh installs is the one the
package managers do;
- with ruby on PATH, the formula parses as Ruby.
Exit 0 when each holds, 1 naming each that does not. Standard library only.
"""
import hashlib
import http.server
import json
import pathlib
import re
import shutil
import subprocess
import sys
import tempfile
import threading
ROOT = pathlib.Path(__file__).resolve().parents[3]
QUICKSTART = ROOT / "wai/quickstart"
failures = []
def check(ok, what):
print(("ok " if ok else "FAIL ") + what)
if not ok:
failures.append(what)
build_sh = (QUICKSTART / "build.sh").read_text()
# `need "
" `: what the archive's bin/ holds.
packed = re.findall(r'^need "[^"]+" (\S+)', build_sh, re.M)
check("wai" in packed and "wai-quantum" in packed and len(packed) == len(set(packed)), f"build.sh packs wai and wai-quantum, each once ({packed})")
installed = [b for b in packed if b != "wai-quantum"]
# The forge, as formulae.py reads it: the release by its tag, and each archive's .sha256.
VERSION, TAG, REPO = "9.9.9", "wai-v9.9.9", "Transaction-Science/open-standards"
TRIPLES = ["aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-unknown-linux-musl", "x86_64-unknown-linux-musl"]
archives = [f"wai-{VERSION}-{t}.tar.gz" for t in TRIPLES] + [f"wai-{VERSION}-x86_64-pc-windows-msvc.zip"]
files = {}
for a in archives:
files[a] = a.encode()
files[a + ".sha256"] = f"{hashlib.sha256(a.encode()).hexdigest()} {a}\n".encode()
class Forge(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == f"/api/v1/repos/{REPO}/releases/tags/{TAG}":
body = json.dumps({"tag_name": TAG, "assets": [{"name": n} for n in files]}).encode()
elif self.path.startswith(f"/{REPO}/releases/download/{TAG}/") and self.path.rsplit("/", 1)[1] in files:
body = files[self.path.rsplit("/", 1)[1]]
else:
self.send_error(404)
return
self.send_response(200)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, *args):
pass
server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Forge)
threading.Thread(target=server.serve_forever, daemon=True).start()
api = f"http://127.0.0.1:{server.server_address[1]}/api/v1"
with tempfile.TemporaryDirectory() as out:
run = subprocess.run(
[sys.executable, "-I", str(QUICKSTART / "formulae.py"), VERSION, TAG, api, REPO, "https://forge.example/" + REPO, out],
capture_output=True, text=True, timeout=120,
)
server.shutdown()
check(run.returncode == 0, f"formulae.py writes the entries ({run.stderr.strip() or run.stdout.strip()})")
rb = pathlib.Path(out, "wai.rb").read_text() if run.returncode == 0 else ""
manifest = json.loads(pathlib.Path(out, "wai.json").read_text()) if run.returncode == 0 else {}
# The formula.
lines = [l.strip() for l in rb.splitlines() if l.strip().startswith("bin.install")]
check(len(lines) == 1, f"the formula installs bin/ in one line ({lines})")
names = re.findall(r'"bin/([^"]+)"', lines[0]) if lines else []
check(names == installed, f"the formula installs each binary build.sh packs but wai-quantum: {names}, not {installed}")
check('Dir["bin/*"]' not in rb and '"bin/wai-quantum"' not in rb, "the formula does not install bin/wai-quantum, by name or by a glob")
check('depends_on "transaction-science/tap/wai-quantum"' in rb, "the formula depends on wai-quantum's own formula")
for t in TRIPLES:
check(f"wai-{VERSION}-{t}.tar.gz" in rb and hashlib.sha256(f"wai-{VERSION}-{t}.tar.gz".encode()).hexdigest() in rb, f"the formula names the {t} archive and its digest")
if shutil.which("ruby"):
with tempfile.NamedTemporaryFile("w", suffix=".rb") as f:
f.write(rb)
f.flush()
r = subprocess.run(["ruby", "-c", f.name], capture_output=True, text=True)
check(r.returncode == 0, f"the formula parses as Ruby ({r.stdout.strip() or r.stderr.strip()})")
else:
print("note no ruby on PATH; the formula's syntax is not checked")
# The manifest.
check(manifest.get("bin") == [f"bin\\{b}.exe" for b in installed], f"the manifest names each binary but wai-quantum: {manifest.get('bin')}")
check(manifest.get("depends") == "wai-quantum", f"the manifest depends on wai-quantum's own manifest ({manifest.get('depends')!r})")
# The Windows job packs the binaries build.sh does, so each the manifest names is in the zip.
release = (ROOT / ".github/workflows/wai-release.yml").read_text()
windows = re.findall(r"bin = '([^']+)'", release)
check(sorted(windows) == sorted(packed), f"the Windows job packs build.sh's binaries ({windows})")
# wai-quantum's own entries are where the dependency names them: in this tap and this bucket,
# as wai-quantum.
own = (ROOT / "wai/wai-quantum-cli/release/formulae.py").read_text()
check("class WaiQuantum < Formula" in own and 'pathlib.Path(out, "wai-quantum.rb")' in own and 'pathlib.Path(out, "wai-quantum.json")' in own,
"wai-quantum's release writes the formula wai-quantum and the manifest wai-quantum")
# One program by either path: the archive's wai-quantum has the features of wai-quantum's own
# release, on macOS (its macOS job) and elsewhere (none).
quantum = (ROOT / ".github/workflows/wai-quantum-cli-release.yml").read_text()
mac_job = quantum.split("\n macos:", 1)[1].split("\n linux:", 1)[0]
mac_features = re.findall(r"cargo build [^\n]*--features (\S+)", mac_job)
other = quantum.split("\n linux:", 1)[1]
check(re.findall(r"cargo build [^\n]*--features (\S+)", other) == [], "wai-quantum's own Linux and Windows builds take no feature")
m = re.search(r"\*apple-darwin\) QUANTUM=\(--features (\S+)\)", build_sh)
check(m is not None and mac_features == [m.group(1)], f"the archive's macOS wai-quantum has the features of its own release's: {m and m.group(1)}, {mac_features}")
check(re.search(r'^need "\$ROOT/wai/wai-quantum-cli" wai-quantum --bin wai-quantum \$\{QUANTUM\[@\]', build_sh, re.M) is not None,
"build.sh builds wai-quantum with those features")
if failures:
print(f"formulae_test: {len(failures)} check(s) failed")
sys.exit(1)
print("formulae_test: every check held")