CI lint's format-check on added files (base-range dependent) failed on files that predate the format gate's effective coverage. Formatting-only: no semantic changes; integration tests 15/15, ruff check clean, ratchet PASS, daemon convergence re-verified.
84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""install_wr_daemon.py — REAL_ASYNC_BRIDGE §6: daemon governance.
|
|
|
|
Canonical source lives IN THIS REPO at bridge/daemon/. The active install
|
|
is ~/.local/share/mimo-wait-resume/. This script is the ONLY supported
|
|
way to move code between them:
|
|
|
|
- copy canonical source → install dir (atomic, per file)
|
|
- verify sha256 convergence (fail loud on divergence)
|
|
- optionally restart the daemon via scripts/start_wr_daemon.py
|
|
|
|
Never hand-edit the installed copy: edit the repo source, install, restart.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
CANONICAL = REPO / "bridge" / "daemon"
|
|
INSTALL = Path.home() / ".local/share/mimo-wait-resume"
|
|
FILES = ("daemon.py", "waitstore.py", "verify.py", "completion_file.py")
|
|
|
|
|
|
def sha256(p: Path) -> str:
|
|
return hashlib.sha256(p.read_bytes()).hexdigest()
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser(description=__doc__)
|
|
ap.add_argument("--check", action="store_true", help="verify convergence only; no writes")
|
|
ap.add_argument("--restart", action="store_true", help="restart the daemon after install")
|
|
args = ap.parse_args()
|
|
|
|
if not CANONICAL.is_dir():
|
|
print(f"canonical source missing: {CANONICAL}")
|
|
return 1
|
|
INSTALL.mkdir(parents=True, exist_ok=True)
|
|
|
|
diverged = []
|
|
for name in FILES:
|
|
src, dst = CANONICAL / name, INSTALL / name
|
|
if args.check:
|
|
if not dst.is_file() or sha256(src) != sha256(dst):
|
|
diverged.append(name)
|
|
continue
|
|
if not dst.is_file() or sha256(src) != sha256(dst):
|
|
tmp = dst.with_suffix(f".tmp.{name}")
|
|
shutil.copy2(src, tmp)
|
|
tmp.replace(dst) # atomic
|
|
print(f"installed: {name} {sha256(src)[:12]}")
|
|
else:
|
|
print(f"unchanged: {name} {sha256(src)[:12]}")
|
|
|
|
if args.check:
|
|
if diverged:
|
|
print(f"DIVERGED: {', '.join(diverged)} — run install_wr_daemon.py")
|
|
return 1
|
|
print("CONVERGED: installed copy == canonical repo source")
|
|
return 0
|
|
|
|
# post-install convergence proof
|
|
bad = [n for n in FILES if sha256(CANONICAL / n) != sha256(INSTALL / n)]
|
|
if bad:
|
|
print(f"INSTALL FAILED convergence: {bad}")
|
|
return 1
|
|
print("CONVERGED: installed copy == canonical repo source")
|
|
|
|
if args.restart:
|
|
rc = subprocess.call([sys.executable, str(REPO / "scripts" / "start_wr_daemon.py")])
|
|
if rc != 0:
|
|
print("restart failed")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|