"""Run Linux wheel release checks in the matching manylinux Docker image.""" from __future__ import annotations import json import subprocess from pathlib import Path from packaging.utils import parse_wheel_filename PLATFORM_LABELS = { "win_amd64": "Windows x64", "x86_64": "Linux x86_64", "aarch64": "Linux ARM64", } def wheel_target(wheel: Path) -> tuple[str, str]: """Return the CPython tag and supported OS/architecture; reject ambiguity.""" _, _, _, tags = parse_wheel_filename(wheel.name) identities = set() for tag in tags: if ( tag.interpreter not in {"cp310", "cp311", "cp312"} or tag.abi != tag.interpreter ): raise RuntimeError(f"Unsupported Python ABI in {wheel.name}") if tag.platform == "win_amd64": target = "win_amd64" elif tag.platform.startswith("manylinux") and tag.platform.endswith("_aarch64"): target = "aarch64" elif tag.platform.startswith("manylinux") and tag.platform.endswith("_x86_64"): target = "x86_64" else: raise RuntimeError(f"Unsupported release platform in {wheel.name}") identities.add((tag.interpreter, target)) if len(identities) != 1: raise RuntimeError(f"Ambiguous release platform in {wheel.name}") return identities.pop() _CONTAINER_CHECK = """ import json, sys from pathlib import Path sys.path.insert(0, '/src/build') from common.verify.wheel import verify_wheel record = verify_wheel(Path(sys.argv[1]), video=Path(sys.argv[2]), config_name=sys.argv[3], frames=int(sys.argv[4]), check_assets=sys.argv[5] == '1') print('ORISYS_RUNTIME_RESULT=' + json.dumps(record)) """ def verify_manylinux_wheel( wheel: Path, *, repo_root: Path, video: Path, config_name: str, frames: int, check_assets: bool = True, ) -> dict: tag, architecture = wheel_target(wheel) if architecture == "win_amd64": raise RuntimeError("Windows wheels must be verified with a Windows interpreter") platform = "linux/arm64" if architecture == "aarch64" else "linux/amd64" image = ( "orisys-manylinux-aarch64" if architecture == "aarch64" else "orisys-manylinux" ) abi = f"{tag}-{tag}" argv = [ "docker", "run", "--rm", "--pull=never", "--platform", platform, "-v", f"{repo_root.resolve()}:/src:ro", "-v", f"{wheel.resolve().parent}:/wheels:ro", "-v", f"{video.resolve().parent}:/video:ro", "-e", "PIP_NO_INDEX=1", "-e", f"PIP_FIND_LINKS=/opt/orisys-wheelhouse/{abi}", "--entrypoint", f"/opt/python/{abi}/bin/python", image, "-c", _CONTAINER_CHECK, f"/wheels/{wheel.name}", f"/video/{video.name}", config_name, str(frames), "1" if check_assets else "0", ] print(f" verifying {wheel.name} in {image} ({platform}) ...", flush=True) result = subprocess.run(argv, capture_output=True, text=True, check=False) if result.returncode: raise RuntimeError( f"{image} verification failed:\n{result.stdout}\n{result.stderr}" ) marker = "ORISYS_RUNTIME_RESULT=" records = [ line[len(marker) :] for line in result.stdout.splitlines() if line.startswith(marker) ] if len(records) != 1: raise RuntimeError( f"{image} returned no unique verification record:\n{result.stdout}" ) record = json.loads(records[0]) if record.get("wheel") != wheel.name or record.get("frames") != frames: raise RuntimeError(f"Unexpected verification record for {wheel.name}: {record}") return record