feat: 完成macOS应用打包功能
This commit is contained in:
171
build.py
171
build.py
@@ -1,9 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import warnings
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import time
|
||||
import threading
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Ignore specific SyntaxWarning
|
||||
warnings.filterwarnings("ignore", category=SyntaxWarning, module="DrissionPage")
|
||||
@@ -79,6 +85,169 @@ def filter_output(output):
|
||||
return "\n".join(important_lines)
|
||||
|
||||
|
||||
def increment_version():
|
||||
"""增加构建版本号"""
|
||||
version_file = Path("version.json")
|
||||
if version_file.exists():
|
||||
with open(version_file, "r") as f:
|
||||
version_data = json.load(f)
|
||||
|
||||
# 增加构建号
|
||||
version_data["build"] += 1
|
||||
|
||||
# 更新版本号的最后一位
|
||||
version_parts = version_data["version"].split(".")
|
||||
version_parts[-1] = str(version_data["build"])
|
||||
version_data["version"] = ".".join(version_parts)
|
||||
|
||||
# 保存更新后的版本信息
|
||||
with open(version_file, "w") as f:
|
||||
json.dump(version_data, f, indent=4)
|
||||
|
||||
return version_data
|
||||
else:
|
||||
print("错误:未找到 version.json 文件")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_icns():
|
||||
"""将 SVG 转换为 ICNS 格式"""
|
||||
if not Path("icons/logo.svg").exists():
|
||||
print("错误:未找到 logo.svg 文件")
|
||||
sys.exit(1)
|
||||
|
||||
# 创建临时目录
|
||||
os.makedirs("icons/tmp.iconset", exist_ok=True)
|
||||
|
||||
# 转换 SVG 到 PNG
|
||||
sizes = [16, 32, 64, 128, 256, 512, 1024]
|
||||
for size in sizes:
|
||||
# 普通分辨率
|
||||
os.system(f"rsvg-convert -w {size} -h {size} icons/logo.svg > icons/tmp.iconset/icon_{size}x{size}.png")
|
||||
# 高分辨率(@2x)
|
||||
if size <= 512:
|
||||
os.system(f"rsvg-convert -w {size*2} -h {size*2} icons/logo.svg > icons/tmp.iconset/icon_{size}x{size}@2x.png")
|
||||
|
||||
# 生成 icns 文件
|
||||
os.system("iconutil -c icns icons/tmp.iconset -o icons/logo.icns")
|
||||
|
||||
# 清理临时文件
|
||||
os.system("rm -rf icons/tmp.iconset")
|
||||
|
||||
|
||||
def update_spec(version_data):
|
||||
"""更新 spec 文件中的版本信息"""
|
||||
spec_content = f'''# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['cursor_gui.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
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,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='听泉Cursor助手',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=True,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon='icons/logo.icns',
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='听泉Cursor助手',
|
||||
)
|
||||
|
||||
app = BUNDLE(
|
||||
coll,
|
||||
name='听泉Cursor助手.app',
|
||||
icon='icons/logo.icns',
|
||||
bundle_identifier='com.tingquan.cursor',
|
||||
info_plist={{
|
||||
'CFBundleShortVersionString': '{version_data["version"]}',
|
||||
'CFBundleVersion': '{version_data["build"]}',
|
||||
'NSHighResolutionCapable': 'True',
|
||||
'LSMinimumSystemVersion': '10.13.0',
|
||||
'CFBundleName': '听泉Cursor助手',
|
||||
'CFBundleDisplayName': '听泉Cursor助手',
|
||||
}},
|
||||
)'''
|
||||
|
||||
with open("cursor_app.spec", "w") as f:
|
||||
f.write(spec_content)
|
||||
|
||||
|
||||
def build_app():
|
||||
"""构建应用程序"""
|
||||
# 增加版本号
|
||||
version_data = increment_version()
|
||||
|
||||
# 创建图标
|
||||
create_icns()
|
||||
|
||||
# 更新 spec 文件
|
||||
update_spec(version_data)
|
||||
|
||||
# 更新主程序中的版本号
|
||||
update_main_version(version_data["version"])
|
||||
|
||||
# 构建应用
|
||||
os.system("pyinstaller cursor_app.spec")
|
||||
|
||||
# 创建压缩包
|
||||
os.system(f'cd dist && zip -r "听泉Cursor助手_v{version_data["version"]}.zip" "听泉Cursor助手.app"')
|
||||
|
||||
print(f"\n构建完成!版本号:v{version_data['version']}")
|
||||
print(f"应用程序位置:dist/听泉Cursor助手.app")
|
||||
print(f"压缩包位置:dist/听泉Cursor助手_v{version_data['version']}.zip")
|
||||
|
||||
|
||||
def update_main_version(version):
|
||||
"""更新主程序中的版本号"""
|
||||
with open("cursor_gui.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# 替换版本号
|
||||
content = content.replace(
|
||||
'self.setWindowTitle("Cursor账号管理器 v3.5.3")',
|
||||
f'self.setWindowTitle("听泉Cursor助手 v{version}")'
|
||||
)
|
||||
|
||||
with open("cursor_gui.py", "w") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def build():
|
||||
# Clear screen
|
||||
os.system("cls" if platform.system().lower() == "windows" else "clear")
|
||||
@@ -176,4 +345,4 @@ def build():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build()
|
||||
build_app()
|
||||
|
||||
@@ -7,6 +7,42 @@ from PyQt6.QtCore import Qt, QTimer, QPropertyAnimation
|
||||
from PyQt6.QtGui import QIcon, QPixmap
|
||||
import cursor_account_manager as backend
|
||||
from logger import logging
|
||||
import traceback
|
||||
|
||||
# 设置日志文件路径
|
||||
def setup_logging():
|
||||
try:
|
||||
# 获取应用程序所在目录
|
||||
if getattr(sys, 'frozen', False):
|
||||
# 如果是打包后的应用程序
|
||||
app_dir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
# 如果是开发环境
|
||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# 创建日志目录
|
||||
log_dir = os.path.join(app_dir, 'logs')
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
# 设置日志文件路径
|
||||
log_file = os.path.join(log_dir, 'app.log')
|
||||
|
||||
# 配置日志记录
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(log_file, encoding='utf-8'),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
|
||||
logging.info('日志系统初始化成功')
|
||||
logging.info(f'日志文件路径: {log_file}')
|
||||
|
||||
except Exception as e:
|
||||
print(f"设置日志系统时出错: {str(e)}")
|
||||
print(traceback.format_exc())
|
||||
|
||||
class SuccessDialog(QDialog):
|
||||
def __init__(self, message, parent=None):
|
||||
@@ -154,7 +190,7 @@ class PasswordDialog(QDialog):
|
||||
class CursorGUI(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("Cursor账号管理器 v3.5.3")
|
||||
self.setWindowTitle("听泉Cursor助手 v3.0.2")
|
||||
self.setFixedSize(600, 600)
|
||||
|
||||
# 设置整体样式
|
||||
@@ -488,7 +524,27 @@ class CursorGUI(QMainWindow):
|
||||
QMessageBox.information(self, "提示", "更新功能开发中")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = CursorGUI()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
try:
|
||||
# 初始化日志系统
|
||||
setup_logging()
|
||||
|
||||
# 记录启动信息
|
||||
logging.info("=== 应用程序启动 ===")
|
||||
logging.info(f"Python 版本: {sys.version}")
|
||||
logging.info(f"操作系统: {sys.platform}")
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
window = CursorGUI()
|
||||
window.show()
|
||||
|
||||
# 捕获未处理的异常
|
||||
def handle_exception(exc_type, exc_value, exc_traceback):
|
||||
logging.error("未捕获的异常:", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
|
||||
sys.excepthook = handle_exception
|
||||
|
||||
sys.exit(app.exec())
|
||||
except Exception as e:
|
||||
logging.error(f"程序启动失败: {str(e)}")
|
||||
logging.error(traceback.format_exc())
|
||||
raise
|
||||
BIN
icons/logo.icns
Normal file
BIN
icons/logo.icns
Normal file
Binary file not shown.
14
icons/logo.svg
Normal file
14
icons/logo.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- 背景 -->
|
||||
<rect width="1024" height="1024" rx="200" fill="#1e88e5"/>
|
||||
|
||||
<!-- 水波纹效果 -->
|
||||
<path d="M312,512 Q512,412 712,512" stroke="white" stroke-width="20" fill="none" opacity="0.6"/>
|
||||
<path d="M312,562 Q512,462 712,562" stroke="white" stroke-width="15" fill="none" opacity="0.4"/>
|
||||
<path d="M312,612 Q512,512 712,612" stroke="white" stroke-width="10" fill="none" opacity="0.2"/>
|
||||
|
||||
<!-- 主文字 -->
|
||||
<text x="512" y="480" font-family="Arial" font-size="180" font-weight="bold" text-anchor="middle" fill="white">听泉</text>
|
||||
<text x="512" y="680" font-family="Arial" font-size="120" font-weight="bold" text-anchor="middle" fill="white">Cursor</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 838 B |
@@ -1,7 +1,9 @@
|
||||
DrissionPage==4.1.0.9
|
||||
colorama==0.4.6
|
||||
python-dotenv==1.0.0
|
||||
pyinstaller
|
||||
pyinstaller==6.3.0
|
||||
PyQt6==6.6.1
|
||||
PyQt6-Qt6==6.6.1
|
||||
PyQt6-sip==13.6.0
|
||||
PyQt6-sip==13.6.0
|
||||
requests==2.31.0
|
||||
urllib3==2.1.0
|
||||
4
version.json
Normal file
4
version.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version": "3.0.5",
|
||||
"build": 5
|
||||
}
|
||||
Reference in New Issue
Block a user