shadow / authoring /version_store.py
garywelz's picture
Add reader, versioning, and export tools
b15141d
from __future__ import annotations
from dataclasses import dataclass
import json
from pathlib import Path
from typing import Optional
@dataclass(frozen=True)
class VersionInfo:
name: str
path: Path
created_at: str | None = None
based_on: str | None = None
def _is_writable_dir(p: Path) -> bool:
try:
p.mkdir(parents=True, exist_ok=True)
test = p / ".write_test"
test.write_text("ok", encoding="utf-8")
test.unlink(missing_ok=True)
return True
except Exception:
return False
def get_versions_root() -> tuple[Path, bool]:
"""
Returns (root_dir, is_persistent_like).
Prefers /data when available (HF persistent storage), otherwise uses repo-local storage.
"""
data_root = Path("/data/shadow_versions")
if _is_writable_dir(data_root):
return data_root, True
local_root = Path("shadow_versions")
_is_writable_dir(local_root) # best-effort
return local_root, False
def list_versions() -> list[VersionInfo]:
root, _ = get_versions_root()
infos: list[VersionInfo] = []
for p in sorted(root.glob("*.json")):
name = p.stem
created_at: Optional[str] = None
based_on: Optional[str] = None
try:
data = json.loads(p.read_text(encoding="utf-8"))
meta = data.get("meta", {}) if isinstance(data, dict) else {}
created_at = meta.get("created_at")
based_on = meta.get("based_on")
except Exception:
pass
infos.append(VersionInfo(name=name, path=p, created_at=created_at, based_on=based_on))
return infos
def load_version(name: str) -> dict:
root, _ = get_versions_root()
path = root / f"{name}.json"
return json.loads(path.read_text(encoding="utf-8"))
def save_version(name: str, payload: dict) -> Path:
root, _ = get_versions_root()
path = root / f"{name}.json"
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
return path