CadHubManage/scripts/build_exe.py
2025-12-22 09:14:34 +08:00

102 lines
2.7 KiB
Python

"""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()