You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Curriculum_Design/build_v1.0.py

331 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/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)