|
@@ -23,7 +23,7 @@ r"""一条命令重算全部 (2026-09-12) —— 把散在各脚本里的重算
|
|
|
|
|
|
|
|
python scripts/rebuild_all.py # 全套 (会跑 SCADA 那 15 分钟)
|
|
python scripts/rebuild_all.py # 全套 (会跑 SCADA 那 15 分钟)
|
|
|
python scripts/rebuild_all.py --skip-scada # 只换台账时的常用档
|
|
python scripts/rebuild_all.py --skip-scada # 只换台账时的常用档
|
|
|
- python scripts/rebuild_all.py --src F:\temp\如东风场数据 # 连"放数据"一起
|
|
|
|
|
|
|
+ python scripts/rebuild_all.py --src <现场包目录> # 连"放数据"一起
|
|
|
python scripts/rebuild_all.py --no-restart # 不碰服务(自己管)
|
|
python scripts/rebuild_all.py --no-restart # 不碰服务(自己管)
|
|
|
python scripts/rebuild_all.py --with-verify # 末尾加等价验收(需随包基线在位)
|
|
python scripts/rebuild_all.py --with-verify # 末尾加等价验收(需随包基线在位)
|
|
|
python scripts/rebuild_all.py --dry-run # 只打印计划
|
|
python scripts/rebuild_all.py --dry-run # 只打印计划
|
|
@@ -41,9 +41,9 @@ ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|
|
PY = sys.executable
|
|
PY = sys.executable
|
|
|
|
|
|
|
|
|
|
|
|
|
-def step_cmd(name, cmd, tolerate=()):
|
|
|
|
|
- """tolerate: 允许的退出码 (不算失败)。"""
|
|
|
|
|
- return (name, cmd, tuple(tolerate))
|
|
|
|
|
|
|
+def step_cmd(name, cmd, tolerate=(), note=''):
|
|
|
|
|
+ """tolerate: 允许的退出码 (不算失败); note: 该步非零退出时打给人看的解释(按步, 别用一句通用话糊过去)。"""
|
|
|
|
|
+ return (name, cmd, tuple(tolerate), note)
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_plan(a) -> list:
|
|
def build_plan(a) -> list:
|
|
@@ -62,7 +62,8 @@ def build_plan(a) -> list:
|
|
|
# 连网关会**沿父子树把正在执行的重算一起杀掉**(2026-09-12 实测: 日志停在 stop 那行, 之后全无)。
|
|
# 连网关会**沿父子树把正在执行的重算一起杀掉**(2026-09-12 实测: 日志停在 stop 那行, 之后全无)。
|
|
|
# 组件停掉再 serve 就够: chain_ingest 要的是 detail(18033) 重新加载新产物, 网关不缓存产物。
|
|
# 组件停掉再 serve 就够: chain_ingest 要的是 detail(18033) 重新加载新产物, 网关不缓存产物。
|
|
|
plan.append(step_cmd('⑥ 重启组件服务 (保留网关, stop)', [PY, 'scripts/_ops_stop_keep_gateway.py']))
|
|
plan.append(step_cmd('⑥ 重启组件服务 (保留网关, stop)', [PY, 'scripts/_ops_stop_keep_gateway.py']))
|
|
|
- plan.append(step_cmd('⑥ 重启组件服务 (serve)', [PY, 'guanlan.py', 'serve'], tolerate=(1,)))
|
|
|
|
|
|
|
+ plan.append(step_cmd('⑥ 重启组件服务 (serve)', [PY, 'guanlan.py', 'serve'], tolerate=(1,),
|
|
|
|
|
+ note='serve 在"有模块 DOWN"时故意返回 1 —— degraded 是正常状态(例如本机模型未启动)'))
|
|
|
plan.append(step_cmd('⑦ 本体: 码表/手册/文档', [PY, '-m', 'src.ontology.kb_ingest']))
|
|
plan.append(step_cmd('⑦ 本体: 码表/手册/文档', [PY, '-m', 'src.ontology.kb_ingest']))
|
|
|
plan.append(step_cmd('⑦ 本体: 铺开判级与台账', [PY, '-m', 'src.ontology.populate']))
|
|
plan.append(step_cmd('⑦ 本体: 铺开判级与台账', [PY, '-m', 'src.ontology.populate']))
|
|
|
plan.append(step_cmd('⑦ 本体: 决策链进度', [PY, '-m', 'src.ontology.chain_ingest']))
|
|
plan.append(step_cmd('⑦ 本体: 决策链进度', [PY, '-m', 'src.ontology.chain_ingest']))
|
|
@@ -71,10 +72,11 @@ def build_plan(a) -> list:
|
|
|
plan.append(step_cmd('⑦ 本体: 实机参数表', [PY, '-c', 'from src.ontology.maintenance import refresh_params as f; print(f())']))
|
|
plan.append(step_cmd('⑦ 本体: 实机参数表', [PY, '-c', 'from src.ontology.maintenance import refresh_params as f; print(f())']))
|
|
|
plan.append(step_cmd('⑧ 本体审计 (期望 0 问题)', [PY, '-m', 'src.ontology.audit']))
|
|
plan.append(step_cmd('⑧ 本体审计 (期望 0 问题)', [PY, '-m', 'src.ontology.audit']))
|
|
|
if a.with_verify:
|
|
if a.with_verify:
|
|
|
- # 退出码 4 = 有"无法归类"的差异; 本包已知的差异是"油样 102 行源件不在现场包里"(属人工项),
|
|
|
|
|
- # 所以容忍 4 但把完整报告打给用户看 —— 真出现新差异时报告里会点名。
|
|
|
|
|
- plan.append(step_cmd('⑧ 台账等价验收 (rc=4 表示有需人工看的差异, 属已知)',
|
|
|
|
|
- [PY, 'scripts/rebuild_from_raw.py', '--verify'], tolerate=(4,)))
|
|
|
|
|
|
|
+ # 只有 4 = "有需人工看的差异"(本包已知项: 油样 102 行的源件不在现场包里) 才容忍;
|
|
|
|
|
+ # 5 = 找不到基线(等于没验收) 必须当失败 —— 2026-09-12 就是因为放过了它, 出现过"验收没做却报通过"。
|
|
|
|
|
+ plan.append(step_cmd('⑧ 台账等价验收 (rc=4 = 有需人工看的差异, 属已知)',
|
|
|
|
|
+ [PY, 'scripts/rebuild_from_raw.py', '--verify'], tolerate=(4,),
|
|
|
|
|
+ note='rc=5 表示找不到随包基线, 那是"没验收"不是通过'))
|
|
|
return plan
|
|
return plan
|
|
|
|
|
|
|
|
|
|
|
|
@@ -91,7 +93,7 @@ def main() -> int:
|
|
|
print(f'重算全部 · {len(plan)} 步 · 根目录 {ROOT}')
|
|
print(f'重算全部 · {len(plan)} 步 · 根目录 {ROOT}')
|
|
|
print(f' 跳过 SCADA: {a.skip_scada} | 重启服务: {not a.no_restart} | 等价验收: {a.with_verify}\n')
|
|
print(f' 跳过 SCADA: {a.skip_scada} | 重启服务: {not a.no_restart} | 等价验收: {a.with_verify}\n')
|
|
|
if a.dry_run:
|
|
if a.dry_run:
|
|
|
- for name, cmd, tol in plan:
|
|
|
|
|
|
|
+ for name, cmd, tol, note in plan:
|
|
|
print(f' {name:34s} {" ".join(cmd[1:])[:90]}')
|
|
print(f' {name:34s} {" ".join(cmd[1:])[:90]}')
|
|
|
print('\n(dry-run, 未执行)')
|
|
print('\n(dry-run, 未执行)')
|
|
|
return 0
|
|
return 0
|
|
@@ -100,7 +102,7 @@ def main() -> int:
|
|
|
# 子脚本 print 里的 ✔/✗ 会抛 UnicodeEncodeError, 明明干成了却以退出码 1 结束。
|
|
# 子脚本 print 里的 ✔/✗ 会抛 UnicodeEncodeError, 明明干成了却以退出码 1 结束。
|
|
|
env = dict(os.environ, PYTHONUTF8='1', PYTHONIOENCODING='utf-8')
|
|
env = dict(os.environ, PYTHONUTF8='1', PYTHONIOENCODING='utf-8')
|
|
|
results, t_all = [], time.time()
|
|
results, t_all = [], time.time()
|
|
|
- for i, (name, cmd, tol) in enumerate(plan, 1):
|
|
|
|
|
|
|
+ for i, (name, cmd, tol, note) in enumerate(plan, 1):
|
|
|
print(f'\n{"=" * 78}\n[{i}/{len(plan)}] {name}\n$ {" ".join(cmd)}\n{"=" * 78}', flush=True)
|
|
print(f'\n{"=" * 78}\n[{i}/{len(plan)}] {name}\n$ {" ".join(cmd)}\n{"=" * 78}', flush=True)
|
|
|
t0 = time.time()
|
|
t0 = time.time()
|
|
|
rc = subprocess.run(cmd, cwd=str(ROOT), env=env).returncode
|
|
rc = subprocess.run(cmd, cwd=str(ROOT), env=env).returncode
|
|
@@ -109,9 +111,11 @@ def main() -> int:
|
|
|
results.append((name, rc, dt, ok, tol))
|
|
results.append((name, rc, dt, ok, tol))
|
|
|
if not ok:
|
|
if not ok:
|
|
|
print(f'\n[X] 第 {i} 步失败 (退出码 {rc}): {name} —— 后面的步骤依赖它, 先停下。')
|
|
print(f'\n[X] 第 {i} 步失败 (退出码 {rc}): {name} —— 后面的步骤依赖它, 先停下。')
|
|
|
|
|
+ if note:
|
|
|
|
|
+ print(f' 该步说明: {note}')
|
|
|
break
|
|
break
|
|
|
if rc != 0:
|
|
if rc != 0:
|
|
|
- print(f'\n (退出码 {rc} 属预期: {name} 的 degraded 是正常状态 —— 例如本机模型未启动)')
|
|
|
|
|
|
|
+ print(f'\n (退出码 {rc} 属预期{(": " + note) if note else ""})')
|
|
|
|
|
|
|
|
print(f'\n{"=" * 78}\n汇总 (总耗时 {time.time() - t_all:.0f}s)')
|
|
print(f'\n{"=" * 78}\n汇总 (总耗时 {time.time() - t_all:.0f}s)')
|
|
|
for name, rc, dt, ok, tol in results:
|
|
for name, rc, dt, ok, tol in results:
|