#!/usr/bin/env python3 # -*- coding: utf-8 -*- """bug-2 修复: 从 v0.1.0 发行包把缺失的 release/如东/ 交付件恢复到 v0.2.0 安装目录。 根因: v0.2.0 包**根本没带** release/如东/ (0.2.0 zip 里 release/ 下只有 viewer/), 而 release/portal.html 的 #documents 区块用 iframe 指向 http://127.0.0.1:28084/如东/如东治理清单_交付_20260901/02_治理清单/如东_液压系统治理清单_v1.2_2026-09-01.html 该路径由网关 _static() 从 release/ 目录取文件, 文件不在 → 404 {"err":"not found", "path": …}, iframe 里就直接显示那段 JSON。v0.1.0 包里这份交付件是齐的 (76 项), 直接恢复。 (release/如东/ 按 .gitignore 约定不入库 —— 客户交付物只在受保护工作区。) """ from __future__ import annotations import pathlib import shutil import sys import zipfile ZIP = pathlib.Path(r"F:\temp\guanlan-rudong-v2_0.1.0_all.zip") REL = pathlib.Path(r"F:\temp\guanlan-rudong-v2_0.2.0\release") PREFIX = "release/如东/" def nm(info): raw = info.filename for enc in ("gbk", "utf-8"): try: return raw.encode("cp437").decode(enc) except Exception: continue return raw def main() -> int: if not ZIP.is_file(): print(f" [X] 缺源包 {ZIP}") return 1 print(f"源: {ZIP}") print(f"目标: {REL}\\如东\\\n") n_files = 0 n_bytes = 0 with zipfile.ZipFile(ZIP) as zf: items = [(nm(i), i) for i in zf.infolist()] rel = [(n.replace("\\", "/"), i) for n, i in items if n.replace("\\", "/").startswith(PREFIX)] if not rel: print(" [X] 源包里没有 release/如东/") return 1 for name, info in rel: target = REL / name[len("release/"):] if info.is_dir(): target.mkdir(parents=True, exist_ok=True) continue target.parent.mkdir(parents=True, exist_ok=True) with zf.open(info) as fsrc, open(target, "wb") as fdst: shutil.copyfileobj(fsrc, fdst, 1024 * 1024) if target.stat().st_size != info.file_size: print(f" [X] 大小不符: {target}") return 1 n_files += 1 n_bytes += info.file_size print(f"恢复 {n_files} 个文件, {n_bytes/1024/1024:.1f} MB") return 0 if __name__ == "__main__": sys.exit(main())