world_sync/scripts/sync_code_to_app.py
2026-09-21 13:25:24 +08:00

98 lines
3.2 KiB
Python
Raw 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-3 代码镜像同步器:modules/world_sync/ 是唯一真源,
apps/scense/pkgs/world_sync/ 是打包镜像(宿主 build.sh 从应用仓库安装,禁止手工双写)。
与 sync_models_to_app.py(只管 models/)互补,本脚本同步 **Python 包与测试**:
- world_sync/*.py(包源码,含 pbl_runtime_broadcast.py)
- tests/*.py(含 test_m11b3_post_commit_broadcast.py)
- skill/SKILL.md、README.md
用法:
python modules/world_sync/scripts/sync_code_to_app.py # 同步
python modules/world_sync/scripts/sync_code_to_app.py --check # 只校验 sha256
行为:逐文件以同一份字节覆盖镜像落点,打印两两 sha256 比对;--check 不一致退出码 1。
"""
from __future__ import annotations
import argparse
import hashlib
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
WS_ROOT = os.path.abspath(os.path.join(HERE, "..", "..", ".."))
SRC_ROOT = os.path.join("modules", "world_sync")
DST_ROOT = os.path.join("apps", "scense", "pkgs", "world_sync")
#: 需要镜像的相对路径(真源 = modules/world_sync/)
MIRROR_SUBDIRS = ("world_sync", "tests")
MIRROR_FILES = ("README.md", os.path.join("skill", "SKILL.md"))
#: 不同步的产物/缓存
SKIP_SUFFIX = ("__pycache__", ".pyc", ".egg-info", ".pytest_cache")
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 collect() -> list:
rels = []
for sub in MIRROR_SUBDIRS:
base = os.path.join(SRC_ROOT, sub)
if not os.path.isdir(base):
continue
for name in sorted(os.listdir(base)):
if any(s in name for s in SKIP_SUFFIX):
continue
if not name.endswith(".py"):
continue
rels.append(os.path.join(sub, name))
for rel in MIRROR_FILES:
if os.path.isfile(os.path.join(SRC_ROOT, rel)):
rels.append(rel)
return rels
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true", help="只校验,不写入")
args = ap.parse_args()
bad = 0
for rel in collect():
src = os.path.join(WS_ROOT, SRC_ROOT, rel)
dst = os.path.join(WS_ROOT, DST_ROOT, rel)
src_sha = sha256_of(src)
same = os.path.isfile(dst) and sha256_of(dst) == src_sha
if args.check:
print("%-58s %s" % (rel, "OK" if same else "DRIFT"))
if not same:
bad += 1
continue
os.makedirs(os.path.dirname(dst), exist_ok=True)
with open(src, "rb") as fh:
data = fh.read()
with open(dst, "wb") as fh:
fh.write(data)
ok = sha256_of(dst) == src_sha
print("%-58s %s sha256=%s" % (rel, "SYNCED" if ok else "FAIL", src_sha[:12]))
if not ok:
bad += 1
if bad:
print("RESULT: FAIL (%d 项不一致)" % bad)
return 1
print("RESULT: PASS (镜像与真源逐文件 sha256 一致)")
return 0
if __name__ == "__main__":
sys.exit(main())