"""stand-schreiben.py — den Software-Stand einer Instanz festhalten (seit 24.09.2026). deploy.sh (KI-Box) und homelab/ausrollen.sh (Container des Homelab-Teils) rufen es nach einem erfolgreichen Umschalten auf. Es liest drei Zeilen von stdin, genau wie `git log -1 --format='%h%n%cI%n%s'` sie liefert: Commit kurz, Commit-Datum (ISO), Betreff. Dazu kommt der Zeitpunkt des Deploys, und alles landet als JSON in der angegebenen Datei (atomar). Die Oberfläche zeigt daraus „Software-Stand“ (backend/services/software_stand.py). Nur Standardbibliothek: Es läuft mit dem python3 des Systems, auch im Container ohne git. Nutzung: git log -1 --format='%h%n%cI%n%s' HEAD | python3 deploy/stand-schreiben.py /srv/models/mc2-stand.json """ import json import os import sys import tempfile from datetime import datetime from pathlib import Path def stand_aus(zeilen: list[str], jetzt: datetime) -> dict: """Die drei git-Zeilen und der Zeitpunkt des Deploys als Stand. Leere Felder werden None.""" commit, datum, betreff = ([z.strip() for z in zeilen] + ["", "", ""])[:3] return {"commit": commit or None, "betreff": betreff or None, "commit_datum": datum or None, "deploy_zeit": jetzt.isoformat(timespec="seconds")} def schreiben(ziel: Path, stand: dict) -> None: """Atomar: erst eine Nachbardatei, dann umbenennen — ein Leser sieht nie eine halbe Datei.""" ziel.parent.mkdir(parents=True, exist_ok=True) fd, tmp = tempfile.mkstemp(prefix=".mc2-stand-", suffix=".tmp", dir=ziel.parent) try: with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(stand, f, ensure_ascii=False, indent=1) os.chmod(tmp, 0o644) os.replace(tmp, ziel) except BaseException: Path(tmp).unlink(missing_ok=True) raise def main(argv: list[str]) -> int: if len(argv) != 2: print("Nutzung: git log -1 --format='%h%n%cI%n%s' | python3 stand-schreiben.py ", file=sys.stderr) return 2 # Bytes lesen und selbst als UTF-8 deuten: Im Container ist die Locale oft C/POSIX. zeilen = sys.stdin.buffer.read().decode("utf-8", "replace").splitlines() stand = stand_aus(zeilen, datetime.now().astimezone()) if not stand["commit"]: print("Kein Commit auf stdin — Stand nicht geschrieben.", file=sys.stderr) return 1 schreiben(Path(argv[1]), stand) print(f"Stand {stand['commit']} festgehalten in {argv[1]}.") return 0 if __name__ == "__main__": sys.exit(main(sys.argv))