207 lines
5.7 KiB
Python
Executable File
207 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
BootRepairTool 打包脚本
|
||
使用 Python 3.9 + PyInstaller 打包
|
||
"""
|
||
|
||
import sys
|
||
import os
|
||
import subprocess
|
||
import shutil
|
||
|
||
# 需要的 Python 版本
|
||
REQUIRED_PYTHON_VERSION = (3, 9)
|
||
|
||
|
||
def check_python_version():
|
||
"""检查 Python 版本是否为 3.9"""
|
||
current = sys.version_info[:2]
|
||
if current != REQUIRED_PYTHON_VERSION:
|
||
print(f"错误: 需要使用 Python {REQUIRED_PYTHON_VERSION[0]}.{REQUIRED_PYTHON_VERSION[1]}")
|
||
print(f"当前版本: Python {current[0]}.{current[1]}")
|
||
print("\n请使用以下命令运行:")
|
||
print(f" python3.9 {sys.argv[0]}")
|
||
return False
|
||
print(f"✓ Python 版本检查通过: {sys.version.split()[0]}")
|
||
return True
|
||
|
||
|
||
def install_dependencies():
|
||
"""安装打包所需的依赖"""
|
||
print("\n[1/5] 安装依赖...")
|
||
|
||
deps = ["pyinstaller"]
|
||
|
||
for dep in deps:
|
||
print(f" 安装 {dep}...")
|
||
try:
|
||
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", dep])
|
||
print(f" ✓ {dep} 安装成功")
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" ✗ {dep} 安装失败: {e}")
|
||
return False
|
||
|
||
return True
|
||
|
||
|
||
def clean_build():
|
||
"""清理之前的构建文件"""
|
||
print("\n[2/5] 清理构建文件...")
|
||
|
||
dirs_to_remove = ["build", "dist"]
|
||
files_to_remove = ["*.pyc", "*.spec"]
|
||
|
||
for d in dirs_to_remove:
|
||
if os.path.exists(d):
|
||
shutil.rmtree(d)
|
||
print(f" 删除 {d}/")
|
||
|
||
# 清理 __pycache__
|
||
for root, dirs, files in os.walk("."):
|
||
if "__pycache__" in dirs:
|
||
pycache_path = os.path.join(root, "__pycache__")
|
||
shutil.rmtree(pycache_path)
|
||
print(f" 删除 {pycache_path}/")
|
||
|
||
print(" ✓ 清理完成")
|
||
|
||
|
||
def build_executable():
|
||
"""使用 PyInstaller 打包"""
|
||
print("\n[3/5] 开始打包...")
|
||
|
||
# 打包命令 - 输出为 .bin 文件,wrapper 脚本将调用它
|
||
cmd = [
|
||
sys.executable, "-m", "PyInstaller",
|
||
"--name=LinuxGrubRepair.bin",
|
||
"--onefile",
|
||
"--console",
|
||
"--clean",
|
||
"--noconfirm",
|
||
"frontend.py"
|
||
]
|
||
|
||
print(f" 执行: {' '.join(cmd)}")
|
||
|
||
try:
|
||
subprocess.check_call(cmd)
|
||
print(" ✓ 打包成功")
|
||
return True
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" ✗ 打包失败: {e}")
|
||
return False
|
||
|
||
|
||
def create_launcher():
|
||
"""创建启动器脚本,解决 X11 字体渲染问题"""
|
||
print("\n[4/5] 创建启动器脚本...")
|
||
|
||
launcher_content = '''#!/bin/bash
|
||
# ==============================================================================
|
||
# BootRepairTool 启动脚本
|
||
# 解决 Arch Linux 等系统上的 X11 字体渲染问题
|
||
# ==============================================================================
|
||
|
||
# 获取脚本实际所在目录(处理软链接情况)
|
||
SCRIPT_SOURCE="${BASH_SOURCE[0]}"
|
||
while [ -L "$SCRIPT_SOURCE" ]; do
|
||
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
||
SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
|
||
[[ $SCRIPT_SOURCE != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
|
||
done
|
||
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
||
|
||
# 如果是从 /bin 软链接启动,则使用实际安装目录
|
||
if [ "$SCRIPT_DIR" = "/bin" ] || [ "$SCRIPT_DIR" = "/usr/bin" ]; then
|
||
SCRIPT_DIR="/opt/boot-repair-tool"
|
||
fi
|
||
|
||
# 设置字体渲染环境变量,解决 "BadLength (poly request too large)" 错误
|
||
export XLIB_SKIP_ARGB_VISUALS=1
|
||
|
||
# 禁用某些 X11 RENDER 扩展功能
|
||
export GDK_NATIVE_WINDOWS=1
|
||
|
||
# 设置 tkinter 使用基本字体渲染
|
||
export TCL_DONT_USE_RENDER_EXTENSION=1
|
||
|
||
# 如果使用 Wayland,强制使用 XWayland
|
||
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
|
||
export GDK_BACKEND=x11
|
||
fi
|
||
|
||
# 执行实际程序
|
||
exec "${SCRIPT_DIR}/LinuxGrubRepair.bin" "$@"
|
||
'''
|
||
|
||
dist_path = os.path.join(os.getcwd(), "dist")
|
||
launcher_path = os.path.join(dist_path, "LinuxGrubRepair")
|
||
|
||
with open(launcher_path, 'w') as f:
|
||
f.write(launcher_content)
|
||
|
||
# 设置可执行权限
|
||
os.chmod(launcher_path, 0o755)
|
||
print(f" ✓ 启动器创建完成: {launcher_path}")
|
||
return True
|
||
|
||
|
||
def show_result():
|
||
"""显示打包结果"""
|
||
print("\n[5/5] 打包完成!")
|
||
|
||
dist_path = os.path.join(os.getcwd(), "dist")
|
||
launcher_name = "LinuxGrubRepair"
|
||
bin_name = "LinuxGrubRepair.bin"
|
||
launcher_path = os.path.join(dist_path, launcher_name)
|
||
bin_path = os.path.join(dist_path, bin_name)
|
||
|
||
if os.path.exists(launcher_path) and os.path.exists(bin_path):
|
||
bin_size = os.path.getsize(bin_path)
|
||
bin_size_mb = bin_size / (1024 * 1024)
|
||
print(f"\n 启动器: {launcher_path}")
|
||
print(f" 程序文件: {bin_path}")
|
||
print(f" 文件大小: {bin_size_mb:.2f} MB")
|
||
print("\n 使用方式:")
|
||
print(f" sudo ./{launcher_name}")
|
||
print("\n 注意: 启动器脚本已配置 X11 环境变量,可解决字体渲染问题")
|
||
else:
|
||
print(" 未找到生成的文件")
|
||
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("=" * 50)
|
||
print("BootRepairTool 打包脚本")
|
||
print("=" * 50)
|
||
|
||
# 检查 Python 版本
|
||
if not check_python_version():
|
||
sys.exit(1)
|
||
|
||
# 安装依赖
|
||
if not install_dependencies():
|
||
print("依赖安装失败")
|
||
sys.exit(1)
|
||
|
||
# 清理旧构建
|
||
clean_build()
|
||
|
||
# 打包
|
||
if not build_executable():
|
||
print("打包失败")
|
||
sys.exit(1)
|
||
|
||
# 创建启动器
|
||
if not create_launcher():
|
||
print("创建启动器失败")
|
||
sys.exit(1)
|
||
|
||
# 显示结果
|
||
show_result()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|