ArticleReplaceBatch/deepseek-clien/build.py
2025-08-06 15:57:14 +08:00

449 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
优化的EXE加密工具构建脚本
支持多种构建方式,自动处理依赖和错误恢复
"""
import os
import sys
import shutil
import subprocess
import platform
from pathlib import Path
import json
class BuildTool:
def __init__(self):
self.root_dir = Path.cwd()
self.dist_dir = self.root_dir / "dist"
self.build_dir = self.root_dir / "build"
self.temp_files = []
def cleanup(self):
"""清理临时文件和目录"""
print("🧹 清理临时文件...")
# 清理目录
dirs_to_clean = [self.build_dir, self.dist_dir]
for dir_path in dirs_to_clean:
if dir_path.exists():
try:
shutil.rmtree(dir_path)
print(f" 删除目录: {dir_path}")
except Exception as e:
print(f" 删除目录失败 {dir_path}: {e}")
# 清理临时文件
patterns = ["*.spec", "setup_*.py", "*.pyc", "*.pyo"]
for pattern in patterns:
for file_path in self.root_dir.glob(pattern):
try:
file_path.unlink()
print(f" 删除文件: {file_path}")
except Exception as e:
print(f" 删除文件失败 {file_path}: {e}")
# 清理__pycache__目录
for pycache_dir in self.root_dir.rglob("__pycache__"):
try:
shutil.rmtree(pycache_dir)
print(f" 删除缓存: {pycache_dir}")
except:
pass
def check_dependencies(self):
"""检查依赖包"""
print("📦 检查依赖包...")
required_packages = [
"mysql-connector-python",
"cryptography",
"pyperclip"
]
missing_packages = []
for package in required_packages:
try:
__import__(package.replace('-', '_'))
print(f"{package}")
except ImportError:
missing_packages.append(package)
print(f"{package}")
if missing_packages:
print(f"❌ 缺少依赖包: {', '.join(missing_packages)}")
print("正在安装缺少的依赖包...")
for package in missing_packages:
try:
subprocess.run([sys.executable, "-m", "pip", "install", package],
check=True, capture_output=True)
print(f" ✓ 安装成功: {package}")
except subprocess.CalledProcessError as e:
print(f" ✗ 安装失败: {package} - {e}")
return False
return True
def create_setup_file(self, script_name, exe_name, base_type="Console"):
"""创建setup文件"""
packages = [
"mysql.connector",
"cryptography",
"uuid",
"hashlib",
"datetime",
"platform",
"subprocess",
"json",
"tempfile",
"atexit",
"ctypes"
]
# 主程序需要额外的包
if script_name == "main.py":
packages.extend(["tkinter", "pyperclip"])
setup_content = f'''#!/usr/bin/env python3
from cx_Freeze import setup, Executable
import sys
import os
# 构建选项
build_exe_options = {{
"packages": {packages},
"include_files": [],
"excludes": ["unittest", "test", "distutils", "email"],
"build_exe": "dist_{exe_name.replace('.exe', '')}",
"optimize": 0,
"include_msvcrt": True
}}
# 如果存在配置文件,包含它
if os.path.exists("db_config.json"):
build_exe_options["include_files"].append("db_config.json")
# 可执行文件配置
executables = [
Executable(
"{script_name}",
base="{base_type}" if sys.platform == "win32" else None,
target_name="{exe_name}",
icon=None
)
]
setup(
name="{exe_name.replace('.exe', '')}",
version="2.0",
description="EXE Encryption Tool Component",
options={{"build_exe": build_exe_options}},
executables=executables
)
'''
return setup_content
def build_with_cx_freeze(self):
"""使用cx_Freeze构建"""
print("🏗️ 使用cx_Freeze构建...")
# 检查cx_Freeze
try:
import cx_Freeze
print(f" cx_Freeze版本: {cx_Freeze.version}")
except ImportError:
print(" 安装cx_Freeze...")
try:
subprocess.run([sys.executable, "-m", "pip", "install", "cx_Freeze"], check=True)
except subprocess.CalledProcessError:
print(" ❌ cx_Freeze安装失败")
return False
# 构建配置
builds = [
("validator.py", "validator.exe", "Console"),
("main.py", "EXE加密工具.exe", "Win32GUI")
]
success_count = 0
for script, exe_name, base_type in builds:
print(f" 构建 {script} -> {exe_name}")
# 创建setup文件
setup_filename = f"setup_{exe_name.replace('.exe', '').replace('EXE加密工具', 'main')}.py"
setup_content = self.create_setup_file(script, exe_name, base_type)
try:
with open(setup_filename, 'w', encoding='utf-8') as f:
f.write(setup_content)
self.temp_files.append(setup_filename)
# 执行构建
result = subprocess.run(
[sys.executable, setup_filename, "build"],
capture_output=True,
text=True,
cwd=self.root_dir
)
if result.returncode == 0:
print(f"{exe_name} 构建成功")
success_count += 1
else:
print(f"{exe_name} 构建失败:")
print(f" 错误: {result.stderr}")
except Exception as e:
print(f"{exe_name} 构建异常: {e}")
return success_count == len(builds)
def build_with_pyinstaller(self):
"""使用PyInstaller构建"""
print("🏗️ 使用PyInstaller构建...")
# 检查PyInstaller
try:
import PyInstaller
except ImportError:
print(" 安装PyInstaller...")
try:
subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], check=True)
except subprocess.CalledProcessError:
print(" ❌ PyInstaller安装失败")
return False
# 构建命令
commands = [
[
sys.executable, "-m", "PyInstaller",
"--onefile",
"--console",
"--name=validator",
"validator.py"
],
[
sys.executable, "-m", "PyInstaller",
"--onefile",
"--windowed",
"--name=EXE加密工具",
"main.py"
]
]
success_count = 0
for cmd in commands:
print(f" 执行: {' '.join(cmd)}")
try:
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root_dir)
if result.returncode == 0:
print(f" ✓ 构建成功")
success_count += 1
else:
print(f" ✗ 构建失败: {result.stderr}")
except Exception as e:
print(f" ✗ 构建异常: {e}")
return success_count == len(commands)
def organize_cx_freeze_output(self):
"""整理cx_Freeze输出"""
print("📁 整理cx_Freeze构建输出...")
# 创建最终输出目录
final_dir = self.root_dir / "dist_final"
final_dir.mkdir(exist_ok=True)
# 查找所有构建目录
dist_dirs = [d for d in self.root_dir.iterdir()
if d.is_dir() and d.name.startswith("dist_")]
if not dist_dirs:
print(" ❌ 没有找到构建输出目录")
return False
# 收集所有文件
all_files = {}
for dist_dir in dist_dirs:
print(f" 处理目录: {dist_dir}")
for file_path in dist_dir.rglob("*"):
if file_path.is_file():
# 避免重复的DLL文件保留EXE文件
if file_path.name in all_files and not file_path.suffix == '.exe':
continue
all_files[file_path.name] = file_path
# 复制文件到最终目录
for filename, filepath in all_files.items():
dest_path = final_dir / filename
try:
shutil.copy2(filepath, dest_path)
print(f" 复制: {filename}")
except Exception as e:
print(f" 复制失败 {filename}: {e}")
# 清理临时构建目录
for dist_dir in dist_dirs:
try:
shutil.rmtree(dist_dir)
except:
pass
print(f" ✓ 文件已整理到: {final_dir}")
return True
def organize_pyinstaller_output(self):
"""整理PyInstaller输出"""
print("📁 整理PyInstaller构建输出...")
dist_dir = self.root_dir / "dist"
if not dist_dir.exists():
print(" ❌ dist目录不存在")
return False
exe_files = list(dist_dir.glob("*.exe"))
if not exe_files:
print(" ❌ 没有找到可执行文件")
return False
print(f" ✓ 找到 {len(exe_files)} 个可执行文件")
for exe_file in exe_files:
print(f" {exe_file.name}")
return True
def cleanup_temp_files(self):
"""清理临时文件"""
for temp_file in self.temp_files:
try:
if os.path.exists(temp_file):
os.remove(temp_file)
except:
pass
def validate_build_output(self):
"""验证构建输出"""
print("✅ 验证构建结果...")
# 查找可执行文件
exe_files = []
# 检查cx_Freeze输出
final_dir = self.root_dir / "dist_final"
if final_dir.exists():
exe_files.extend(final_dir.glob("*.exe"))
# 检查PyInstaller输出
if not exe_files:
dist_dir = self.root_dir / "dist"
if dist_dir.exists():
exe_files.extend(dist_dir.glob("*.exe"))
if not exe_files:
print(" ❌ 没有找到可执行文件")
return False
required_exes = ["validator.exe", "EXE加密工具.exe"]
found_exes = [exe.name for exe in exe_files]
success = True
for required in required_exes:
if required in found_exes:
print(f"{required}")
else:
print(f"{required} - 未找到")
success = False
if success:
print(f" ✓ 构建验证通过,共 {len(exe_files)} 个文件")
for exe_file in exe_files:
size_mb = exe_file.stat().st_size / (1024 * 1024)
print(f" {exe_file.name}: {size_mb:.1f} MB")
return success
def build(self):
"""主构建流程"""
print("🚀 开始构建EXE加密工具...")
print(f"Python版本: {sys.version}")
print(f"操作系统: {platform.system()} {platform.release()}")
print(f"工作目录: {self.root_dir}")
try:
# 1. 清理环境
self.cleanup()
# 2. 检查依赖
if not self.check_dependencies():
return False
# 3. 尝试cx_Freeze构建
cx_success = self.build_with_cx_freeze()
if cx_success:
if self.organize_cx_freeze_output():
if self.validate_build_output():
print("🎉 cx_Freeze构建成功")
return True
print("⚠️ cx_Freeze构建失败尝试PyInstaller...")
self.cleanup()
# 4. 尝试PyInstaller构建
py_success = self.build_with_pyinstaller()
if py_success:
if self.organize_pyinstaller_output():
if self.validate_build_output():
print("🎉 PyInstaller构建成功")
return True
print("❌ 所有构建方法都失败了")
return False
except KeyboardInterrupt:
print("\n⏹️ 构建被用户中断")
return False
except Exception as e:
print(f"❌ 构建过程出现异常: {e}")
return False
finally:
# 清理临时文件
self.cleanup_temp_files()
def show_usage_info(self):
"""显示使用说明"""
print("\n📖 使用说明:")
print("1. 确保所有Python文件在同一目录")
print("2. 运行此构建脚本")
print("3. 构建完成后可执行文件将在dist或dist_final目录中")
print("4. validator.exe是验证程序用于加密过程")
print("5. EXE加密工具.exe是主程序界面")
print("\n⚠️ 注意事项:")
print("- 确保有稳定的网络连接以下载依赖包")
print("- 首次构建可能需要较长时间")
print("- 如果遇到权限问题,请以管理员身份运行")
def main():
builder = BuildTool()
if len(sys.argv) > 1 and sys.argv[1] == "--help":
builder.show_usage_info()
return
success = builder.build()
if success:
print("\n🎊 构建完成!")
builder.show_usage_info()
else:
print("\n💥 构建失败!")
print("请检查错误信息并解决相关问题")
sys.exit(1)
if __name__ == "__main__":
main()