tradingSystem/scripts/code_fingerprint.py

56 lines
2.4 KiB
Python
Raw Normal View History

2026-08-03 09:10:56 +08:00
# -*- coding: utf-8 -*-
"""
代码指纹 (零依赖, 不连库, import 业务模块)
================================================
运行: python scripts/code_fingerprint.py 只打印一行 12 位短哈希
为什么需要它
------------
**源码是打进镜像的**, `docker compose run --rm pms-web python scripts/xxx.py` 跑的是
**镜像里的那份**, 不是工作树里刚 `git pull` 下来的那份于是有一条特别难发现的路径:
git pull make test ALL SUITES PASS
这个 PASS **旧代码的 PASS**它读起来像"新改的代码验过了", 实际上新代码一行都没跑过
连单测清单都还是旧的 (新增的一批测试文件根本不在镜像里, `run_tests.py` 只会打印
"跳过 xxx (文件不存在)" 然后照样 ALL SUITES PASS)2026-07-31 实机就是这样:
`make t-pre` 的返回里少了新加的字段, 才反推出容器跑的是旧镜像
这跟本项目一直在治的是同一种病 **一个不成立的结论长得像成立**所以给它一个指纹:
`make test` 会把容器里的指纹和工作树的指纹对一遍, 对不上就喊, 而不是让那个 PASS 蒙人
指纹只覆盖 .py 源码 (app/ scripts/ config/) MakefilecomposeDDL 不影响它
那几样不进 Python 运行时, 另有各自的生效路径
"""
import hashlib
import os
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DIRS = ("app", "scripts", "config")
def fingerprint(root: str = ROOT) -> str:
h = hashlib.sha256()
files = []
for d in DIRS:
base = os.path.join(root, d)
for dirpath, dirnames, filenames in os.walk(base):
# __pycache__ 里是编译产物, 跟着源码走, 不该进指纹
dirnames[:] = [x for x in dirnames if x != "__pycache__"]
for fn in filenames:
if fn.endswith(".py"):
files.append(os.path.join(dirpath, fn))
for p in sorted(files, key=lambda x: os.path.relpath(x, root)):
rel = os.path.relpath(p, root).replace(os.sep, "/")
h.update(rel.encode("utf-8"))
h.update(b"\0")
with open(p, "rb") as f:
h.update(hashlib.sha256(f.read()).digest())
return h.hexdigest()[:12]
if __name__ == "__main__":
# 只打印指纹本身, 一行, 不带任何前后缀 —— 调用方要拿它做字符串比较
sys.stdout.write(fingerprint() + "\n")