open-standards/wai/quickstart/formulae.py
Transaction Science 15d6a51e9d CI: the examples run on every leg that hosts them, and the release builds the archive
.github/workflows/wai-examples.yml runs each example through wai create and
wai dev: the portable ones on linux, the archive as the release builds it,
the quickstart's readiness check (wai dev --check from the unpacked archive),
the browser examples and apple-app on macos, android-app on linux-arm64.
wai-conformance.yml runs tests/floor.rs and tests/cli_dx.rs, and fires on
wai/examples/ (the templates are compiled into wai). wai-release.yml, on a
tag wai-v<version>, builds the room client once and the archive on each
runner, attaches them with their SHA-256, and writes the Homebrew formula
and the Scoop manifest; wai/quickstart/install.sh installs a release.

Two clippy notes of the new code fixed (a type alias for a template's files;
hex only where hello and verify are built).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 22:58:39 -04:00

101 lines
3.5 KiB
Python

"""The package managers' entries for a release of the WAI command line, from the SHA-256 files
attached to it:
python3 wai/quickstart/formulae.py <version> <tag> <forge-api> <owner/repo> <public-url> <out-dir>
Writes <out-dir>/wai.rb (a Homebrew formula for macOS and Linux) and <out-dir>/wai.json (a
Scoop manifest for Windows). A platform whose archive is not attached is left out, and stderr
says so; with none at all, it fails. Each archive holds bin/ and share/wai/web/, kept side by
side as `wai dev` expects them.
"""
import json
import os
import pathlib
import sys
import urllib.request
version, tag, api, repo, public, out = sys.argv[1:7]
token = os.environ.get("FORGE_TOKEN", "")
headers = {"User-Agent": "wai-release"}
if token:
headers["Authorization"] = f"token {token}"
web = api.rsplit("/api/v1", 1)[0]
def get(url):
with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=60) as r:
return r.read()
release = json.loads(get(f"{api}/repos/{repo}/releases/tags/{tag}"))
assets = {a["name"]: a for a in release.get("assets", [])}
def digest(archive):
if archive not in assets or archive + ".sha256" not in assets:
print(f"note: {archive} is not attached; left out", file=sys.stderr)
return None
return get(f"{web}/{repo}/releases/download/{tag}/{archive}.sha256").decode().split()[0]
def url(archive):
return f"{public}/releases/download/{tag}/{archive}"
DESC = "WAI, an open media standard: its command line, and a local relay and room service"
HOME = "https://wai.transaction.science/docs/quickstart/"
targets = {
("macos", "arm"): "aarch64-apple-darwin",
("macos", "intel"): "x86_64-apple-darwin",
("linux", "arm"): "aarch64-unknown-linux-musl",
("linux", "intel"): "x86_64-unknown-linux-musl",
}
blocks = {}
for (os_name, cpu), triple in targets.items():
archive = f"wai-{version}-{triple}.tar.gz"
sha = digest(archive)
if sha:
blocks.setdefault(os_name, []).append(f' on_{cpu} do\n url "{url(archive)}"\n sha256 "{sha}"\n end\n')
win = f"wai-{version}-x86_64-pc-windows-msvc"
win_sha = digest(win + ".zip")
if not blocks and not win_sha:
sys.exit("no archive is attached to the release")
formula = f'''class Wai < Formula
desc "{DESC}"
homepage "{HOME}"
version "{version}"
license "Apache-2.0"
'''
for os_name in ("macos", "linux"):
if os_name in blocks:
formula += f" on_{os_name} do\n" + "".join(blocks[os_name]) + " end\n"
formula += '''
def install
# bin/ and share/wai/web/ side by side: `wai dev` finds the relay, the room service and the
# room client beside its own binary.
bin.install Dir["bin/*"]
(share/"wai").install "share/wai/web"
end
test do
assert_match "video-room", shell_output("#{bin}/wai create --list")
assert_match "delivered-verified", shell_output("#{bin}/wai hello #{testpath}/hello")
assert_match "verified", shell_output("#{bin}/wai verify #{testpath}/hello")
end
end
'''
pathlib.Path(out, "wai.rb").write_text(formula)
if win_sha:
manifest = {
"version": version,
"description": DESC,
"homepage": HOME,
"license": "Apache-2.0",
"architecture": {"64bit": {"url": url(win + ".zip"), "hash": win_sha, "extract_dir": win}},
"bin": ["bin\\wai.exe", "bin\\joule-moq-relay.exe", "bin\\joule-moq-room.exe", "bin\\wai-remote-host.exe", "bin\\wai-pack.exe"],
}
pathlib.Path(out, "wai.json").write_text(json.dumps(manifest, indent=2) + "\n")
print(f"wrote the formula{' and the manifest' if win_sha else ''} for wai {version}")