141 lines
5.7 KiB
Python
141 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Audit the fixed ownership and feature boundary for milestone 06."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import re
|
|
import tomllib
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
OWNED_CRATES = (
|
|
ROOT / "crates" / "libremetaverse-imaging",
|
|
ROOT / "crates" / "libremetaverse-imaging-skia",
|
|
ROOT / "crates" / "libremetaverse-prim-mesher",
|
|
)
|
|
OWNED_FIXTURES = {
|
|
"LibreMetaverse.Tests/ManagedImageTests.cs": 3,
|
|
"LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs": 18,
|
|
"LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs": 27,
|
|
}
|
|
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")
|
|
|
|
|
|
def load_toml(path: Path) -> dict:
|
|
with path.open("rb") as stream:
|
|
return tomllib.load(stream)
|
|
|
|
|
|
def check_owned_rust() -> None:
|
|
offenders: list[str] = []
|
|
for crate in OWNED_CRATES:
|
|
for path in sorted((crate / "src").rglob("*.rs")):
|
|
if STUB_RE.search(path.read_text()):
|
|
offenders.append(path.relative_to(ROOT).as_posix())
|
|
if offenders:
|
|
raise SystemExit("milestone-owned Rust stubs remain: " + ", ".join(offenders))
|
|
|
|
|
|
def check_features() -> None:
|
|
imaging = load_toml(OWNED_CRATES[0] / "Cargo.toml")
|
|
if imaging["features"].get("default") != ["rust-j2k"]:
|
|
raise SystemExit("imaging defaults must select only pure-Rust JPEG 2000")
|
|
if imaging["features"].get("jpeg2000") != ["dep:libremetaverse-openjpeg"]:
|
|
raise SystemExit("JPEG 2000 must stay isolated behind its optional feature")
|
|
if imaging["features"].get("rust-j2k") != ["dep:j2k"]:
|
|
raise SystemExit("pure-Rust JPEG 2000 must stay isolated behind rust-j2k")
|
|
if not imaging["dependencies"]["libremetaverse-openjpeg"].get("optional"):
|
|
raise SystemExit("the OpenJPEG adapter dependency must stay optional")
|
|
|
|
skia = load_toml(OWNED_CRATES[1] / "Cargo.toml")
|
|
if skia["features"].get("default") != ["rust-skia"]:
|
|
raise SystemExit("raster adapter defaults must select only pure-Rust codecs")
|
|
if skia["features"].get("skia") != ["dep:skia-safe"]:
|
|
raise SystemExit("Skia must stay isolated behind its optional feature")
|
|
targets = skia.get("target", {}).values()
|
|
skia_dependencies = [
|
|
target.get("dependencies", {}).get("skia-safe") for target in targets
|
|
]
|
|
if not skia_dependencies or any(
|
|
dependency is None or not dependency.get("optional")
|
|
for dependency in skia_dependencies
|
|
):
|
|
raise SystemExit("every platform-specific Skia dependency must stay optional")
|
|
|
|
workspace = load_toml(ROOT / "Cargo.toml")["workspace"]
|
|
adapter = "crates/libremetaverse-openjpeg"
|
|
if adapter not in workspace.get("members", []):
|
|
raise SystemExit("the native OpenJPEG adapter must remain explicitly packageable")
|
|
if adapter in workspace.get("default-members", workspace.get("members", [])):
|
|
raise SystemExit("the native OpenJPEG adapter must stay outside default workspace builds")
|
|
|
|
|
|
def check_parity() -> None:
|
|
catalog = json.loads((ROOT / "tests" / "upstream-tests.json").read_text())
|
|
grouped: dict[str, list[dict]] = {source: [] for source in OWNED_FIXTURES}
|
|
for case in catalog["tests"]:
|
|
if case["source"] in grouped:
|
|
grouped[case["source"]].append(case)
|
|
for source, expected in OWNED_FIXTURES.items():
|
|
cases = grouped[source]
|
|
if len(cases) != expected:
|
|
raise SystemExit(f"{source}: expected {expected} reviewed cases, found {len(cases)}")
|
|
incomplete = [
|
|
case["id"]
|
|
for case in cases
|
|
if case["status"] != "translated"
|
|
or case.get("semantic_review") != "reviewed"
|
|
or not (ROOT / case["rust_file"]).is_file()
|
|
]
|
|
if incomplete:
|
|
raise SystemExit(f"{source}: incomplete parity cases: " + ", ".join(incomplete))
|
|
|
|
|
|
def check_benchmarks_and_ci() -> None:
|
|
expected_benches = {
|
|
OWNED_CRATES[0]: "image_pipeline",
|
|
OWNED_CRATES[2]: "meshing",
|
|
}
|
|
for crate, name in expected_benches.items():
|
|
manifest = load_toml(crate / "Cargo.toml")
|
|
benches = {entry["name"]: entry for entry in manifest.get("bench", [])}
|
|
if benches.get(name, {}).get("harness") is not False:
|
|
raise SystemExit(f"missing harness-free {name} benchmark declaration")
|
|
if not (crate / "benches" / f"{name}.rs").is_file():
|
|
raise SystemExit(f"missing {name} benchmark source")
|
|
|
|
workflows = {"consolidated": ROOT / ".gitea" / "workflows" / "ci.yml"}
|
|
for name, path in workflows.items():
|
|
if not path.is_file():
|
|
raise SystemExit(f"missing {name} native-feature workflow")
|
|
runners = re.findall(r"(?m)^\s*runs-on:\s*([^\s#]+)", path.read_text().lower())
|
|
if not runners:
|
|
raise SystemExit(f"{name} workflow has no runner")
|
|
unsupported = sorted({runner for runner in runners if runner != "ubuntu-latest"})
|
|
if unsupported:
|
|
raise SystemExit(
|
|
f"{name} workflow must use only ubuntu-latest, found: "
|
|
+ ", ".join(unsupported)
|
|
)
|
|
text = path.read_text()
|
|
for marker in ("required-gate", "METACRATE_SKIA_ARCHIVE", "OPENJPEG_PREFIX"):
|
|
if marker not in text:
|
|
raise SystemExit(f"{name} workflow is missing {marker}")
|
|
|
|
|
|
def main() -> None:
|
|
check_owned_rust()
|
|
check_features()
|
|
check_parity()
|
|
check_benchmarks_and_ci()
|
|
print(
|
|
"milestone 06 audit: owned Rust has no stubs; 48 reviewed parity cases, "
|
|
"optional native features, benchmarks, and Linux-only Gitea workflows are complete"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|