#!/usr/bin/env python3 """Run Docker boot-time config migrations safely.""" from __future__ import annotations import shutil import sys from datetime import datetime, timezone from pathlib import Path from typing import Iterable from hermes_cli.config import ( check_config_version, get_config_path, get_env_path, migrate_config, ) from utils import env_var_enabled def _backup_path(path: Path, stamp: str) -> Path: base = path.with_name(f"{path.name}.bak-{stamp}") if not base.exists(): return base for index in range(1, 1000): candidate = path.with_name(f"{path.name}.bak-{stamp}.{index}") if not candidate.exists(): return candidate raise RuntimeError(f"could not choose a backup path for {path}") def _backup_existing(paths: Iterable[Path]) -> list[Path]: stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") backups: list[Path] = [] for path in paths: if not path.is_file(): continue dest = _backup_path(path, stamp) shutil.copy2(path, dest) backups.append(dest) return backups def main() -> int: if env_var_enabled("HERMES_SKIP_CONFIG_MIGRATION"): print("[config-migrate] HERMES_SKIP_CONFIG_MIGRATION is set; skipping config migration") return 0 current_ver, latest_ver = check_config_version() if current_ver >= latest_ver: return 0 backups = _backup_existing((get_config_path(), get_env_path())) backup_text = ", ".join(str(path) for path in backups) if backups else "none" print( f"[config-migrate] Migrating config schema {current_ver} -> {latest_ver}; " f"backups: {backup_text}" ) migrate_config(interactive=False, quiet=False) return 0 if __name__ == "__main__": try: raise SystemExit(main()) except Exception as exc: print(f"[config-migrate] ERROR: {exc}", file=sys.stderr) raise SystemExit(1)