CadHubManage/scripts/build_exe.py
2025-12-19 17:21:53 +08:00

102 lines
2.8 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"
bundle_dir = dist_dir / "CadHubManage"
exe_name = "CadHubManage.exe"
if clean:
if build_dir.exists():
shutil.rmtree(build_dir)
if temp_dist.exists():
shutil.rmtree(temp_dist)
if bundle_dir.exists():
shutil.rmtree(bundle_dir)
ensure_pyinstaller()
dist_dir.mkdir(parents=True, exist_ok=True)
temp_dist.mkdir(parents=True, exist_ok=True)
command = [
sys.executable,
"-m",
"PyInstaller",
"--noconfirm",
"--clean",
"--onefile",
"--name",
"CadHubManage",
"--distpath",
str(temp_dist),
"--workpath",
str(build_dir),
"--specpath",
str(project_root / "scripts"),
str(project_root / "launcher.py"),
]
subprocess.check_call(command)
bundle_dir.mkdir(parents=True, exist_ok=True)
built_exe = temp_dist / exe_name
if not built_exe.exists():
raise FileNotFoundError(f"未找到 PyInstaller 生成的可执行文件: {built_exe}")
shutil.move(str(built_exe), str(bundle_dir / exe_name))
configs_src = project_root / "configs"
if configs_src.exists():
shutil.copytree(configs_src, bundle_dir / "configs", dirs_exist_ok=True)
env_example = project_root / ".env.example"
if env_example.exists():
shutil.copy2(env_example, bundle_dir / ".env.example")
log_dir = bundle_dir / "logs"
(log_dir / "operation_logs").mkdir(parents=True, exist_ok=True)
shutil.rmtree(temp_dist)
return bundle_dir / exe_name
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 目录整体分发到目标机器运行 CadHubManage.exe")
if __name__ == "__main__":
main()