"""Build CadHubManage as a standalone Windows executable using PyInstaller.""" from __future__ import annotations import argparse import os import shutil import subprocess import sys from pathlib import Path def ensure_pyinstaller() -> None: try: import PyInstaller # noqa: F401 pylint: disable=unused-import except ImportError as exc: # pragma: no cover - runtime guard raise SystemExit( "PyInstaller 未安装,请先运行 'pip install pyinstaller'." ) from exc def build_executable(*, clean: bool) -> Path: project_root = Path(__file__).resolve().parents[1] dist_dir = project_root / "dist" build_dir = project_root / "build" temp_dist = dist_dir / "tmp_pyinstaller" exe_name = "CadHubManage.exe" output_exe = dist_dir / exe_name if clean: if build_dir.exists(): shutil.rmtree(build_dir) if temp_dist.exists(): shutil.rmtree(temp_dist) if output_exe.exists(): output_exe.unlink() ensure_pyinstaller() dist_dir.mkdir(parents=True, exist_ok=True) temp_dist.mkdir(parents=True, exist_ok=True) entry_script = project_root / "launcher.py" command = [ sys.executable, "-m", "PyInstaller", "--noconfirm", "--clean", "--onefile", "--name", "CadHubManage", "--distpath", str(temp_dist), "--workpath", str(build_dir), "--specpath", str(project_root / "scripts"), ] configs_src = project_root / "configs" if configs_src.exists(): command += ["--add-data", f"{configs_src}{os.pathsep}configs"] env_example = project_root / ".env.example" if env_example.exists(): command += ["--add-data", f"{env_example}{os.pathsep}."] command.append(str(entry_script)) subprocess.check_call(command) built_exe = temp_dist / exe_name if not built_exe.exists(): raise FileNotFoundError(f"未找到 PyInstaller 生成的可执行文件: {built_exe}") if output_exe.exists(): output_exe.unlink() shutil.move(str(built_exe), str(output_exe)) shutil.rmtree(temp_dist) return output_exe def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="打包 CadHubManage 为单文件 exe") parser.add_argument("--clean", action="store_true", help="构建前清理旧产物") return parser.parse_args() def main() -> None: args = parse_args() exe_path = build_executable(clean=args.clean) print(f"构建完成: {exe_path}") print("将 dist/CadHubManage.exe 单文件分发到目标机器即可运行") if __name__ == "__main__": main()