- 维护索引按 git 视角枚举(已跟踪 + 未跟踪且未忽略):被 .gitignore 忽略的运行痕迹与 过程性检查报告不再进入目录派生或影响索引门禁;非 git 场景退回原磁盘枚举 - conftest 验证闸门在 `验证锁 --执行` 启动的会话内不再取共享锁,修复 `make 索引生成` 在独占锁内收集用例时的自锁(原 180s 超时失败 → 现 6s 通过) - .gitignore 登记过程性检查报告与工具会话缓存(.zcode/):可复跑,不入历史 - 新增两条测试:忽略内容不参与目录派生、独占锁内收集不自锁
166 lines
5.7 KiB
Python
166 lines
5.7 KiB
Python
"""验证期写闸门:验证会话持锁,生成与格式化入口在锁被持有时拒绝改写。
|
||
|
||
两个反复踩到的坑都从这里堵:
|
||
|
||
- 验证跑着的时候改 `src/`,本轮结论作废,但报告已经按旧结论写出去;
|
||
- `make 格式写入` 也算改源码,改完没重新 `make 生成`,整层用例报「已安装源码与资源发布身份不符」,
|
||
几百个错误全是假的。
|
||
|
||
锁是 `fcntl.flock`,进程退出即释放,不靠残留 PID 文件判断;锁文件里记一句当前验证说明。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import fcntl
|
||
import json
|
||
import os
|
||
import sys
|
||
from collections.abc import Iterator
|
||
from contextlib import contextmanager
|
||
from pathlib import Path
|
||
from typing import Any
|
||
|
||
锁路径 = Path(os.environ.get("MUSE_验证锁", "/tmp/muse-验证锁.lock")) # noqa: S108
|
||
_持锁标记 = "MUSE_写入锁已持有"
|
||
|
||
|
||
def 已在独占锁内() -> bool:
|
||
"""本进程是否由 `--执行` 启动:父进程已持独占写锁,不能再取共享锁。"""
|
||
|
||
return os.environ.get(_持锁标记) == "1"
|
||
|
||
|
||
def 正在验证() -> str | None:
|
||
"""返回当前验证说明;没有验证在跑时返回 None。
|
||
|
||
`--执行` 会在独占锁内跑写命令,被它启动的子进程(如构建编排)本身就是持锁方,
|
||
不能把自己判成「验证正在运行」;用环境变量把这一事实传给子进程。
|
||
"""
|
||
|
||
if 已在独占锁内():
|
||
return None
|
||
if not 锁路径.exists():
|
||
return None
|
||
with 锁路径.open("a+", encoding="utf-8") as 文件:
|
||
try:
|
||
fcntl.flock(文件, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||
except OSError:
|
||
return "有一个或多个验证会话在运行"
|
||
else:
|
||
fcntl.flock(文件, fcntl.LOCK_UN)
|
||
return None
|
||
|
||
|
||
def 登记说明(说明: str) -> None:
|
||
"""把本次验证写进锁文件,供人工查看谁在跑。"""
|
||
|
||
with 锁路径.open("a+", encoding="utf-8") as 文件:
|
||
文件.write(f"{说明}\n")
|
||
|
||
|
||
@contextmanager
|
||
def 持有(说明: str) -> Iterator[None]:
|
||
"""验证会话全程持共享锁;写入方要求独占,故分片并行验证互不阻塞。"""
|
||
|
||
锁路径.parent.mkdir(parents=True, exist_ok=True)
|
||
with 锁路径.open("a+", encoding="utf-8") as 文件:
|
||
fcntl.flock(文件, fcntl.LOCK_SH)
|
||
try:
|
||
yield
|
||
finally:
|
||
fcntl.flock(文件, fcntl.LOCK_UN)
|
||
|
||
|
||
def 已安装代码哈希() -> str | None:
|
||
"""直接读安装清单里的代码哈希;不需要打开资源提供器。"""
|
||
|
||
清单 = Path(__file__).resolve().parents[1] / "src" / "muse" / "资源" / "清单.json"
|
||
if not 清单.is_file():
|
||
return None
|
||
try:
|
||
数据: dict[str, Any] = json.loads(清单.read_text(encoding="utf-8"))
|
||
except (OSError, ValueError):
|
||
return None
|
||
return 数据.get("代码哈希")
|
||
|
||
|
||
def 源码身份核对() -> str | None:
|
||
"""返回不一致说明;一致返回 None。只算一次源码哈希,约 0.3 秒。"""
|
||
|
||
from muse.基础设施.系统运行 import 运行代码哈希
|
||
|
||
期望 = 已安装代码哈希()
|
||
if 期望 is None:
|
||
return "缺少已安装资源清单;先执行 make 生成"
|
||
当前 = 运行代码哈希()
|
||
if 当前 != 期望:
|
||
return "已安装源码与资源发布身份不符;先执行 make 生成(改过 src/ 或跑过格式写入都要重跑)"
|
||
return None
|
||
|
||
|
||
def 独占执行(命令: list[str]) -> int:
|
||
"""在独占锁内执行写命令:写窗口全程持锁,验证会话无法插入。
|
||
|
||
与 `--要求空闲` 的区别:后者查完即放锁,检查与写入之间仍可被验证会话插入。
|
||
"""
|
||
|
||
import subprocess
|
||
|
||
锁路径.parent.mkdir(parents=True, exist_ok=True)
|
||
with 锁路径.open("a+", encoding="utf-8") as 文件:
|
||
try:
|
||
fcntl.flock(文件, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||
except OSError:
|
||
print(
|
||
"拒绝改写:验证正在运行;等它结束再改,否则本轮验证结果作废",
|
||
file=sys.stderr,
|
||
)
|
||
return 1
|
||
try:
|
||
os.environ[_持锁标记] = "1"
|
||
return subprocess.run(命令, check=False).returncode
|
||
finally:
|
||
os.environ.pop(_持锁标记, None)
|
||
fcntl.flock(文件, fcntl.LOCK_UN)
|
||
|
||
|
||
def main(argv: list[str] | None = None) -> int:
|
||
解析 = argparse.ArgumentParser(description=__doc__)
|
||
解析.add_argument(
|
||
"--要求空闲", action="store_true", help="锁被持有时非零退出,供写入入口前置检查(查完即放锁)"
|
||
)
|
||
解析.add_argument("--核对源码身份", action="store_true", help="比较源码哈希与安装清单")
|
||
解析.add_argument(
|
||
"--执行",
|
||
nargs=argparse.REMAINDER,
|
||
metavar="命令",
|
||
help="在独占锁内执行写命令,例如 --执行 uv run --no-sync python 工具/构建编排.py",
|
||
)
|
||
值 = 解析.parse_args(argv)
|
||
if 值.要求空闲:
|
||
说明 = 正在验证()
|
||
if 说明:
|
||
print(
|
||
f"拒绝改写:验证正在运行({说明});等它结束再改,否则本轮验证结果作废",
|
||
file=sys.stderr,
|
||
)
|
||
return 1
|
||
print("验证空闲:可以改写源码")
|
||
if 值.核对源码身份:
|
||
问题 = 源码身份核对()
|
||
if 问题:
|
||
print(问题, file=sys.stderr)
|
||
return 1
|
||
print("源码身份一致:安装清单与当前源码同哈希")
|
||
if 值.执行 is not None:
|
||
if not 值.执行:
|
||
print("--执行 需要给出命令", file=sys.stderr)
|
||
return 2
|
||
return 独占执行(list(值.执行))
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|