# -*- coding: utf-8 -*- r"""把整个项目打成压缩包,交给用户。 包含:全部源码(三端 + 安装包脚本 + 测试 + 构建脚本)+ 三份文档 + 已构建好的成品(安装包 / APK / 两个 zip) 排除: * .git 版本库(几十 MB,而且推上去过) * dist_exe 40MB PyInstaller 产物,一条命令能重建 * _build/pyinstaller_work 同上 * __pycache__ / *.pyc * _tests/out_* / _tests/received 测试临时数据 * _build/jc* 编译中间产物 * **_build/.gitee_token** ← Gitee 令牌,**绝对不能进包** """ from __future__ import annotations import re import sys import zipfile from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") OUT = ROOT / "dist" / "ykxmz-项目完整源码.zip" # 目录级排除(按相对路径前缀) EXCLUDE_DIRS = ( ".git", "dist_exe", "_build/pyinstaller_work", "_build/jc_all", "_build/jc_tls", "_build/jc_tls2", "_build/jc_v15", "_build/out_java", "_build/out_app", "_tests/out_java", "_tests/out_app", "_tests/received", "_tests/_stubdata", "_tests/shots", "__pycache__", "android/build", "android/gen", "android/bin", "windows/data", ) # 文件名级排除 EXCLUDE_NAMES = { ".gitee_token", "Thumbs.db", "desktop.ini", ".DS_Store", } # 后缀级排除 EXCLUDE_SUFFIXES = ( ".pyc", ".pyo", ".pyd", ".log", ".tmp", ".toc", ".pyz", ".pkg", ".bak", ".orig", ) # 要打进去的顶层条目(只打这些,别的一律不要) INCLUDE_TOP = ( "windows", "android", "relay", "installer", "docs", "tools", "_tests", "_build", "README.md", "LICENSE.md", ".gitignore", "diag", "dist", ) # dist 里只带上成品,别把中间目录带进去 DIST_KEEP = (".exe", ".apk", ".zip", ".idsig", ".txt") def excluded(rel: str, path: Path) -> bool: rel_posix = rel.replace("\\", "/") for prefix in EXCLUDE_DIRS: if rel_posix == prefix or rel_posix.startswith(prefix + "/"): return True if path.name in EXCLUDE_NAMES: return True if path.suffix.lower() in EXCLUDE_SUFFIXES: return True # dist 目录只留成品 if rel_posix.startswith("dist/"): if path.is_file() and not path.name.lower().endswith(DIST_KEEP): return True if rel_posix == "dist" and path.is_dir(): return False return False def main() -> int: if OUT.exists(): OUT.unlink() OUT.parent.mkdir(parents=True, exist_ok=True) count = 0 total = 0 skipped_token = False with zipfile.ZipFile(OUT, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as archive: for top in INCLUDE_TOP: root = ROOT / top if not root.exists(): print(f" [跳过] 没有 {top}") continue if root.is_file(): archive.write(root, f"ykxmz/{top}") count += 1 total += root.stat().st_size continue for path in sorted(root.rglob("*")): rel = str(path.relative_to(ROOT)) if excluded(rel, path): if path.name == ".gitee_token": skipped_token = True continue if path.is_dir(): continue archive.write(path, f"ykxmz/{rel.replace(chr(92), '/')}") count += 1 total += path.stat().st_size size = OUT.stat().st_size / 1024 / 1024 print(f" ✓ {OUT.name}") print(f" {count} 个文件,原始 {total / 1024 / 1024:.1f} MB," f"压缩后 {size:.1f} MB") print(f" Gitee 令牌已排除: {skipped_token or '(本来就没扫到)'}") return 0 if __name__ == "__main__": sys.exit(main())