#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ MagicWord 1.0.0 版本发布脚本 用于构建和打包应用程序,包含所有图片和图标资源 """ import os import sys import subprocess import platform import shutil import zipfile from datetime import datetime from PIL import Image def run_command(command, shell=False, cwd=None): """运行命令并返回结果""" try: result = subprocess.run(command, shell=shell, capture_output=True, text=True, encoding='utf-8', cwd=cwd) return result.returncode, result.stdout, result.stderr except Exception as e: return -1, "", str(e) def create_ico_from_png(): """从PNG图标创建ICO文件""" print("创建ICO图标文件...") # 检查是否存在256x256的PNG图标 png_path = "resources/icons/app_icon_256X256.png" ico_path = "resources/icons/app_icon.ico" if os.path.exists(png_path): try: # 打开PNG图像 img = Image.open(png_path) # 创建不同尺寸的图标 icon_sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)] # 保存为ICO格式 img.save(ico_path, format='ICO', sizes=icon_sizes) print(f"ICO图标创建成功: {ico_path}") return True except Exception as e: print(f"创建ICO图标失败: {e}") return False else: print(f"找不到PNG图标文件: {png_path}") return False def clean_build_dirs(): """清理构建目录""" print("清理构建目录...") dirs_to_clean = ['build', 'dist', '__pycache__', '*.egg-info'] for dir_name in dirs_to_clean: if '*' in dir_name: # 处理通配符 import glob for path in glob.glob(dir_name): if os.path.isdir(path): shutil.rmtree(path, ignore_errors=True) elif os.path.exists(dir_name): if os.path.isdir(dir_name): shutil.rmtree(dir_name, ignore_errors=True) else: os.remove(dir_name) # 清理src目录下的__pycache__ for root, dirs, files in os.walk('src'): for dir_name in dirs: if dir_name == '__pycache__': cache_path = os.path.join(root, dir_name) shutil.rmtree(cache_path, ignore_errors=True) print(f"清理缓存: {cache_path}") def install_dependencies(): """安装依赖""" print("安装项目依赖...") # 首先安装PIL(用于图标转换) code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "Pillow"]) if code != 0: print(f"Pillow安装失败: {stderr}") return False # 安装其他依赖 code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]) if code != 0: print(f"依赖安装失败: {stderr}") return False print("依赖安装成功") return True def build_executable(): """构建可执行文件""" print("构建可执行文件...") # 安装pyinstaller print("安装PyInstaller...") code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "pyinstaller"]) if code != 0: print(f"PyInstaller安装失败: {stderr}") return False # 创建ICO图标 create_ico_from_png() # PyInstaller命令 - 完整版本 pyinstaller_cmd = [ "pyinstaller", "--name", "MagicWord", "--version", "1.0.0", # 设置版本号为1.0.0 "--distpath", "dist", "--workpath", "build", "--specpath", ".", # 添加资源文件 "--add-data", "resources;resources", "--add-data", "resources/icons;resources/icons", "--add-data", "resources/config;resources/config", "--add-data", "resources/qss;resources/qss", "--add-data", "src;src", "--add-data", "src/ui;src/ui", "--add-data", "src/demo;src/demo", # 隐藏导入 "--hidden-import", "PyQt5", "--hidden-import", "PyQt5.QtCore", "--hidden-import", "PyQt5.QtGui", "--hidden-import", "PyQt5.QtWidgets", "--hidden-import", "requests", "--hidden-import", "beautifulsoup4", "--hidden-import", "python-docx", "--hidden-import", "PyPDF2", "--hidden-import", "ebooklib", "--hidden-import", "chardet", "--hidden-import", "PIL", "--hidden-import", "pillow", # 图标设置 "--icon", "resources/icons/app_icon.ico" if os.path.exists("resources/icons/app_icon.ico") else "resources/icons/app_icon_256X256.png", "--windowed", # 无控制台窗口 "--noconfirm", "--clean", # 清理临时文件 "src/main.py" ] print("运行PyInstaller...") code, stdout, stderr = run_command(pyinstaller_cmd) if code != 0: print(f"完整构建失败,尝试简化构建: {stderr}") # 简化版本 simple_cmd = [ "pyinstaller", "--onefile", "--windowed", "--icon=resources/icons/app_icon.ico" if os.path.exists("resources/icons/app_icon.ico") else "resources/icons/app_icon_256X256.png", "--add-data=resources;resources", "--add-data=resources/icons;resources/icons", "--add-data=src;src", "--name=MagicWord", "--version=1.0.0", "--clean", "src/main.py" ] code, stdout, stderr = run_command(simple_cmd) if code != 0: print(f"简化构建也失败: {stderr}") return False print("可执行文件构建成功") return True def create_package(): """创建发布包""" print("创建发布包...") # 检查构建结果 if platform.system() == "Windows": exe_path = "dist/MagicWord.exe" else: exe_path = "dist/MagicWord" if not os.path.exists(exe_path): print(f"错误: 找不到可执行文件 {exe_path}") return False # 创建发布目录 release_dir = "dist_package_v1.0" if os.path.exists(release_dir): shutil.rmtree(release_dir) os.makedirs(release_dir) # 复制文件到发布目录 files_to_copy = [ (exe_path, "MagicWord.exe" if platform.system() == "Windows" else "MagicWord"), ("README.md", "README.md"), ("CHANGELOG.md", "CHANGELOG.md"), ("requirements.txt", "requirements.txt"), ("install_and_fix.py", "install_and_fix.py"), ] for src, dst in files_to_copy: if os.path.exists(src): shutil.copy2(src, os.path.join(release_dir, dst)) print(f"复制: {src} -> {dst}") # 复制图标文件到发布包 icons_dir = os.path.join(release_dir, "icons") if os.path.exists("resources/icons"): shutil.copytree("resources/icons", icons_dir) print("复制图标文件到发布包") # 创建运行脚本 if platform.system() == "Windows": run_script = """@echo off echo MagicWord 1.0.0 启动中... cd /d "%~dp0" start MagicWord.exe """ with open(os.path.join(release_dir, "run.bat"), "w") as f: f.write(run_script) # 创建桌面快捷方式脚本 desktop_shortcut_script = """@echo off echo 创建桌面快捷方式... set SCRIPT_DIR=%~dp0 set DESKTOP=%USERPROFILE%\Desktop set SHORTCUT=%DESKTOP%\MagicWord.lnk powershell -Command "$WshShell = New-Object -comObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('%SHORTCUT%'); $Shortcut.TargetPath = '%SCRIPT_DIR%MagicWord.exe'; $Shortcut.WorkingDirectory = '%SCRIPT_DIR%'; $Shortcut.IconLocation = '%SCRIPT_DIR%icons\\app_icon_256X256.png'; $Shortcut.Save()" echo 桌面快捷方式创建完成! pause """ with open(os.path.join(release_dir, "create_desktop_shortcut.bat"), "w") as f: f.write(desktop_shortcut_script) else: run_script = """#!/bin/bash echo "MagicWord 1.0.0 启动中..." cd "$(dirname "$0")" ./MagicWord & """ with open(os.path.join(release_dir, "run.sh"), "w") as f: f.write(run_script) os.chmod(os.path.join(release_dir, "run.sh"), 0o755) # 创建发布说明 release_info = f"""MagicWord 1.0.0 发布包 构建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 平台: {platform.system()} {platform.machine()} Python版本: {platform.python_version()} 快速开始: 1. 运行 install_and_fix.py 安装依赖(如果需要) 2. 运行 run.bat (Windows) 或 run.sh (Linux/Mac) 3. 或直接运行 MagicWord.exe 功能特性: - 完整的文档处理功能 - 打字练习模式 - 学习模式 - 多种文档格式支持(Word, PDF, TXT等) - 美观的Word风格界面 - 完整的图标和界面资源 图标说明: - 包含完整的图标资源文件 - 支持多种尺寸的图标(32x32, 64x64, 128x128, 256x256) - Windows版本包含ICO格式图标 - 可创建桌面快捷方式 详细更新请查看 CHANGELOG.md """ with open(os.path.join(release_dir, "发布说明.txt"), "w", encoding='utf-8') as f: f.write(release_info) # 创建ZIP压缩包 print("创建ZIP压缩包...") zip_filename = f"MagicWord_v1.0.0_{platform.system()}_{platform.machine()}" with zipfile.ZipFile(f"{zip_filename}.zip", 'w', zipfile.ZIP_DEFLATED) as zipf: for root, dirs, files in os.walk(release_dir): for file in files: file_path = os.path.join(root, file) arc_path = os.path.relpath(file_path, release_dir) zipf.write(file_path, arc_path) print(f"添加到压缩包: {arc_path}") print(f"发布包创建成功: {zip_filename}.zip") return True def main(): """主函数""" print("=" * 50) print("MagicWord 1.0.0 构建脚本") print("=" * 50) # 检查Python版本 if sys.version_info < (3, 6): print("错误: 需要Python 3.6或更高版本") return False # 清理构建目录 clean_build_dirs() # 安装依赖 if not install_dependencies(): print("依赖安装失败") return False # 构建可执行文件 if not build_executable(): print("可执行文件构建失败") return False # 创建发布包 if not create_package(): print("发布包创建失败") return False print("=" * 50) print("构建完成!") print("发布包位于: dist_package_v1.0/") print("ZIP压缩包已创建") print("=" * 50) return True if __name__ == "__main__": success = main() sys.exit(0 if success else 1)