139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Red Queen — C5 CLI (C5A + C5B): kontrollierte Inspektion & Dry-Run.
|
|
|
|
KEIN produktiver Poll-Daemon. KEINE daemon/start-forever-Funktion.
|
|
Nur explizite, begrenzte Befehle:
|
|
* poll-once — ein kontrollierter Poll-Zyklus (read-only)
|
|
* show-pending — ausstehende Commits anzeigen
|
|
* show-commit — Details eines Commits anzeigen
|
|
* dry-run-diff — Diff eines Commits anzeigen (read-only)
|
|
* health — Health-Contract anzeigen
|
|
* no-write-check — No-Downstream-Write-Guarantee pruefen
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from rq_c5a import C5AStore
|
|
from rq_c5b import (
|
|
C5BPoller,
|
|
GitReader,
|
|
assert_no_downstream_write,
|
|
DEFAULT_POLL_INTERVAL_SECONDS,
|
|
ENV_POLL_INTERVAL,
|
|
)
|
|
|
|
|
|
def _store(db_path: str) -> C5AStore:
|
|
return C5AStore(db_path)
|
|
|
|
|
|
def _poller(store: C5AStore, repo_path: str, interval: Optional[int]) -> C5BPoller:
|
|
return C5BPoller(store, repo_path, poll_interval_seconds=interval)
|
|
|
|
|
|
def cmd_poll_once(args: argparse.Namespace) -> int:
|
|
store = _store(args.db)
|
|
poller = _poller(store, args.repo, args.interval)
|
|
result = poller.poll_once()
|
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
store.close()
|
|
return 0
|
|
|
|
|
|
def cmd_show_pending(args: argparse.Namespace) -> int:
|
|
store = _store(args.db)
|
|
pending = store.list_commits()
|
|
print(json.dumps(pending, ensure_ascii=False, indent=2))
|
|
store.close()
|
|
return 0
|
|
|
|
|
|
def cmd_show_commit(args: argparse.Namespace) -> int:
|
|
store = _store(args.db)
|
|
commit = store.get_commit(args.sha)
|
|
if commit is None:
|
|
print(f"Commit nicht gefunden: {args.sha}")
|
|
store.close()
|
|
return 1
|
|
print(json.dumps(commit, ensure_ascii=False, indent=2))
|
|
objs = store.list_object_changes(args.sha)
|
|
if objs:
|
|
print("--- Object Changes ---")
|
|
print(json.dumps(objs, ensure_ascii=False, indent=2))
|
|
store.close()
|
|
return 0
|
|
|
|
|
|
def cmd_dry_run_diff(args: argparse.Namespace) -> int:
|
|
reader = GitReader(args.repo)
|
|
changes = reader.diff_name_status(args.sha)
|
|
print(json.dumps(changes, ensure_ascii=False, indent=2))
|
|
return 0
|
|
|
|
|
|
def cmd_health(args: argparse.Namespace) -> int:
|
|
store = _store(args.db)
|
|
print(json.dumps(store.health(), ensure_ascii=False, indent=2))
|
|
store.close()
|
|
return 0
|
|
|
|
|
|
def cmd_no_write_check(args: argparse.Namespace) -> int:
|
|
result = assert_no_downstream_write()
|
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
return 0 if result["no_downstream_write"] else 1
|
|
|
|
|
|
def main(argv: Optional[List[str]] = None) -> int:
|
|
parser = argparse.ArgumentParser(
|
|
prog="rq_c5_cli",
|
|
description="Red Queen C5 CLI (C5A + C5B) — kontrollierte Inspektion & Dry-Run",
|
|
)
|
|
parser.add_argument(
|
|
"--db", default=os.environ.get("C5A_DB", "c5a.db"),
|
|
help="Pfad zur C5A-SQLite-DB (Env C5A_DB, Default c5a.db)",
|
|
)
|
|
parser.add_argument(
|
|
"--repo", default=os.environ.get("C5_REPO", "."),
|
|
help="Pfad zum Forgejo-Clone (Env C5_REPO, Default .)",
|
|
)
|
|
parser.add_argument(
|
|
"--interval", type=int, default=None,
|
|
help=f"Poll-Intervall in Sekunden (Env {ENV_POLL_INTERVAL}, Default {DEFAULT_POLL_INTERVAL_SECONDS})",
|
|
)
|
|
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
|
|
p = sub.add_parser("poll-once", help="Ein kontrollierter Poll-Zyklus (read-only)")
|
|
p.set_defaults(func=cmd_poll_once)
|
|
|
|
p = sub.add_parser("show-pending", help="Ausstehende Commits anzeigen")
|
|
p.set_defaults(func=cmd_show_pending)
|
|
|
|
p = sub.add_parser("show-commit", help="Details eines Commits anzeigen")
|
|
p.add_argument("sha", help="Commit-SHA")
|
|
p.set_defaults(func=cmd_show_commit)
|
|
|
|
p = sub.add_parser("dry-run-diff", help="Diff eines Commits anzeigen (read-only)")
|
|
p.add_argument("sha", help="Commit-SHA")
|
|
p.set_defaults(func=cmd_dry_run_diff)
|
|
|
|
p = sub.add_parser("health", help="Health-Contract anzeigen")
|
|
p.set_defaults(func=cmd_health)
|
|
|
|
p = sub.add_parser("no-write-check", help="No-Downstream-Write-Guarantee pruefen")
|
|
p.set_defaults(func=cmd_no_write_check)
|
|
|
|
args = parser.parse_args(argv)
|
|
return args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|