#!/usr/bin/env python3 """Verify PyInstaller bundle TOC chua du app assets (app/static, app/templates). Dung boi build_windows.ps1 (buoc 3.5/6) de bat loi bundle NGAY tai build: python tools/verify_bundle.py Exit code 0 = OK, 1 = thieu asset. Ly do ton tai: da gap 2 lan exe crash 'Directory ...\\app\\static does not exist' vi chay pyinstaller tu noi khac -> datas relative khong resolve -> bo qua am tham. """ import glob import os import re import sys REQUIRED = ["app/static", "app/templates"] # F4: bridge sidecar phai co truoc khi tauri build (externalBin). Kiem tra tai # day de build fail SOM nhat (build_windows.ps1 goi verify nay truoc tauri build). BRIDGE_SIDECAR = os.path.join( "src-tauri", "binaries", "daw_vst_bridge-x86_64-pc-windows-msvc.exe" ) def find_toc(build_dir: str) -> str: # PyInstaller 6.x: build/engine/Analysis-00.toc (hoac *-00.toc khac) for pattern in ( os.path.join(build_dir, "engine", "Analysis-00.toc"), os.path.join(build_dir, "engine", "*-00.toc"), os.path.join(build_dir, "**", "Analysis-00.toc"), os.path.join(build_dir, "**", "*-00.toc"), ): hits = glob.glob(pattern, recursive=True) if hits: return hits[0] return "" def main() -> int: check_bridge = "--check-bridge" in sys.argv build_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "build")) toc = find_toc(build_dir) if not toc: print(f"WARN: khong tim thay TOC trong {build_dir} - bo qua verify (tiep tuc build)") return 0 print(f"Verify TOC: {toc}") with open(toc, "r", encoding="utf-8", errors="replace") as f: raw = f.read() # TOC Windows co the dung backslash (app\\static) — normalize het ve forward # slash de kiem tra khong bi false positive. TOC la Python literal nen # backslash bi DOUBLE-escape ('app\\\\static') — thay 2 lan (\\\\ truoc, # roi \\) de ca 2 dang deu ve '/'. text = raw.replace("\\\\", "/").replace("\\", "/") missing = [] for req in REQUIRED: # Tim theo prefix thuc su trong TOC (vd 'app/static/js/...' hoac # string repr 'app/static/...' trong tuple DATA entry). if not re.search(re.escape(req) + r"(?=[/'\"]|$)", text): missing.append(req) if missing: print(f"ERROR: Bundle thieu: {', '.join(missing)}. Kiem tra engine.spec datas!") return 1 print("OK: app/static + app/templates co trong bundle.") # F4: bridge sidecar (externalBin) — kiem tra o repo root (khong phai trong # PyInstaller bundle): thieu -> tauri build se im lang bo qua bridge. # Chi chay khi --check-bridge (goi o buoc [7/7] build_windows.ps1 — sau # khi da build bridge o buoc [5/7]). if check_bridge: repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sidecar = os.path.join(repo_root, BRIDGE_SIDECAR) if not os.path.exists(sidecar): print(f"ERROR: Thieu bridge sidecar: {sidecar}") print(" Chay build/scripts/build_native_bridge.ps1 truoc, hoac") print(" build_windows.ps1 buoc [5/7] se build tu dong.") return 1 print(f"OK: bridge sidecar co mat ({BRIDGE_SIDECAR}).") return 0 if __name__ == "__main__": sys.exit(main())