#!/usr/bin/env python3 """Bind a reviewed GuestOps source package to its installed image identities.""" from __future__ import annotations import argparse import hashlib import json import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def project_versions() -> tuple[str, str]: props = (ROOT / "Directory.Build.props").read_text(encoding="utf-8") match = re.search(r"([^<]+)", props) if match is None: raise ValueError("Directory.Build.props does not contain a Version element") package = json.loads((ROOT / "web" / "package.json").read_text(encoding="utf-8")) return match.group(1), str(package["version"]) def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as stream: for chunk in iter(lambda: stream.read(1024 * 1024), b""): digest.update(chunk) return digest.hexdigest() def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--artifact", required=True, type=Path) parser.add_argument("--commit", required=True) parser.add_argument("--api-image", required=True) parser.add_argument("--api-id", required=True) parser.add_argument("--worker-image", required=True) parser.add_argument("--worker-id", required=True) parser.add_argument("--output", required=True, type=Path) args = parser.parse_args() commit = args.commit.lower() if re.fullmatch(r"[0-9a-f]{40}", commit) is None: parser.error("--commit must be a full 40-character Git SHA") if not args.artifact.is_file(): parser.error("--artifact must name an existing file") dotnet_version, web_version = project_versions() if dotnet_version != web_version: parser.error( f"release versions differ: .NET={dotnet_version}, web={web_version}" ) record = { "artifact": { "name": args.artifact.name, "sha256": sha256(args.artifact), "size": args.artifact.stat().st_size, }, "commit": commit, "images": { "api": {"id": args.api_id, "reference": args.api_image}, "worker": {"id": args.worker_id, "reference": args.worker_image}, }, "schemaVersion": 1, "version": dotnet_version, } args.output.write_text( json.dumps(record, indent=2, sort_keys=True) + "\n", encoding="utf-8" ) if __name__ == "__main__": main()