world_sync/scripts/sync_models_to_app.py
2026-09-20 16:39:12 +08:00

99 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""M11b-2b 表定义镜像同步器modules/world_sync/models/ 是唯一真源,
apps/scense/pkgs/world_sync/models/ 是打包镜像(禁止手工双写)。
用法:
python modules/world_sync/scripts/sync_models_to_app.py # 同步镜像
python modules/world_sync/scripts/sync_models_to_app.py --check # 只校验,不写
行为:
1. 逐个把真源表定义 JSON 以「规范化的同一份字节」写入镜像落点(覆盖式);
2. 打印两两 sha256 比对结果;--check 模式下若不一致退出码 1。
这样 QC 抽检任一落点都拿到同一权威文本,消除「多份互相矛盾定义」。
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import sys
# 本文件位于 modules/world_sync/scripts/,向上三级 = 机构工作空间根
HERE = os.path.dirname(os.path.abspath(__file__))
WS_ROOT = os.path.abspath(os.path.join(HERE, "..", "..", ".."))
SRC_DIR = os.path.join("modules", "world_sync", "models")
DST_DIR = os.path.join("apps", "scense", "pkgs", "world_sync", "models")
# 只同步 M11b-2 交付的两张表定义(其余 world_sync*.json 属历史既有文件,不在本任务范围)
TABLES = ("pbl_runtime_event.json", "pbl_entity_state.json")
def sha256_of(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as fh:
for chunk in iter(lambda: fh.read(65536), b""):
h.update(chunk)
return h.hexdigest()
def canonical_bytes(path: str) -> bytes:
"""读入 JSON 后按统一方式序列化,保证真源与镜像字节级一致(消除缩进/空格差异)。"""
with open(path, "r", encoding="utf-8") as fh:
data = json.load(fh)
return (json.dumps(data, ensure_ascii=False, indent=2) + "\n").encode("utf-8")
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true", help="只比对不写入")
args = ap.parse_args()
src_dir = os.path.join(WS_ROOT, SRC_DIR)
dst_dir = os.path.join(WS_ROOT, DST_DIR)
if not os.path.isdir(src_dir):
print(f"FAIL: 真源目录不存在 {src_dir}", file=sys.stderr)
return 1
os.makedirs(dst_dir, exist_ok=True)
bad = 0
for name in TABLES:
src = os.path.join(src_dir, name)
dst = os.path.join(dst_dir, name)
blob = canonical_bytes(src)
if args.check:
same = os.path.isfile(dst) and open(dst, "rb").read() == blob
print(f"[check] {name}: mirror={'OK' if same else 'DRIFT'}")
if not same:
bad += 1
continue
with open(dst, "wb") as fh:
fh.write(blob)
# 写完立刻自证:真源规范化后与镜像 sha256 必须相同
s_src, s_dst = sha256_of(src), sha256_of(dst)
if s_src != s_dst:
# 真源本身不是规范化字节时,把规范化结果同时回写两处,保证两两相同
with open(src, "wb") as fh:
fh.write(blob)
s_src, s_dst = sha256_of(src), sha256_of(dst)
print(f"[sync ] {name}")
print(f" src sha256 = {s_src} ({os.path.join(SRC_DIR, name)})")
print(f" dst sha256 = {s_dst} ({os.path.join(DST_DIR, name)})")
print(f" MATCH = {s_src == s_dst}")
if s_src != s_dst:
bad += 1
if bad:
print(f"RESULT: FAIL ({bad} 个镜像不一致)")
return 1
print("RESULT: OK (真源 modules/world_sync/models -> 镜像 apps/scense/pkgs/world_sync/models 已对齐)")
return 0
if __name__ == "__main__":
raise SystemExit(main())