223 lines
7.0 KiB
Python
223 lines
7.0 KiB
Python
"""
|
||
更高级的打包脚本,使用 spec 文件进行更精细的控制
|
||
这个脚本会生成一个 .spec 文件并基于它进行打包
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import shutil
|
||
import subprocess
|
||
import platform
|
||
import datetime
|
||
import argparse
|
||
from pathlib import Path
|
||
|
||
def install_requirements():
|
||
"""安装必要的依赖"""
|
||
requirements = ["pyinstaller", "colorama", "requests"]
|
||
|
||
for req in requirements:
|
||
print(f"正在检查 {req}...")
|
||
try:
|
||
__import__(req)
|
||
print(f"✅ {req} 已安装")
|
||
except ImportError:
|
||
print(f"❌ {req} 未安装,正在安装...")
|
||
try:
|
||
subprocess.run([sys.executable, "-m", "pip", "install", req], check=True)
|
||
print(f"✅ {req} 安装成功")
|
||
except subprocess.SubprocessError as e:
|
||
print(f"❌ {req} 安装失败: {e}")
|
||
return False
|
||
|
||
return True
|
||
|
||
def create_spec_file(app_name):
|
||
"""创建 .spec 文件"""
|
||
print("正在创建 .spec 文件...")
|
||
|
||
# 获取当前工作目录
|
||
current_dir = os.path.abspath(os.path.dirname(__file__))
|
||
|
||
# 自动检测项目中的所有 Python 文件
|
||
python_files = []
|
||
for file in os.listdir(current_dir):
|
||
if file.endswith('.py') and file != 'package.py' and file != 'package_spec.py':
|
||
python_files.append(file)
|
||
|
||
main_script = 'cursor_pro_register.py'
|
||
if main_script not in python_files:
|
||
print(f"❌ 找不到主脚本文件 {main_script}!")
|
||
return False
|
||
|
||
# 确保 turnstilePatch 目录存在
|
||
turnstile_path = os.path.join(current_dir, 'turnstilePatch')
|
||
if not os.path.exists(turnstile_path):
|
||
print("⚠️ 警告: 找不到 turnstilePatch 目录,功能可能受限")
|
||
|
||
# 获取资源文件
|
||
datas = []
|
||
if os.path.exists(turnstile_path):
|
||
datas.append((turnstile_path, 'turnstilePatch'))
|
||
|
||
# 检查其他可能的资源文件夹
|
||
for folder in ['assets', 'config', 'data']:
|
||
folder_path = os.path.join(current_dir, folder)
|
||
if os.path.exists(folder_path) and os.path.isdir(folder_path):
|
||
datas.append((folder_path, folder))
|
||
|
||
# 确定输出文件名
|
||
output_name = app_name if app_name else "cursor动态账号注册机"
|
||
print(f"输出文件名设置为: {output_name}")
|
||
|
||
# 生成 spec 文件内容
|
||
spec_content = f"""# -*- mode: python ; coding: utf-8 -*-
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
block_cipher = None
|
||
|
||
# 收集项目文件
|
||
a = Analysis(
|
||
['{main_script}'],
|
||
pathex=['{current_dir}'],
|
||
binaries=[],
|
||
datas={datas},
|
||
hiddenimports=[
|
||
'colorama', 'requests', 'json', 'random', 'datetime', 'enum', 'dotenv',
|
||
'tkinter', 'tkinter.messagebox', 'tkinter.ttk',
|
||
'threading', 'queue', 'urllib', 'urllib.request', 'urllib.parse',
|
||
'time', 'sys', 'os', 'traceback', 'logging', 'typing', 're', 'base64',
|
||
'platform', 'collections'
|
||
],
|
||
hookspath=[],
|
||
hooksconfig={{}},
|
||
runtime_hooks=[],
|
||
excludes=[],
|
||
win_no_prefer_redirects=False,
|
||
win_private_assemblies=False,
|
||
cipher=block_cipher,
|
||
noarchive=False,
|
||
)
|
||
|
||
# 创建可执行文件
|
||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||
|
||
exe = EXE(
|
||
pyz,
|
||
a.scripts,
|
||
a.binaries,
|
||
a.zipfiles,
|
||
a.datas,
|
||
[],
|
||
name='{output_name}',
|
||
debug=False,
|
||
bootloader_ignore_signals=False,
|
||
strip=False,
|
||
upx=False,
|
||
upx_exclude=[],
|
||
runtime_tmpdir=None,
|
||
console=True,
|
||
disable_windowed_traceback=False,
|
||
argv_emulation=False,
|
||
target_arch=None,
|
||
codesign_identity=None,
|
||
entitlements_file=None,
|
||
icon=None,
|
||
)
|
||
"""
|
||
|
||
spec_file = 'cursor_pro_register.spec'
|
||
with open(spec_file, 'w', encoding='utf-8') as f:
|
||
f.write(spec_content)
|
||
|
||
print(f"✅ 已创建 {spec_file}")
|
||
return True
|
||
|
||
def build_from_spec(keep_previous, app_name):
|
||
"""从 spec 文件构建可执行文件"""
|
||
print("开始从 spec 文件构建可执行文件...")
|
||
|
||
dist_folder = "dist"
|
||
build_folder = "build"
|
||
|
||
# 如果不保留旧版本,则清除dist和build目录
|
||
if not keep_previous:
|
||
for folder in [dist_folder, build_folder]:
|
||
if os.path.exists(folder):
|
||
shutil.rmtree(folder)
|
||
print(f"已清理 {folder} 文件夹")
|
||
else:
|
||
# 确保目录存在
|
||
os.makedirs(dist_folder, exist_ok=True)
|
||
os.makedirs(build_folder, exist_ok=True)
|
||
print("将保留先前版本")
|
||
|
||
# 生成版本标识(用于区分构建文件夹)
|
||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
build_dir = os.path.join(build_folder, f"build_{timestamp}")
|
||
|
||
# 确定输出文件名
|
||
output_name = app_name if app_name else "cursor动态账号注册机"
|
||
|
||
# 构建命令
|
||
cmd = ["pyinstaller", "--workpath", build_dir, "cursor_pro_register.spec", "--clean", "--noupx"]
|
||
print(f"执行命令: {' '.join(cmd)}")
|
||
|
||
try:
|
||
# 运行 PyInstaller 使用 spec 文件
|
||
subprocess.run(cmd, check=True)
|
||
|
||
# 检查构建结果
|
||
executable_name = f"{output_name}.exe" if platform.system() == "Windows" else output_name
|
||
executable_path = os.path.join("dist", executable_name)
|
||
|
||
if os.path.exists(executable_path):
|
||
print(f"\n✅ 打包成功! 可执行文件位于: {executable_path}")
|
||
|
||
# 获取文件大小
|
||
size_bytes = os.path.getsize(executable_path)
|
||
size_mb = size_bytes / (1024 * 1024)
|
||
print(f"可执行文件大小: {size_mb:.2f} MB")
|
||
|
||
return True
|
||
else:
|
||
print(f"❌ 打包过程可能出错,找不到可执行文件: {executable_path}")
|
||
return False
|
||
|
||
except subprocess.SubprocessError as e:
|
||
print(f"❌ 打包失败: {e}")
|
||
return False
|
||
|
||
if __name__ == "__main__":
|
||
print("=" * 50)
|
||
print("Cursor Pro Register 高级打包工具")
|
||
print("=" * 50)
|
||
|
||
# 解析命令行参数
|
||
parser = argparse.ArgumentParser(description="Cursor Pro Register 高级打包工具")
|
||
parser.add_argument("app_name", nargs="?", default="cursor动态账号注册机", help="应用名称")
|
||
parser.add_argument("keep_previous", nargs="?", type=int, default=0, help="是否保留先前版本 (1=是, 0=否)")
|
||
|
||
args = parser.parse_args()
|
||
|
||
print(f"接收到的参数: 应用名称=\"{args.app_name}\", 保留旧版本={bool(args.keep_previous)}")
|
||
|
||
# 安装必要的依赖
|
||
if not install_requirements():
|
||
print("❌ 安装依赖失败,打包终止")
|
||
sys.exit(1)
|
||
|
||
# 创建 spec 文件
|
||
if not create_spec_file(args.app_name):
|
||
print("❌ 创建 spec 文件失败,打包终止")
|
||
sys.exit(1)
|
||
|
||
# 从 spec 文件构建
|
||
if build_from_spec(bool(args.keep_previous), args.app_name):
|
||
print("\n打包过程完成!")
|
||
else:
|
||
print("\n打包过程出现错误,请检查上面的日志信息")
|
||
|
||
input("按任意键退出...") |