from __future__ import annotations
from pathlib import Path
try:
import tomllib
except ModuleNotFoundError: try:
import tomli as tomllib
except ModuleNotFoundError:
tomllib = None
REQUIRED_FIELDS = {
"triple",
"target_os",
"target_arch",
"target_libc",
"core_supported",
"runtime_supported",
"release_asset",
"runtime_features",
"source_gate",
"post_release_gate",
"asset_suffix",
}
MUSL_RUNTIME_FIELDS = {
"runtime_backend",
"pointer_width",
"endianness",
}
def load_platforms(root: Path) -> list[dict[str, object]]:
if tomllib is None:
raise RuntimeError("Python 3.11+ or the tomli package is required to read platform-support.toml")
path = root / "platform-support.toml"
document = tomllib.loads(path.read_text(encoding="utf-8"))
platforms = document.get("target")
if not isinstance(platforms, list) or not platforms:
raise ValueError("platform-support.toml must contain at least one [[target]]")
seen: set[str] = set()
for entry in platforms:
if not isinstance(entry, dict):
raise ValueError("each [[target]] entry must be a table")
missing = REQUIRED_FIELDS - entry.keys()
if missing:
raise ValueError(f"platform entry is missing fields: {sorted(missing)}")
triple = str(entry["triple"])
if triple in seen:
raise ValueError(f"duplicate platform target: {triple}")
seen.add(triple)
if entry["target_libc"] == "musl":
missing_backend = MUSL_RUNTIME_FIELDS - entry.keys()
if missing_backend:
raise ValueError(
f"musl platform entry is missing backend fields for {triple}: "
f"{sorted(missing_backend)}"
)
if entry["runtime_backend"] not in {"cranelift", "pulley32", "pulley32be"}:
raise ValueError(f"invalid musl runtime backend for {triple}")
if entry["pointer_width"] not in {32, 64}:
raise ValueError(f"invalid musl pointer width for {triple}")
if entry["endianness"] not in {"little", "big"}:
raise ValueError(f"invalid musl endianness for {triple}")
if not isinstance(entry["core_supported"], bool) or not isinstance(
entry["runtime_supported"], bool
):
raise ValueError(f"support flags must be booleans for {triple}")
if entry["runtime_supported"] and not entry["core_supported"]:
raise ValueError(f"Full Runtime cannot be supported without Core: {triple}")
if entry["runtime_supported"] and entry["runtime_features"] != "default":
raise ValueError(f"Full Runtime must use default features: {triple}")
if entry["runtime_supported"] and not entry["release_asset"]:
raise ValueError(f"Full Runtime requires a release asset: {triple}")
if not entry["runtime_supported"] and entry["release_asset"]:
raise ValueError(
f"Core-only target cannot have a Stable release asset: {triple}"
)
if entry["target_os"] == "linux" and entry["target_libc"] not in {"gnu", "musl"}:
raise ValueError(f"Linux target has invalid libc: {triple}")
if entry["target_os"] != "linux" and entry["target_libc"] != "none":
raise ValueError(f"non-Linux target must use target_libc=none: {triple}")
published_asset = entry.get("published_asset", False)
if not isinstance(published_asset, bool):
raise ValueError(f"published_asset must be a boolean for {triple}")
if published_asset and entry["release_asset"]:
raise ValueError(
f"a published non-Stable asset must not be a Stable release asset: {triple}"
)
if published_asset and entry["runtime_supported"]:
raise ValueError(
f"published_asset is only for non-Stable release surfaces: {triple}"
)
return [dict(entry) for entry in platforms]
def targets(root: Path, *, surface: str) -> set[str]:
if surface not in {"core_supported", "runtime_supported"}:
raise ValueError(f"unknown platform surface: {surface}")
return {
str(entry["triple"])
for entry in load_platforms(root)
if bool(entry[surface])
}
def asset_name(root: Path, triple: str, version: str) -> str:
for entry in load_platforms(root):
if entry["triple"] == triple:
return f"rill-runtime-{version}-{entry['asset_suffix']}"
raise KeyError(triple)