102 lines
3.8 KiB
Python
102 lines
3.8 KiB
Python
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from .common import ENUMS_DIR, ROOT, TEMPLATES_DIR, write_if_changed
|
|
from .data_codegen import SchemaWalker
|
|
from .enum_codegen import emit_pure_enum, emit_table_enum
|
|
from .validate import validate_data_yamls
|
|
|
|
|
|
def inputs_newer_than(stamp: Path) -> bool:
|
|
if not stamp.exists():
|
|
return True
|
|
stamp_mtime = stamp.stat().st_mtime
|
|
schemas_dir = ROOT / "data" / "schemas"
|
|
inputs = [
|
|
*Path(__file__).parent.glob("*.py"),
|
|
*TEMPLATES_DIR.glob("*.j2"),
|
|
*ENUMS_DIR.glob("*.yaml"),
|
|
*schemas_dir.glob("*.schema.json"),
|
|
*(schemas_dir / "enums").glob("*.codegen.json"),
|
|
*(ROOT / "data").glob("*.yaml"),
|
|
]
|
|
return any(p.stat().st_mtime > stamp_mtime for p in inputs)
|
|
|
|
|
|
def main():
|
|
"""No-op if stamp is newer than input files and `--validate` wasn't passed."""
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("build_dir")
|
|
parser.add_argument(
|
|
"--validate",
|
|
action="store_true",
|
|
help="Also run schema validation.",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
build_root = Path(args.build_dir)
|
|
stamp = build_root / "generated" / ".codegen.stamp"
|
|
if not inputs_newer_than(stamp) and not args.validate:
|
|
return
|
|
|
|
out_dir = build_root / "generated" / "data" / "enums"
|
|
data_out_dir = build_root / "generated" / "data"
|
|
lua_out_dir = ROOT / "scripts" / "enum"
|
|
keyset_dir = ROOT / "data" / "schemas" / "enums"
|
|
for d in (out_dir, data_out_dir, lua_out_dir, keyset_dir):
|
|
d.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Enums: pure (data/enums/*.yaml) + table-derived (meta.enum: inside a data file).
|
|
enums: list[dict] = []
|
|
for p in sorted(ENUMS_DIR.glob("*.yaml")):
|
|
enums.append(emit_pure_enum(p))
|
|
for p in sorted((ROOT / "data").rglob("*.yaml")):
|
|
if p.is_relative_to(ENUMS_DIR):
|
|
continue
|
|
print(f"scanning {p.relative_to(ROOT).as_posix()} for embedded enum ...", flush=True)
|
|
result = emit_table_enum(p)
|
|
if result is not None:
|
|
enums.append(result)
|
|
|
|
for e in enums:
|
|
write_if_changed(out_dir / (e["name"] + ".h"), e["header"])
|
|
if e["lua"]:
|
|
write_if_changed(lua_out_dir / (e["lua"]["name"] + ".codegen.lua"), e["lua"]["content"])
|
|
# Keyset schema lets other schemas $ref the list of valid values for IDE completion + CI checks.
|
|
keyset = {
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": f"enums/{e['name']}.codegen.json",
|
|
"description": f"GENERATED from {e['source_name']}. Do not edit.",
|
|
"type": "string",
|
|
"enum": list(e["values"].keys()),
|
|
}
|
|
write_if_changed(keyset_dir / (e["name"] + ".codegen.json"), json.dumps(keyset, indent=2) + "\n")
|
|
|
|
schemas_dir = ROOT / "data" / "schemas"
|
|
walker = SchemaWalker()
|
|
data_names: list[str] = []
|
|
for schema_path in sorted(schemas_dir.glob("*.schema.json")):
|
|
print(f"rendering {schema_path.relative_to(ROOT).as_posix()} ...", flush=True)
|
|
result = walker.emit(schema_path)
|
|
if result is None:
|
|
continue
|
|
write_if_changed(data_out_dir / (result["name"] + ".h"), result["pod"])
|
|
write_if_changed(data_out_dir / (result["name"] + "_populator.h"), result["populator"])
|
|
data_names.append(result["name"])
|
|
|
|
manifest_lines = ["// GENERATED by tools/codegen. Do not edit.", "#pragma once", ""]
|
|
for name in sorted(data_names):
|
|
manifest_lines.append(f'#include "data/{name}.h"')
|
|
manifest_lines.append(f'#include "data/{name}_populator.h"')
|
|
write_if_changed(data_out_dir / "all.h", "\n".join(manifest_lines) + "\n")
|
|
|
|
stamp.parent.mkdir(parents=True, exist_ok=True)
|
|
stamp.touch()
|
|
|
|
if args.validate:
|
|
validate_data_yamls(schemas_dir, keyset_dir, build_root)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|