From 9608d0b19d431a84f6a3799a2d22dfb80ba5d9df Mon Sep 17 00:00:00 2001 From: Christian-Manuel Butzke Date: Wed, 1 Jul 2026 21:28:17 +0900 Subject: [PATCH] maint: sync bundled schema from the spec repo (scripts/sync_schema.py) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'make sync-schema' + scripts/sync_schema.py to refresh the bundled src/harel/data/machine.schema.json from fruwehq/harel at the matching version tag (falling back to main, or HAREL_SPEC_DIR for a local checkout) — removing the manual copy. The schema-drift test still guards that they match. The script is dependency-free (reads the version by regex; validates JSON before overwriting). Closes #38. --- Makefile | 7 ++++- scripts/sync_schema.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 scripts/sync_schema.py diff --git a/Makefile b/Makefile index b806791..2efc5d9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test conformance lint typecheck check all +.PHONY: test conformance lint typecheck check all sync-schema # Unit tests — the implementation's own suite. Hermetic and offline. test: @@ -11,6 +11,11 @@ test: conformance: pytest conformance -q +# Refresh the bundled JSON Schema from fruwehq/harel at the matching version tag +# (or HAREL_SPEC_DIR=/path/to/harel). The schema-drift test guards that they match. +sync-schema: + python scripts/sync_schema.py + lint: ruff check . diff --git a/scripts/sync_schema.py b/scripts/sync_schema.py new file mode 100644 index 0000000..5cb6fb3 --- /dev/null +++ b/scripts/sync_schema.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +"""Refresh the bundled JSON Schema from the spec repo (fruwehq/harel). + +Writes ``src/harel/data/machine.schema.json`` from harel's +``schema/machine.schema.json`` at the tag matching this package's version (falling back +to ``main``), or from a local checkout via ``HAREL_SPEC_DIR``. This removes the manual +copy step; the schema-drift test still guards that the two stay in sync. + +Usage: ``python scripts/sync_schema.py`` (or ``make sync-schema``). +""" + +from __future__ import annotations + +import json +import os +import re +import sys +import urllib.error +import urllib.request +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +DEST = ROOT / "src" / "harel" / "data" / "machine.schema.json" +ABOUT = ROOT / "src" / "harel" / "__about__.py" + + +def _version() -> str: + m = re.search(r'__version__\s*=\s*"([^"]+)"', ABOUT.read_text(encoding="utf-8")) + if m is None: + raise SystemExit(f"could not read version from {ABOUT}") + return m.group(1) + + +def _fetch() -> str: + override = os.environ.get("HAREL_SPEC_DIR") + if override: + return (Path(override) / "schema" / "machine.schema.json").read_text(encoding="utf-8") + last: Exception | None = None + for ref in (f"v{_version()}", "main"): + url = f"https://raw.githubusercontent.com/fruwehq/harel/{ref}/schema/machine.schema.json" + try: + with urllib.request.urlopen(url, timeout=10) as resp: # noqa: S310 (fixed host) + return resp.read().decode("utf-8") + except urllib.error.URLError as exc: + last = exc + raise SystemExit(f"could not fetch schema from fruwehq/harel: {last}") + + +def main() -> int: + text = _fetch() + json.loads(text) # sanity check: valid JSON before overwriting + if DEST.read_text(encoding="utf-8") == text: + print(f"{DEST.relative_to(ROOT)} already up to date") + return 0 + DEST.write_text(text, encoding="utf-8") + print(f"updated {DEST.relative_to(ROOT)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())