|
|
@@ -417,23 +417,31 @@ def verify(zip_path: pathlib.Path, keep=False) -> int:
|
|
|
if miss or enc:
|
|
|
return 1
|
|
|
print(' [OK] 引用全部在位, 编码守则通过 (install.ps1 = UTF-8 BOM + CRLF)')
|
|
|
- # ★2026-09-19 用户令: 包里带"输入数据目录结构"(空目录)。解压后必须真的建出来了, 且**一个文件都没有**
|
|
|
- # —— 两边都查: 目录少了 ⇒ 人不知道往哪放; 目录里混进文件 ⇒ 包就不是"只带结构"了。
|
|
|
+ # ★2026-09-19 用户令: 包里带"输入数据目录结构"(空目录)。解压后必须真的建出来了, 且**除说明文件外一个
|
|
|
+ # 文件都没有** —— 两边都查: 目录少了 ⇒ 人不知道往哪放; 目录里混进数据文件 ⇒ 包就不是"只带结构"了。
|
|
|
+ # ★2026-09-19 实逮 (第一次开箱验证就卡在这): ① 原先用 `rglob` 逐目录收集, 同一个文件会被父目录
|
|
|
+ # 重复计入 (`data` 与 `data/raw` 各算一次) ⇒ 报"混进 2 个文件"; ② 按清单随包发的**放置说明**
|
|
|
+ # (`data/raw/README_把原始数据放这里.txt`, 在 `INCLUDE_FILES` 里) 被当成"混进的文件"。
|
|
|
+ # 现在: 允许清单 = INCLUDE_FILES 里落在骨架目录内的文件; 收集用集合(去重)。
|
|
|
skel = data_skeleton()
|
|
|
+ allowed = {f.replace('\\', '/') for f in INCLUDE_FILES if any(f.replace('\\', '/').startswith(r.rstrip('/') + '/')
|
|
|
+ for r in skel)}
|
|
|
miss_d = [r for r in skel if not (tmp / r).is_dir()]
|
|
|
- extra_f = []
|
|
|
+ extra_f = set()
|
|
|
for r in skel:
|
|
|
d = tmp / r
|
|
|
if d.is_dir():
|
|
|
- extra_f += [str(p.relative_to(tmp)) for p in d.rglob('*') if p.is_file()]
|
|
|
+ extra_f |= {p.relative_to(tmp).as_posix() for p in d.rglob('*') if p.is_file()}
|
|
|
+ extra_f -= allowed
|
|
|
if miss_d:
|
|
|
print(f' [X] 输入数据目录骨架缺 {len(miss_d)} 个: {miss_d[:5]}')
|
|
|
if extra_f:
|
|
|
- print(f' [X] 骨架目录里混进了 {len(extra_f)} 个文件 (应只有空目录): {extra_f[:5]}')
|
|
|
+ print(f' [X] 骨架目录里混进了 {len(extra_f)} 个文件 (除说明文件外应只有空目录): {sorted(extra_f)[:5]}')
|
|
|
if miss_d or extra_f:
|
|
|
return 1
|
|
|
- print(f' [OK] 输入数据目录骨架: {len(skel)} 个空目录全部在位, 且无任何文件'
|
|
|
- f' (用户令 2026-09-19: 带结构不带文件)')
|
|
|
+ print(f' [OK] 输入数据目录骨架: {len(skel)} 个空目录全部在位'
|
|
|
+ f'{f" + 放置说明 {len(allowed)} 件" if allowed else ""}, 无其他文件'
|
|
|
+ f' (用户令 2026-09-19: 带结构不带数据文件)')
|
|
|
print('② 离线安装')
|
|
|
xt = _xfer()
|
|
|
py = xt.install_in(tmp)
|