config_store.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. """Centralized config file read / parse / hash (V2-M1B).
  2. Pure refactor: `policy_json` and `walk_strategy_json` previously inlined
  3. read_text + json.loads + sha256. This module concentrates those so M1C's
  4. converter and validators share one read path. Behavior is unchanged — hashes
  5. are still taken over the RAW on-disk text (never re-serialized), so
  6. `policy_bundle_hash` stays byte-identical.
  7. """
  8. from __future__ import annotations
  9. import hashlib
  10. import json
  11. from pathlib import Path
  12. from typing import Any
  13. def read_text(path: Path) -> str:
  14. return Path(path).read_text(encoding="utf-8")
  15. # mtime+size 键缓存:同一 run 内 walk_policy 等配置会被读 3+ 次(walk_engine + 每次 recall),
  16. # 文件未变时不重复读盘/parse。调用方约定不就地修改返回的 parsed 对象(全仓配置均只读消费)。
  17. _CACHE: dict[str, tuple[tuple[int, int], Any, str]] = {}
  18. def load_json(path: Path) -> tuple[Any, str]:
  19. """Return (parsed, raw_text). raw_text is the exact on-disk text for hashing."""
  20. resolved = Path(path)
  21. stat = resolved.stat()
  22. key = str(resolved)
  23. stamp = (stat.st_mtime_ns, stat.st_size)
  24. cached = _CACHE.get(key)
  25. if cached and cached[0] == stamp:
  26. return cached[1], cached[2]
  27. raw = read_text(resolved)
  28. parsed = json.loads(raw)
  29. _CACHE[key] = (stamp, parsed, raw)
  30. return parsed, raw
  31. def sha256_text(text: str) -> str:
  32. return hashlib.sha256(text.encode("utf-8")).hexdigest()