2025-09-17 17:48:35 +08:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
"""
|
|
|
|
|
|
快速打包脚本 - 避免spec文件缩进问题
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
import shutil
|
2025-09-28 17:00:02 +08:00
|
|
|
|
from pathlib import Path
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-10-13 14:58:56 +08:00
|
|
|
|
# Build optimization: Control whether to force full clean
|
|
|
|
|
|
# Set environment variable FORCE_FULL_CLEAN=true to clean both dist and build directories
|
|
|
|
|
|
# Default: false (incremental build, faster)
|
|
|
|
|
|
FORCE_FULL_CLEAN = os.getenv('FORCE_FULL_CLEAN', 'false').lower() == 'true'
|
|
|
|
|
|
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
def clean_build():
|
|
|
|
|
|
"""清理构建目录"""
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Cleaning old build files...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 跳过进程结束步骤,避免影响当前脚本运行
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Skipping process termination step...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 等待少量时间确保文件句柄释放
|
|
|
|
|
|
import time
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Waiting for file handles to release...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
time.sleep(0.5)
|
|
|
|
|
|
|
2025-10-13 14:58:56 +08:00
|
|
|
|
# Build optimization: Preserve build cache for faster incremental builds
|
|
|
|
|
|
# The build directory contains PyInstaller analysis cache
|
|
|
|
|
|
# Preserving it can reduce build time from ~7min to ~3min
|
|
|
|
|
|
if FORCE_FULL_CLEAN:
|
|
|
|
|
|
dirs_to_clean = ['dist', 'build']
|
|
|
|
|
|
print("FORCE_FULL_CLEAN enabled - cleaning all directories including build cache")
|
|
|
|
|
|
else:
|
|
|
|
|
|
dirs_to_clean = ['dist']
|
|
|
|
|
|
print("Incremental build mode - preserving build cache for faster builds")
|
|
|
|
|
|
|
2025-10-13 15:18:39 +08:00
|
|
|
|
# Always remove spec file to ensure PyInstaller regenerates it from command-line args
|
|
|
|
|
|
spec_file = 'MultiPlatformGUI.spec'
|
|
|
|
|
|
if os.path.exists(spec_file):
|
|
|
|
|
|
try:
|
|
|
|
|
|
os.remove(spec_file)
|
|
|
|
|
|
print(f"Removed old spec file: {spec_file}")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"WARNING: Failed to remove spec file: {e}")
|
|
|
|
|
|
|
2025-09-17 17:48:35 +08:00
|
|
|
|
for dir_name in dirs_to_clean:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Checking directory: {dir_name}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if os.path.exists(dir_name):
|
|
|
|
|
|
try:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Deleting: {dir_name}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
shutil.rmtree(dir_name)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Deleted: {dir_name}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except PermissionError as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"WARNING: {dir_name} is in use, attempting force delete... Error: {e}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
try:
|
|
|
|
|
|
subprocess.run(['rd', '/s', '/q', dir_name],
|
|
|
|
|
|
shell=True, check=True)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Force delete successful: {dir_name}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except Exception as e2:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"ERROR: Cannot delete {dir_name}: {e2}")
|
|
|
|
|
|
print("TIP: Please delete manually or run force_clean_dist.bat")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except Exception as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"ERROR: Failed to delete {dir_name}: {e}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"INFO: {dir_name} does not exist, skipping")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Cleaning phase completed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_with_command():
|
|
|
|
|
|
"""使用命令行参数直接打包"""
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Starting build...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
cmd = [
|
|
|
|
|
|
'pyinstaller',
|
2025-10-10 16:16:36 +08:00
|
|
|
|
'--name=MultiPlatformGUI', # 直接使用最终目录名
|
2025-09-17 17:48:35 +08:00
|
|
|
|
'--onedir', # 相当于 --exclude-binaries
|
|
|
|
|
|
'--windowed', # 相当于 -w
|
2025-10-13 14:58:56 +08:00
|
|
|
|
'--noconfirm', # Build optimization: Skip confirmation prompts
|
|
|
|
|
|
'--log-level=WARN', # Build optimization: Reduce log output (only warnings and errors)
|
|
|
|
|
|
'--noupx', # Build optimization: Skip UPX compression (saves time, minimal size impact)
|
2025-09-29 16:08:16 +08:00
|
|
|
|
'--icon=static/ai_assistant_icon_64.png', # 添加主程序图标
|
2025-09-17 17:48:35 +08:00
|
|
|
|
'--add-data=config.py;.',
|
|
|
|
|
|
'--add-data=exe_file_logger.py;.',
|
2025-09-18 15:52:03 +08:00
|
|
|
|
'--add-data=windows_taskbar_fix.py;.',
|
2025-09-17 17:48:35 +08:00
|
|
|
|
'--add-data=Utils/PythonNew32;Utils/PythonNew32',
|
|
|
|
|
|
'--add-data=Utils/JD;Utils/JD',
|
|
|
|
|
|
'--add-data=Utils/Dy;Utils/Dy',
|
|
|
|
|
|
'--add-data=Utils/Pdd;Utils/Pdd',
|
|
|
|
|
|
'--add-data=Utils/QianNiu;Utils/QianNiu',
|
|
|
|
|
|
'--add-data=Utils/message_models.py;Utils',
|
|
|
|
|
|
'--add-data=Utils/__init__.py;Utils',
|
|
|
|
|
|
'--add-data=WebSocket;WebSocket',
|
|
|
|
|
|
'--add-data=static;static',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/SaiNiuApi.dll;Utils/PythonNew32',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/SaiNiuSys.dll;Utils/PythonNew32',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/SaiNiuServer.dll;Utils/PythonNew32',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/python32.exe;Utils/PythonNew32',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/python313.dll;Utils/PythonNew32',
|
|
|
|
|
|
'--add-binary=Utils/PythonNew32/vcruntime140.dll;Utils/PythonNew32',
|
|
|
|
|
|
'--hidden-import=PyQt5.QtCore',
|
|
|
|
|
|
'--hidden-import=PyQt5.QtGui',
|
|
|
|
|
|
'--hidden-import=PyQt5.QtWidgets',
|
|
|
|
|
|
'--hidden-import=websockets',
|
|
|
|
|
|
'--hidden-import=asyncio',
|
|
|
|
|
|
'--hidden-import=Utils.QianNiu.QianNiuUtils',
|
|
|
|
|
|
'--hidden-import=Utils.JD.JdUtils',
|
|
|
|
|
|
'--hidden-import=Utils.Dy.DyUtils',
|
|
|
|
|
|
'--hidden-import=Utils.Pdd.PddUtils',
|
|
|
|
|
|
'--hidden-import=WebSocket.backend_singleton',
|
|
|
|
|
|
'--hidden-import=WebSocket.BackendClient',
|
2025-09-18 15:52:03 +08:00
|
|
|
|
'--hidden-import=windows_taskbar_fix',
|
2025-09-17 17:48:35 +08:00
|
|
|
|
'main.py'
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
print(f"执行命令: {' '.join(cmd[:5])}... (共{len(cmd)}个参数)")
|
|
|
|
|
|
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
|
|
|
|
|
|
|
|
|
|
|
if result.returncode == 0:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Build successful!")
|
|
|
|
|
|
print("Build result: dist/MultiPlatformGUI/")
|
2025-10-13 15:07:00 +08:00
|
|
|
|
|
|
|
|
|
|
# Debug: List files in dist directory
|
|
|
|
|
|
if os.path.exists('dist/MultiPlatformGUI'):
|
|
|
|
|
|
print("DEBUG: Files in dist/MultiPlatformGUI/:")
|
|
|
|
|
|
for item in os.listdir('dist/MultiPlatformGUI'):
|
|
|
|
|
|
item_path = os.path.join('dist/MultiPlatformGUI', item)
|
|
|
|
|
|
if os.path.isfile(item_path):
|
|
|
|
|
|
size_mb = os.path.getsize(item_path) / 1024 / 1024
|
|
|
|
|
|
print(f" - {item} ({size_mb:.1f} MB)")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f" - {item}/ (directory)")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("WARNING: dist/MultiPlatformGUI directory does not exist!")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-10-10 16:16:36 +08:00
|
|
|
|
# 验证输出目录(不需要重命名了)
|
|
|
|
|
|
if os.path.exists('dist/MultiPlatformGUI/MultiPlatformGUI.exe'):
|
|
|
|
|
|
# PyInstaller 生成的 exe 名称是 MultiPlatformGUI.exe
|
|
|
|
|
|
# 重命名为 main.exe(保持兼容性)
|
2025-09-17 17:48:35 +08:00
|
|
|
|
try:
|
2025-10-10 16:16:36 +08:00
|
|
|
|
old_exe = 'dist/MultiPlatformGUI/MultiPlatformGUI.exe'
|
|
|
|
|
|
new_exe = 'dist/MultiPlatformGUI/main.exe'
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists(new_exe):
|
|
|
|
|
|
os.remove(new_exe)
|
2025-09-28 17:00:02 +08:00
|
|
|
|
|
2025-10-10 16:16:36 +08:00
|
|
|
|
os.rename(old_exe, new_exe)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Main executable renamed: MultiPlatformGUI.exe -> main.exe")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
|
2025-10-10 16:16:36 +08:00
|
|
|
|
exe_size = os.path.getsize(new_exe) / 1024 / 1024
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Main executable verified: main.exe ({exe_size:.1f} MB)")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except Exception as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"WARNING: Failed to rename main executable: {e}")
|
2025-10-10 16:16:36 +08:00
|
|
|
|
elif os.path.exists('dist/MultiPlatformGUI/main.exe'):
|
|
|
|
|
|
# 如果已经是 main.exe,直接验证
|
|
|
|
|
|
exe_size = os.path.getsize('dist/MultiPlatformGUI/main.exe') / 1024 / 1024
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Main executable verified: main.exe ({exe_size:.1f} MB)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("WARNING: Main executable file not found")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 创建使用说明
|
|
|
|
|
|
try:
|
|
|
|
|
|
create_usage_guide()
|
|
|
|
|
|
except:
|
|
|
|
|
|
create_usage_guide_fallback()
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: Build failed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if result.stderr:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Error messages:")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
print(result.stderr)
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"ERROR: Build process error: {e}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_usage_guide():
|
|
|
|
|
|
"""创建使用说明"""
|
|
|
|
|
|
guide_content = r"""# 多平台客服GUI使用说明
|
|
|
|
|
|
|
|
|
|
|
|
## 🚀 运行方式
|
|
|
|
|
|
```
|
|
|
|
|
|
cd dist/MultiPlatformGUI
|
|
|
|
|
|
.\main.exe
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 📝 支持平台
|
|
|
|
|
|
- 千牛 (淘宝)
|
|
|
|
|
|
- 京东 (JD)
|
|
|
|
|
|
- 抖音 (DY)
|
|
|
|
|
|
- 拼多多 (PDD)
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 特点
|
|
|
|
|
|
- 支持多平台同时监听
|
|
|
|
|
|
- 无平台间冲突
|
|
|
|
|
|
- 自动生成日志文件
|
2025-09-18 15:52:03 +08:00
|
|
|
|
- 美观的系统托盘图标
|
|
|
|
|
|
- 现代化UI界面
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
## 📁 文件结构
|
|
|
|
|
|
```
|
|
|
|
|
|
MultiPlatformGUI/
|
|
|
|
|
|
├── main.exe # 主程序
|
|
|
|
|
|
└── _internal/ # 程序依赖文件
|
2025-09-18 15:52:03 +08:00
|
|
|
|
├── static/ # 图标资源
|
|
|
|
|
|
│ ├── ai_assistant_icon_16.png
|
|
|
|
|
|
│ ├── ai_assistant_icon_32.png
|
|
|
|
|
|
│ └── ai_assistant_icon_64.png
|
2025-09-17 17:48:35 +08:00
|
|
|
|
├── Utils/
|
|
|
|
|
|
│ ├── PythonNew32/ # 千牛DLL文件
|
|
|
|
|
|
│ ├── JD/ # 京东模块
|
|
|
|
|
|
│ ├── Dy/ # 抖音模块
|
|
|
|
|
|
│ └── Pdd/ # 拼多多模块
|
|
|
|
|
|
└── ...
|
|
|
|
|
|
```
|
2025-09-18 15:52:03 +08:00
|
|
|
|
|
|
|
|
|
|
## 🔧 故障排除
|
|
|
|
|
|
1. **图标不显示**:检查 _internal/static/ 目录下的图标文件是否存在
|
|
|
|
|
|
2. **连接失败**:检查网络连接和令牌是否正确
|
|
|
|
|
|
3. **平台无响应**:查看日志文件了解详细错误信息
|
|
|
|
|
|
|
|
|
|
|
|
## 📞 技术支持
|
|
|
|
|
|
如有问题,请提供:
|
|
|
|
|
|
- 错误截图
|
|
|
|
|
|
- 具体的错误描述
|
|
|
|
|
|
- 操作步骤
|
2025-09-17 17:48:35 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open('dist/MultiPlatformGUI/使用说明.txt', 'w', encoding='utf-8') as f:
|
|
|
|
|
|
f.write(guide_content)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Usage guide file generated")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("WARNING: Usage guide generation failed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_usage_guide_fallback():
|
|
|
|
|
|
"""备用使用说明生成"""
|
|
|
|
|
|
guide_content = r"""# 多平台客服GUI使用说明
|
|
|
|
|
|
|
|
|
|
|
|
## 🚀 运行方式
|
|
|
|
|
|
```
|
|
|
|
|
|
cd dist/main
|
|
|
|
|
|
.\main.exe
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 📝 支持平台
|
|
|
|
|
|
- 千牛 (淘宝)
|
|
|
|
|
|
- 京东 (JD)
|
|
|
|
|
|
- 抖音 (DY)
|
|
|
|
|
|
- 拼多多 (PDD)
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 特点
|
|
|
|
|
|
- 支持多平台同时监听
|
|
|
|
|
|
- 无平台间冲突
|
|
|
|
|
|
- 自动生成日志文件
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open('dist/main/使用说明.txt', 'w', encoding='utf-8') as f:
|
|
|
|
|
|
f.write(guide_content)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Usage guide file generated (fallback path)")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
except:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("WARNING: Usage guide generation failed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify_result():
|
|
|
|
|
|
"""验证打包结果"""
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nVerifying build result...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-10-10 16:16:36 +08:00
|
|
|
|
# 检查MultiPlatformGUI目录(统一输出目录)
|
2025-09-28 17:00:02 +08:00
|
|
|
|
target_dir = "dist/MultiPlatformGUI"
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists(target_dir):
|
|
|
|
|
|
return _verify_directory(target_dir)
|
|
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: Build output directory not found: dist/MultiPlatformGUI")
|
|
|
|
|
|
print("TIP: Please check if PyInstaller executed successfully")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def _verify_directory(base_dir):
|
|
|
|
|
|
"""验证指定目录的打包结果"""
|
2025-10-10 16:16:36 +08:00
|
|
|
|
# 检查可能的 exe 名称
|
2025-09-28 17:00:02 +08:00
|
|
|
|
exe_path = f"{base_dir}/main.exe"
|
2025-10-10 16:16:36 +08:00
|
|
|
|
if not os.path.exists(exe_path):
|
|
|
|
|
|
exe_path = f"{base_dir}/MultiPlatformGUI.exe"
|
|
|
|
|
|
|
2025-09-28 17:00:02 +08:00
|
|
|
|
internal_dir = f"{base_dir}/_internal"
|
|
|
|
|
|
dll_path = f"{base_dir}/_internal/Utils/PythonNew32/SaiNiuApi.dll"
|
|
|
|
|
|
static_dir = f"{base_dir}/_internal/static"
|
|
|
|
|
|
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Verifying directory: {base_dir}")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
|
|
|
|
|
|
# 检查主程序
|
|
|
|
|
|
if os.path.exists(exe_path):
|
|
|
|
|
|
size = os.path.getsize(exe_path) / 1024 / 1024 # MB
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Main executable: main.exe ({size:.1f} MB)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: Main executable main.exe does not exist")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
return False
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-09-28 17:00:02 +08:00
|
|
|
|
# 检查_internal目录
|
|
|
|
|
|
if os.path.exists(internal_dir):
|
|
|
|
|
|
file_count = len([f for f in os.listdir(internal_dir) if os.path.isfile(os.path.join(internal_dir, f))])
|
|
|
|
|
|
dir_count = len([d for d in os.listdir(internal_dir) if os.path.isdir(os.path.join(internal_dir, d))])
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Dependencies directory: _internal/ ({file_count} files, {dir_count} subdirectories)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: _internal directory does not exist")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 检查关键DLL(可选)
|
|
|
|
|
|
if os.path.exists(dll_path):
|
|
|
|
|
|
dll_size = os.path.getsize(dll_path) / 1024 # KB
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"QianNiu DLL: SaiNiuApi.dll ({dll_size:.1f} KB)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("WARNING: QianNiu DLL does not exist (may be normal)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
|
|
|
|
|
|
# 检查静态资源
|
|
|
|
|
|
if os.path.exists(static_dir):
|
|
|
|
|
|
icon_files = list(Path(static_dir).glob("*.png"))
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Static resources: static/ ({len(icon_files)} icon files)")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("WARNING: static directory does not exist")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"Directory {base_dir} verification passed")
|
2025-09-28 17:00:02 +08:00
|
|
|
|
return True
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
"""主函数"""
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Multi-Platform Customer Service GUI Quick Build Tool")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 检查依赖
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Checking build dependencies...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
try:
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
result = subprocess.run(['pyinstaller', '--version'],
|
|
|
|
|
|
capture_output=True, text=True, check=False)
|
|
|
|
|
|
if result.returncode == 0:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"PyInstaller version: {result.stdout.strip()}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: PyInstaller not installed or unavailable")
|
|
|
|
|
|
print("TIP: Run: pip install pyinstaller")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
|
|
|
|
|
except Exception as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"ERROR: Failed to check PyInstaller: {e}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 清理
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nCleaning phase started...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
clean_build()
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Cleaning phase completed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 打包
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nBuild phase started...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if not build_with_command():
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: Build phase failed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Build phase completed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
# 验证
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nVerification phase started...")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if not verify_result():
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("ERROR: Verification phase failed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Verification phase completed")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 60)
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Build completed successfully!")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
2025-10-10 16:16:36 +08:00
|
|
|
|
# 显示打包结果
|
2025-09-17 17:48:35 +08:00
|
|
|
|
if os.path.exists("dist/MultiPlatformGUI"):
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("Build result: dist/MultiPlatformGUI/")
|
|
|
|
|
|
print("Run command: cd dist/MultiPlatformGUI && .\\main.exe")
|
|
|
|
|
|
print("Create installer: python installer/build_installer.py")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print(f"ERROR: Build failed: {e}")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
success = main()
|
|
|
|
|
|
if success:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nReady for testing!")
|
2025-09-17 17:48:35 +08:00
|
|
|
|
else:
|
2025-10-11 16:04:35 +08:00
|
|
|
|
print("\nERROR: Please check error messages and retry")
|