feat(content-build): CLI build + --check staleness gate

This commit is contained in:
2026-07-11 18:27:48 -05:00
parent 973af41a6e
commit 11c4d6dcd7
2 changed files with 126 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
"""CLI entry: `python -m content_build [--check]`. Orchestrates
parse -> model -> resolve -> emit. --check builds in memory and diffs against
the on-disk committed JSON (stale-or-invalid -> exit 1)."""
import argparse
import sys
from pathlib import Path
from .emit import build_trees, check_secrecy, dump_json, write_trees
from .errors import BuildError
from .model import entry_from_raw
from .parse import parse_bible
from .resolve import resolve
def _load_world(lore_dir: Path):
raws = []
for md in sorted(Path(lore_dir).glob("*.md")):
raws.extend(parse_bible(md))
return resolve([entry_from_raw(r) for r in raws])
def build(lore_dir, world_dir, server_dir) -> None:
world = _load_world(lore_dir)
client_files, server_files = build_trees(world)
check_secrecy(client_files, world)
write_trees(client_files, server_files, world_dir, server_dir)
def _diff(path: Path, obj) -> list[str]:
want = dump_json(obj)
if not path.exists():
return [f"missing {path}"]
if path.read_text() != want:
return [f"differs {path}"]
return []
def check(lore_dir, world_dir, server_dir) -> int:
world = _load_world(lore_dir)
client_files, server_files = build_trees(world)
check_secrecy(client_files, world)
stale: list[str] = []
for relpath, obj in client_files.items():
stale += _diff(Path(world_dir) / relpath, obj)
for relpath, obj in server_files.items():
stale += _diff(Path(server_dir) / relpath, obj)
for s in stale:
print("STALE:", s, file=sys.stderr)
return 1 if stale else 0
def main(argv=None) -> int:
ap = argparse.ArgumentParser(prog="content_build")
ap.add_argument("--check", action="store_true",
help="verify committed JSON is fresh + valid; no writes")
ap.add_argument("--lore", default="content/lore")
ap.add_argument("--world", default="content/world")
ap.add_argument("--server", default="content/server")
args = ap.parse_args(argv)
try:
if args.check:
return check(args.lore, args.world, args.server)
build(args.lore, args.world, args.server)
return 0
except BuildError as e:
print("BUILD FAILED:", e, file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())