#!/usr/bin/env python3 """Restore the exact upstream dependency revisions for the vendored plugins.""" import argparse import json from pathlib import Path import subprocess ROOT = Path(__file__).resolve().parents[1] def git(directory, *args, capture=False): return subprocess.check_output(["git", "-C", str(directory), *args], text=True).strip() if capture else subprocess.check_call(["git", "-C", str(directory), *args]) def restore(game, check_only): plugin = ROOT / game / "plugins" / f"tws-{game}-gsc-utils" lock = json.loads((plugin / "upstream.json").read_text()) for dependency in lock["dependencies"]: target = plugin / dependency["path"] if not target.resolve().is_relative_to(plugin.resolve()): raise RuntimeError(f"Dependency path leaves the plugin: {target}") if not (target / ".git").exists(): if check_only: raise RuntimeError(f"Missing dependency: {target}") if target.exists() and any(target.iterdir()): raise RuntimeError(f"Refusing to replace nonempty directory: {target}") target.mkdir(parents=True, exist_ok=True) git(target, "init", "--quiet") git(target, "remote", "add", "origin", dependency["url"]) if git(target, "remote", "get-url", "origin", capture=True) != dependency["url"]: raise RuntimeError(f"Unexpected dependency remote: {target}") if git(target, "status", "--porcelain", capture=True): raise RuntimeError(f"Dependency has local changes: {target}") current = subprocess.run(["git", "-C", str(target), "rev-parse", "--verify", "HEAD"], capture_output=True, text=True) if current.stdout.strip() != dependency["commit"]: if check_only: raise RuntimeError(f"Wrong dependency revision: {target}") git(target, "fetch", "--depth", "1", "origin", dependency["commit"]) git(target, "checkout", "--quiet", "--detach", dependency["commit"]) print(f"OK {game}/{dependency['path']} {dependency['commit']}") if __name__ == "__main__": parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("game", choices=["t5", "t6", "all"]) parser.add_argument("--check", action="store_true", help="Verify existing checkouts without fetching or changing them") args = parser.parse_args() for game in ("t5", "t6") if args.game == "all" else (args.game,): restore(game, args.check)