110 lines
3.3 KiB
Python
110 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Run the complete verifier suite against the versions pinned in requirements.txt.
|
|
|
|
This is the repository's Tier 2 baseline gate. It refuses to run individual
|
|
verifiers when the active Python environment does not contain the exact pinned
|
|
RNS and LXMF versions, then runs every tools/verify_*.py script in isolation.
|
|
|
|
Exit code 0 means every verifier passed. Exit code 1 means the environment
|
|
does not match the pins or at least one verifier failed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.metadata
|
|
import pathlib
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
TOOLS_DIR = pathlib.Path(__file__).resolve().parent
|
|
REQUIREMENTS_PATH = TOOLS_DIR / "requirements.txt"
|
|
PIN_PATTERN = re.compile(r"^(rns|lxmf)==([A-Za-z0-9_.+-]+)$", re.IGNORECASE)
|
|
|
|
|
|
def load_pins() -> dict[str, str]:
|
|
pins: dict[str, str] = {}
|
|
for raw_line in REQUIREMENTS_PATH.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
match = PIN_PATTERN.match(line)
|
|
if match:
|
|
pins[match.group(1).lower()] = match.group(2)
|
|
|
|
missing = {"rns", "lxmf"} - pins.keys()
|
|
if missing:
|
|
names = ", ".join(sorted(missing))
|
|
raise RuntimeError(f"missing required pins in {REQUIREMENTS_PATH}: {names}")
|
|
return pins
|
|
|
|
|
|
def installed_versions(names: list[str]) -> dict[str, str]:
|
|
versions: dict[str, str] = {}
|
|
for name in names:
|
|
try:
|
|
versions[name] = importlib.metadata.version(name)
|
|
except importlib.metadata.PackageNotFoundError:
|
|
versions[name] = "<not installed>"
|
|
return versions
|
|
|
|
|
|
def verifier_paths() -> list[pathlib.Path]:
|
|
return sorted(
|
|
path
|
|
for path in TOOLS_DIR.glob("verify_*.py")
|
|
if path.name != pathlib.Path(__file__).name
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
try:
|
|
pins = load_pins()
|
|
except (OSError, RuntimeError) as exc:
|
|
print(f"FAIL baseline configuration: {exc}")
|
|
return 1
|
|
|
|
installed = installed_versions(sorted(pins))
|
|
mismatches = [
|
|
f"{name}: installed {installed[name]}, pinned {pins[name]}"
|
|
for name in sorted(pins)
|
|
if installed[name] != pins[name]
|
|
]
|
|
|
|
print(f"Python: {sys.executable}")
|
|
print("Pinned environment: " + ", ".join(
|
|
f"{name}=={pins[name]}" for name in sorted(pins)
|
|
))
|
|
|
|
if mismatches:
|
|
print("FAIL environment does not match tools/requirements.txt:")
|
|
for mismatch in mismatches:
|
|
print(f" - {mismatch}")
|
|
return 1
|
|
|
|
verifiers = verifier_paths()
|
|
if not verifiers:
|
|
print("FAIL no verifier scripts found")
|
|
return 1
|
|
|
|
failures: list[tuple[str, int]] = []
|
|
for index, path in enumerate(verifiers, start=1):
|
|
print(f"\n=== [{index}/{len(verifiers)}] {path.name} ===", flush=True)
|
|
result = subprocess.run([sys.executable, str(path)], cwd=TOOLS_DIR.parent)
|
|
if result.returncode != 0:
|
|
failures.append((path.name, result.returncode))
|
|
|
|
print("\n=== Verification summary ===")
|
|
print(f"Passed: {len(verifiers) - len(failures)}")
|
|
print(f"Failed: {len(failures)}")
|
|
if failures:
|
|
for name, returncode in failures:
|
|
print(f" - {name}: exit {returncode}")
|
|
return 1
|
|
|
|
print("ALL VERIFIERS PASS")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|