243 lines
7.1 KiB
Python
243 lines
7.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""
|
||
|
|
GPCT-standalone 自动打包脚本
|
||
|
|
支持: Windows (PyInstaller) + NSIS 安装包生成
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
import json
|
||
|
|
import shutil
|
||
|
|
import subprocess
|
||
|
|
from datetime import datetime
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
# 配置
|
||
|
|
PROJECT_DIR = Path("C:/PPRO/TG-PlatformPlus")
|
||
|
|
VENV_DIR = PROJECT_DIR / "venv"
|
||
|
|
DIST_DIR = PROJECT_DIR / "dist"
|
||
|
|
BUILD_DIR = PROJECT_DIR / "build"
|
||
|
|
SPEC_DIR = PROJECT_DIR / "spec"
|
||
|
|
NSIS_SCRIPT = PROJECT_DIR / "GPCT-standalone.nsi"
|
||
|
|
VERSION_FILE = PROJECT_DIR / "version.json"
|
||
|
|
|
||
|
|
def run_command(cmd, cwd=None, check=True):
|
||
|
|
"""执行命令并返回结果"""
|
||
|
|
print(f"执行: {cmd}")
|
||
|
|
result = subprocess.run(
|
||
|
|
cmd,
|
||
|
|
shell=True,
|
||
|
|
cwd=cwd or PROJECT_DIR,
|
||
|
|
capture_output=True,
|
||
|
|
text=True,
|
||
|
|
encoding='utf-8'
|
||
|
|
)
|
||
|
|
if result.returncode != 0 and check:
|
||
|
|
print(f"[错误] 命令执行失败:")
|
||
|
|
print(f"stdout: {result.stdout}")
|
||
|
|
print(f"stderr: {result.stderr}")
|
||
|
|
sys.exit(1)
|
||
|
|
return result
|
||
|
|
|
||
|
|
def activate_venv():
|
||
|
|
"""激活虚拟环境"""
|
||
|
|
venv_python = VENV_DIR / "Scripts" / "python.exe"
|
||
|
|
if not venv_python.exists():
|
||
|
|
print(f"[错误] 未找到虚拟环境 Python: {venv_python}")
|
||
|
|
sys.exit(1)
|
||
|
|
return venv_python
|
||
|
|
|
||
|
|
def clean_build():
|
||
|
|
"""清理旧的构建文件"""
|
||
|
|
print("\n[1/6] 清理旧的构建文件...")
|
||
|
|
|
||
|
|
dirs_to_clean = [DIST_DIR, BUILD_DIR]
|
||
|
|
for dir_path in dirs_to_clean:
|
||
|
|
if dir_path.exists():
|
||
|
|
shutil.rmtree(dir_path)
|
||
|
|
print(f" - 已删除: {dir_path}")
|
||
|
|
|
||
|
|
def update_version():
|
||
|
|
"""更新版本信息"""
|
||
|
|
print("\n[2/6] 更新版本信息...")
|
||
|
|
|
||
|
|
if VERSION_FILE.exists():
|
||
|
|
with open(VERSION_FILE, 'r', encoding='utf-8') as f:
|
||
|
|
version_data = json.load(f)
|
||
|
|
|
||
|
|
# 更新发布时间
|
||
|
|
version_data['releaseTime'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
|
|
|
||
|
|
with open(VERSION_FILE, 'w', encoding='utf-8') as f:
|
||
|
|
json.dump(version_data, f, ensure_ascii=False, indent=4)
|
||
|
|
|
||
|
|
print(f" - 版本: {version_data.get('version', 'N/A')}")
|
||
|
|
print(f" - 发布时间: {version_data['releaseTime']}")
|
||
|
|
else:
|
||
|
|
print(f" [警告] 未找到版本文件: {VERSION_FILE}")
|
||
|
|
|
||
|
|
def build_with_pyinstaller():
|
||
|
|
"""使用 PyInstaller 打包"""
|
||
|
|
print("\n[3/6] 使用 PyInstaller 打包...")
|
||
|
|
|
||
|
|
python_exe = activate_venv()
|
||
|
|
|
||
|
|
# 查找 spec 文件
|
||
|
|
spec_files = list(SPEC_DIR.glob("*.spec"))
|
||
|
|
if not spec_files:
|
||
|
|
print(f"[错误] 未找到 spec 文件在: {SPEC_DIR}")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
spec_file = spec_files[0]
|
||
|
|
print(f" - 使用 spec 文件: {spec_file}")
|
||
|
|
|
||
|
|
# 执行 PyInstaller
|
||
|
|
cmd = f'"{python_exe}" -m PyInstaller "{spec_file}" --clean'
|
||
|
|
result = run_command(cmd)
|
||
|
|
|
||
|
|
if "completed successfully" in result.stdout or (DIST_DIR / "GPCT-standalone").exists():
|
||
|
|
print(" - PyInstaller 打包成功")
|
||
|
|
else:
|
||
|
|
print(f" [警告] 请检查输出: {result.stdout}")
|
||
|
|
|
||
|
|
def copy_additional_files():
|
||
|
|
"""复制额外文件到输出目录"""
|
||
|
|
print("\n[4/6] 复制额外文件...")
|
||
|
|
|
||
|
|
output_dir = DIST_DIR / "GPCT-standalone" / "_internal"
|
||
|
|
|
||
|
|
# 创建 dataFile 目录
|
||
|
|
datafile_dir = output_dir / "dataFile"
|
||
|
|
datafile_dir.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
# 复制 dataFile 文件
|
||
|
|
src_datafile = PROJECT_DIR / "dataFile"
|
||
|
|
if src_datafile.exists():
|
||
|
|
for file in ["config.json", "data.db"]:
|
||
|
|
src = src_datafile / file
|
||
|
|
if src.exists():
|
||
|
|
shutil.copy2(src, datafile_dir / file)
|
||
|
|
print(f" - 已复制: {file}")
|
||
|
|
|
||
|
|
# 复制加密狗 DLL
|
||
|
|
dog_dll = PROJECT_DIR / "Syunew3D_x64.dll"
|
||
|
|
if dog_dll.exists():
|
||
|
|
shutil.copy2(dog_dll, output_dir / "Syunew3D_x64.dll")
|
||
|
|
print(f" - 已复制: Syunew3D_x64.dll")
|
||
|
|
|
||
|
|
# 复制 influxd.exe
|
||
|
|
influxd = PROJECT_DIR / "influxd.exe"
|
||
|
|
if influxd.exists():
|
||
|
|
shutil.copy2(influxd, output_dir / "influxd.exe")
|
||
|
|
print(f" - 已复制: influxd.exe")
|
||
|
|
|
||
|
|
def build_nsis_installer():
|
||
|
|
"""构建 NSIS 安装包"""
|
||
|
|
print("\n[5/6] 构建 NSIS 安装包...")
|
||
|
|
|
||
|
|
if not NSIS_SCRIPT.exists():
|
||
|
|
print(f" [跳过] 未找到 NSIS 脚本: {NSIS_SCRIPT}")
|
||
|
|
return
|
||
|
|
|
||
|
|
# 查找 makensis
|
||
|
|
makensis_paths = [
|
||
|
|
r"C:\Program Files (x86)\NSIS\makensis.exe",
|
||
|
|
r"C:\Program Files\NSIS\makensis.exe",
|
||
|
|
]
|
||
|
|
|
||
|
|
makensis = None
|
||
|
|
for path in makensis_paths:
|
||
|
|
if os.path.exists(path):
|
||
|
|
makensis = path
|
||
|
|
break
|
||
|
|
|
||
|
|
if not makensis:
|
||
|
|
# 尝试从环境变量查找
|
||
|
|
result = subprocess.run("where makensis", shell=True, capture_output=True, text=True)
|
||
|
|
if result.returncode == 0:
|
||
|
|
makensis = result.stdout.strip().split('\n')[0]
|
||
|
|
|
||
|
|
if not makensis:
|
||
|
|
print(" [跳过] 未找到 NSIS (makensis.exe),请安装 NSIS")
|
||
|
|
return
|
||
|
|
|
||
|
|
print(f" - 使用 NSIS: {makensis}")
|
||
|
|
|
||
|
|
# 执行 NSIS 编译
|
||
|
|
cmd = f'"{makensis}" "{NSIS_SCRIPT}"'
|
||
|
|
result = run_command(cmd, check=False)
|
||
|
|
|
||
|
|
if result.returncode == 0:
|
||
|
|
print(" - NSIS 安装包构建成功")
|
||
|
|
# 查找生成的安装包
|
||
|
|
installer = PROJECT_DIR / "GPCT-standalone-Setup.exe"
|
||
|
|
if installer.exists():
|
||
|
|
print(f" - 安装包位置: {installer}")
|
||
|
|
else:
|
||
|
|
print(f" [警告] NSIS 构建可能失败: {result.stderr}")
|
||
|
|
|
||
|
|
def verify_build():
|
||
|
|
"""验证构建结果"""
|
||
|
|
print("\n[6/6] 验证构建结果...")
|
||
|
|
|
||
|
|
exe_path = DIST_DIR / "GPCT-standalone" / "GPCT-standalone.exe"
|
||
|
|
|
||
|
|
if exe_path.exists():
|
||
|
|
size = exe_path.stat().st_size / (1024 * 1024) # MB
|
||
|
|
print(f" - 可执行文件: {exe_path}")
|
||
|
|
print(f" - 文件大小: {size:.2f} MB")
|
||
|
|
|
||
|
|
# 检查关键文件
|
||
|
|
internal_dir = DIST_DIR / "GPCT-standalone" / "_internal"
|
||
|
|
critical_files = [
|
||
|
|
"config.json",
|
||
|
|
"data.db",
|
||
|
|
"Syunew3D_x64.dll"
|
||
|
|
]
|
||
|
|
|
||
|
|
print(" - 关键文件检查:")
|
||
|
|
for file in critical_files:
|
||
|
|
file_path = internal_dir / file
|
||
|
|
if file_path.exists():
|
||
|
|
print(f" [OK] {file}")
|
||
|
|
else:
|
||
|
|
print(f" [缺失] {file}")
|
||
|
|
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
print(f" [错误] 未找到可执行文件: {exe_path}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""主函数"""
|
||
|
|
print("=" * 50)
|
||
|
|
print(" GPCT-standalone 自动打包脚本")
|
||
|
|
print("=" * 50)
|
||
|
|
|
||
|
|
# 检查项目目录
|
||
|
|
if not PROJECT_DIR.exists():
|
||
|
|
print(f"[错误] 项目目录不存在: {PROJECT_DIR}")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# 执行构建步骤
|
||
|
|
clean_build()
|
||
|
|
update_version()
|
||
|
|
build_with_pyinstaller()
|
||
|
|
copy_additional_files()
|
||
|
|
build_nsis_installer()
|
||
|
|
success = verify_build()
|
||
|
|
|
||
|
|
print("\n" + "=" * 50)
|
||
|
|
if success:
|
||
|
|
print(" 打包完成!")
|
||
|
|
print(f" 输出目录: {DIST_DIR / 'GPCT-standalone'}")
|
||
|
|
else:
|
||
|
|
print(" 打包过程中出现错误")
|
||
|
|
print("=" * 50)
|
||
|
|
|
||
|
|
return 0 if success else 1
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
sys.exit(main())
|