from __future__ import annotations import hashlib, json, subprocess from pathlib import Path def sha256_text(s: str) -> str: return hashlib.sha256(s.encode()).hexdigest() def stable_json(obj) -> str: return json.dumps(obj, sort_keys=True, default=str, separators=(",", ":")) def git_revision(path: str | Path | None = None) -> str: try: out = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=path, capture_output=True, text=True, timeout=5) dirty = subprocess.run(["git", "status", "--porcelain"], cwd=path, capture_output=True, text=True, timeout=5) rev = out.stdout.strip() or "unknown" return rev + ("-dirty" if dirty.stdout.strip() else "") except Exception: return "unknown"