fix bug 打包
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build/
|
||||
/__pycache__/
|
||||
38
LinuxGrubRepair.spec
Normal file
38
LinuxGrubRepair.spec
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['frontend.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='LinuxGrubRepair',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
Binary file not shown.
Binary file not shown.
683
backend.py
683
backend.py
@@ -1340,22 +1340,7 @@ def _manual_install_efi_files(mount_point: str, efi_target: str, efi_grub_file:
|
||||
modules = "part_gpt part_msdos fat ext2 xfs btrfs normal boot linux configfile search search_fs_uuid search_fs_file"
|
||||
|
||||
# 构建 chroot 内的输出路径
|
||||
chroot_output_path = f"/boot/efi/EFI/{bootloader_id}/{efi_grub_file}"
|
||||
|
||||
# 检测是否有独立的 /boot 分区
|
||||
has_separate_boot = os.path.ismount(os.path.join(mount_point, "boot"))
|
||||
|
||||
# 确定正确的 prefix
|
||||
# 对于独立 /boot 分区,使用 '(<device>)/grub2' 格式,让 GRUB 自动搜索
|
||||
# 或者使用 '/boot/grub2' 配合 search 命令
|
||||
if has_separate_boot:
|
||||
# 独立 /boot 分区:使用相对路径,依赖 grub.cfg 中的 search 命令
|
||||
# 或者使用 '(,gpt2)/grub2' 格式指定分区
|
||||
grub_prefix = "/grub2"
|
||||
log_info(f"检测到独立 /boot 分区,使用 prefix: {grub_prefix}")
|
||||
else:
|
||||
grub_prefix = "/boot/grub2"
|
||||
log_info(f"使用标准 prefix: {grub_prefix}")
|
||||
chroot_output_path = f"/boot/efi/EFI/{efi_bootloader_id}/{efi_grub_file}"
|
||||
|
||||
# 尝试使用 grub-mkimage 生成 EFI 文件
|
||||
chroot_cmd_prefix = ["sudo", "chroot", mount_point]
|
||||
@@ -1363,7 +1348,7 @@ def _manual_install_efi_files(mount_point: str, efi_target: str, efi_grub_file:
|
||||
"grub2-mkimage",
|
||||
"-o", chroot_output_path,
|
||||
"-O", efi_target,
|
||||
"-p", grub_prefix,
|
||||
"-p", "/boot/grub2",
|
||||
] + modules.split()
|
||||
|
||||
success, _, stderr = run_command(
|
||||
@@ -1376,52 +1361,6 @@ def _manual_install_efi_files(mount_point: str, efi_target: str, efi_grub_file:
|
||||
host_output_path = os.path.join(mount_point, chroot_output_path.lstrip('/'))
|
||||
if success and os.path.exists(host_output_path):
|
||||
log_success(f"✓ 成功生成 EFI 文件: {host_output_path}")
|
||||
|
||||
# 对于独立 /boot 分区,创建辅助配置
|
||||
if has_separate_boot:
|
||||
log_info("为独立 /boot 分区创建辅助配置...")
|
||||
|
||||
# 获取 /boot 分区的 UUID
|
||||
boot_uuid = None
|
||||
try:
|
||||
success_uuid, uuid_out, _ = run_command(
|
||||
["sudo", "blkid", "-s", "UUID", "-o", "value", f"{mount_point}/boot"],
|
||||
"获取 /boot 分区 UUID",
|
||||
timeout=10
|
||||
)
|
||||
if success_uuid:
|
||||
boot_uuid = uuid_out.strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 创建 EFI 分区上的 grub.cfg(GRUB 首先查找这里)
|
||||
helper_cfg_path = os.path.join(mount_point, f"boot/efi/EFI/{bootloader_id}/grub.cfg")
|
||||
try:
|
||||
# 使用通用 search --file 方法
|
||||
helper_cfg = '''# BootRepairTool - Auto-find /boot partition
|
||||
# Try to find grub2/grub.cfg on any partition
|
||||
|
||||
if search --no-floppy --set=root --file /grub2/grub.cfg; then
|
||||
set prefix=($root)/grub2
|
||||
elif search --no-floppy --set=root --file /grub/grub.cfg; then
|
||||
set prefix=($root)/grub
|
||||
elif search --no-floppy --set=root --file /boot/grub2/grub.cfg; then
|
||||
set prefix=($root)/boot/grub2
|
||||
elif search --no-floppy --set=root --file /boot/grub/grub.cfg; then
|
||||
set prefix=($root)/boot/grub
|
||||
fi
|
||||
|
||||
if [ -n "$root" ] && [ -n "$prefix" ]; then
|
||||
configfile ${prefix}/grub.cfg
|
||||
else
|
||||
echo "Error: Could not find grub.cfg"
|
||||
fi
|
||||
'''
|
||||
with open(helper_cfg_path, 'w') as f:
|
||||
f.write(helper_cfg)
|
||||
log_success(f"✓ 创建 EFI 辅助 grub.cfg: {helper_cfg_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"创建辅助 grub.cfg 失败: {e}")
|
||||
else:
|
||||
log_error(f"生成 EFI 文件失败: {stderr}")
|
||||
return False
|
||||
@@ -1515,54 +1454,6 @@ def install_efi_fallback(mount_point: str, efi_target: str, efi_grub_file: str,
|
||||
try:
|
||||
shutil.copy2(source_file, target_file)
|
||||
log_success(f"✓ EFI fallback 安装成功: {source_file} -> {target_file}")
|
||||
|
||||
# 为 fallback 创建 grub.cfg(独立 /boot 分区时需要)
|
||||
has_separate_boot = os.path.ismount(os.path.join(mount_point, "boot"))
|
||||
if has_separate_boot:
|
||||
log_info("检测到独立 /boot 分区,为 fallback 创建 grub.cfg...")
|
||||
|
||||
# 获取 /boot 分区 UUID
|
||||
boot_uuid = None
|
||||
try:
|
||||
success_uuid, uuid_out, _ = run_command(
|
||||
["sudo", "blkid", "-s", "UUID", "-o", "value", f"{mount_point}/boot"],
|
||||
"获取 /boot UUID for fallback",
|
||||
timeout=10
|
||||
)
|
||||
if success_uuid:
|
||||
boot_uuid = uuid_out.strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 在 Boot 目录创建 grub.cfg
|
||||
fallback_cfg_path = os.path.join(boot_dir, "grub.cfg")
|
||||
try:
|
||||
# 使用通用 search --file 方法
|
||||
fallback_cfg = '''# BootRepairTool - Auto-find /boot partition
|
||||
# Try to find grub2/grub.cfg on any partition
|
||||
|
||||
if search --no-floppy --set=root --file /grub2/grub.cfg; then
|
||||
set prefix=($root)/grub2
|
||||
elif search --no-floppy --set=root --file /grub/grub.cfg; then
|
||||
set prefix=($root)/grub
|
||||
elif search --no-floppy --set=root --file /boot/grub2/grub.cfg; then
|
||||
set prefix=($root)/boot/grub2
|
||||
elif search --no-floppy --set=root --file /boot/grub/grub.cfg; then
|
||||
set prefix=($root)/boot/grub
|
||||
fi
|
||||
|
||||
if [ -n "$root" ] && [ -n "$prefix" ]; then
|
||||
configfile ${prefix}/grub.cfg
|
||||
else
|
||||
echo "Error: Could not find grub.cfg"
|
||||
fi
|
||||
'''
|
||||
with open(fallback_cfg_path, 'w') as f:
|
||||
f.write(fallback_cfg)
|
||||
log_success(f"✓ 创建 fallback grub.cfg: {fallback_cfg_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"创建 fallback grub.cfg 失败: {e}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
log_error(f"复制 EFI fallback 文件失败: {e}")
|
||||
@@ -1729,61 +1620,17 @@ def check_and_restore_kernel(mount_point: str, distro_type: str, has_separate_bo
|
||||
)
|
||||
elif distro_type in ["arch", "manjaro"]:
|
||||
# Arch 使用 mkinitcpio
|
||||
# 首先检查是否有 preset 文件
|
||||
preset_path = os.path.join(mount_point, f"etc/mkinitcpio.d/{kernel_ver}.preset")
|
||||
|
||||
if os.path.exists(preset_path):
|
||||
# 使用 preset 生成
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + ["mkinitcpio", "-p", kernel_ver],
|
||||
f"生成 initramfs for {kernel_ver}",
|
||||
timeout=120
|
||||
)
|
||||
else:
|
||||
# 没有 preset 文件,直接生成 initramfs
|
||||
log_warning(f"没有找到 preset 文件,使用直接生成模式")
|
||||
initramfs_path = f"/boot/initramfs-{kernel_ver}.img"
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + ["mkinitcpio", "-g", initramfs_path, "-k", kernel_ver],
|
||||
f"直接生成 initramfs for {kernel_ver}",
|
||||
timeout=120
|
||||
)
|
||||
|
||||
# 如果直接生成失败,尝试创建临时 preset
|
||||
if not success:
|
||||
log_info("尝试创建临时 preset 文件...")
|
||||
try:
|
||||
preset_dir = os.path.join(mount_point, "etc/mkinitcpio.d")
|
||||
os.makedirs(preset_dir, exist_ok=True)
|
||||
|
||||
# 创建基本 preset 文件
|
||||
preset_content = f"""# mkinitcpio preset file for {kernel_ver}
|
||||
ALL_config="/etc/mkinitcpio.conf"
|
||||
ALL_kver="{kernel_ver}"
|
||||
|
||||
PRESETS=('default')
|
||||
|
||||
default_image="/boot/initramfs-{kernel_ver}.img"
|
||||
"""
|
||||
with open(preset_path, 'w') as f:
|
||||
f.write(preset_content)
|
||||
log_info(f"✓ 创建临时 preset: {preset_path}")
|
||||
|
||||
# 再次尝试使用 preset 生成
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + ["mkinitcpio", "-p", kernel_ver],
|
||||
f"使用临时 preset 生成 initramfs for {kernel_ver}",
|
||||
timeout=120
|
||||
)
|
||||
except Exception as e:
|
||||
log_warning(f"创建临时 preset 失败: {e}")
|
||||
else:
|
||||
# 通用方法:尝试 dracut
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + ["dracut", "-f", f"/boot/initramfs-{kernel_ver}.img", kernel_ver],
|
||||
f"生成 initramfs for {kernel_ver}",
|
||||
timeout=120
|
||||
|
||||
)
|
||||
|
||||
if success:
|
||||
@@ -1829,11 +1676,6 @@ def restore_bls_entries(mount_point: str, distro_type: str) -> Tuple[bool, str]:
|
||||
except Exception as e:
|
||||
log_debug(f"检查 BLS 失败: {e}")
|
||||
|
||||
# 对于 CentOS/RHEL/Fedora 8+,强制使用 BLS(即使 grub.cfg 不存在或被清空)
|
||||
if not uses_bls and distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux"]:
|
||||
log_info(f"{distro_type} 8+ 默认使用 BLS,启用 BLS 恢复")
|
||||
uses_bls = True
|
||||
|
||||
if not uses_bls:
|
||||
log_debug("系统不使用 BLS,跳过 BLS 恢复")
|
||||
return True, ""
|
||||
@@ -2103,80 +1945,6 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
|
||||
grub_install_success = False
|
||||
install_errors = []
|
||||
|
||||
# ===== 清空并重建 GRUB 环境(针对严重损坏的系统)=====
|
||||
# 这个步骤在 UEFI 和 BIOS 模式下都需要
|
||||
log_step("清空并重建 GRUB 环境")
|
||||
|
||||
# 确定正确的 GRUB 目录名
|
||||
if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux", "opensuse"]:
|
||||
grub_dir_name = "grub2"
|
||||
else:
|
||||
grub_dir_name = "grub"
|
||||
|
||||
# 1. 检查并恢复 GRUB 模块(从系统包中)
|
||||
log_info("检查 GRUB EFI 模块...")
|
||||
grub_modules_dir = os.path.join(mount_point, f"usr/lib/grub/x86_64-efi")
|
||||
boot_grub_mods = os.path.join(mount_point, "boot", grub_dir_name, "x86_64-efi")
|
||||
|
||||
if os.path.exists(grub_modules_dir):
|
||||
log_info(f"✓ 系统模块目录: {grub_modules_dir}")
|
||||
# 确保 /boot/grub2/x86_64-efi 存在且包含模块
|
||||
if not os.path.exists(boot_grub_mods) or len(os.listdir(boot_grub_mods)) < 10:
|
||||
log_info("复制 GRUB 模块到 /boot...")
|
||||
try:
|
||||
import shutil
|
||||
if os.path.exists(boot_grub_mods):
|
||||
shutil.rmtree(boot_grub_mods)
|
||||
shutil.copytree(grub_modules_dir, boot_grub_mods)
|
||||
mod_count = len(os.listdir(boot_grub_mods))
|
||||
log_success(f"✓ 复制 {mod_count} 个模块到 {boot_grub_mods}")
|
||||
except Exception as e:
|
||||
log_warning(f"复制模块失败: {e}")
|
||||
|
||||
# 2. 清空 /boot/grub* 目录中的配置和临时文件(保留模块和字体)
|
||||
boot_grub_paths = [
|
||||
os.path.join(mount_point, "boot", "grub"),
|
||||
os.path.join(mount_point, "boot", "grub2"),
|
||||
]
|
||||
for grub_path in boot_grub_paths:
|
||||
if os.path.exists(grub_path):
|
||||
log_info(f"清理目录: {grub_path}")
|
||||
try:
|
||||
# 只删除配置文件和临时文件,保留 x86_64-efi 目录和字体
|
||||
preserve_dirs = {"x86_64-efi", "i386-pc", "fonts", "locale"}
|
||||
for item in os.listdir(grub_path):
|
||||
if item in preserve_dirs:
|
||||
continue
|
||||
item_path = os.path.join(grub_path, item)
|
||||
if os.path.isfile(item_path) or os.path.islink(item_path):
|
||||
os.unlink(item_path)
|
||||
log_debug(f" 删除文件: {item}")
|
||||
elif os.path.isdir(item_path):
|
||||
import shutil
|
||||
shutil.rmtree(item_path)
|
||||
log_debug(f" 删除目录: {item}")
|
||||
log_success(f"✓ 已清理: {grub_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"清理失败: {e}")
|
||||
|
||||
# 3. 创建 grubenv 文件(普通文件,不是符号链接)
|
||||
# GRUB2 要求环境块精确为 4096 字节(一个扇区)
|
||||
grubenv_path = os.path.join(mount_point, "boot", grub_dir_name, "grubenv")
|
||||
try:
|
||||
# 构建 4096 字节的 grubenv 内容
|
||||
header = "# GRUB Environment Block\n"
|
||||
saved_entry = "saved_entry=\n"
|
||||
# 计算需要填充的字节数(4096 - header - saved_entry - 结尾的 #)
|
||||
padding_size = 4096 - len(header) - len(saved_entry) - 1
|
||||
content = header + saved_entry + "#" * padding_size
|
||||
with open(grubenv_path, 'w') as f:
|
||||
f.write(content)
|
||||
log_success(f"✓ 创建 grubenv ({os.path.getsize(grubenv_path)} 字节): {grubenv_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"创建 grubenv 失败: {e}")
|
||||
|
||||
log_success("✓ GRUB 环境重建完成")
|
||||
|
||||
# ===== UEFI 安装 =====
|
||||
if is_uefi or install_hybrid:
|
||||
log_step("安装 UEFI GRUB")
|
||||
@@ -2193,75 +1961,6 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
|
||||
else:
|
||||
log_warning(f"✗ EFI 目录不存在: {efi_check_path}")
|
||||
|
||||
# ===== 清空 EFI 分区并重建(UEFI 模式特有)=====
|
||||
log_step("清空 EFI 分区并重建")
|
||||
|
||||
# 1. 清空 EFI 分区中的 GRUB 相关目录
|
||||
efi_cleanup_dirs = ["GRUB", "grub", "Boot", "boot", "centos", "redhat", "fedora"]
|
||||
for efi_dir in efi_cleanup_dirs:
|
||||
efi_dir_path = os.path.join(mount_point, "boot/efi/EFI", efi_dir)
|
||||
if os.path.exists(efi_dir_path):
|
||||
log_info(f"清空 EFI 目录: {efi_dir_path}")
|
||||
try:
|
||||
import shutil
|
||||
shutil.rmtree(efi_dir_path)
|
||||
log_success(f"✓ 已删除: {efi_dir_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"删除失败: {e}")
|
||||
|
||||
# 2. 重建 EFI 目录结构
|
||||
log_info("重建 EFI 目录结构...")
|
||||
dirs_to_create = [
|
||||
os.path.join(mount_point, "boot/efi/EFI", efi_bootloader_id),
|
||||
os.path.join(mount_point, "boot/efi/EFI", "Boot"),
|
||||
]
|
||||
for dir_path in dirs_to_create:
|
||||
try:
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
log_info(f"✓ 创建目录: {dir_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"创建目录失败: {e}")
|
||||
|
||||
log_success("✓ GRUB 环境重建完成")
|
||||
|
||||
# 5. 为独立 /boot 分区创建 EFI 辅助 grub.cfg
|
||||
has_separate_boot = os.path.ismount(os.path.join(mount_point, "boot"))
|
||||
if has_separate_boot:
|
||||
log_info("为独立 /boot 分区创建 EFI 辅助 grub.cfg...")
|
||||
|
||||
# 为每个 EFI 目录创建 grub.cfg(使用通用搜索方法)
|
||||
for efi_dir in [efi_bootloader_id, "Boot"]:
|
||||
efi_cfg_dir = os.path.join(mount_point, "boot/efi/EFI", efi_dir)
|
||||
if os.path.exists(efi_cfg_dir):
|
||||
efi_cfg_path = os.path.join(efi_cfg_dir, "grub.cfg")
|
||||
try:
|
||||
# 使用 search --file 通用搜索方法
|
||||
efi_cfg_content = '''# BootRepairTool - Auto-find /boot partition
|
||||
# Try to find grub2/grub.cfg on any partition
|
||||
|
||||
if search --no-floppy --set=root --file /grub2/grub.cfg; then
|
||||
set prefix=($root)/grub2
|
||||
elif search --no-floppy --set=root --file /grub/grub.cfg; then
|
||||
set prefix=($root)/grub
|
||||
elif search --no-floppy --set=root --file /boot/grub2/grub.cfg; then
|
||||
set prefix=($root)/boot/grub2
|
||||
elif search --no-floppy --set=root --file /boot/grub/grub.cfg; then
|
||||
set prefix=($root)/boot/grub
|
||||
fi
|
||||
|
||||
if [ -n "$root" ] && [ -n "$prefix" ]; then
|
||||
configfile ${prefix}/grub.cfg
|
||||
else
|
||||
echo "Error: Could not find grub.cfg on any partition."
|
||||
echo "Please check your /boot partition."
|
||||
fi
|
||||
'''
|
||||
with open(efi_cfg_path, 'w') as f:
|
||||
f.write(efi_cfg_content)
|
||||
log_success(f"✓ 创建 {efi_dir}/grub.cfg (通用搜索)")
|
||||
except Exception as e:
|
||||
log_warning(f" 创建失败: {e}")
|
||||
|
||||
grub_install_cmd = chroot_cmd_prefix + [
|
||||
_grub_install_cmd,
|
||||
f"--target={efi_target}",
|
||||
@@ -2437,32 +2136,20 @@ fi
|
||||
log_step("更新 GRUB 配置文件")
|
||||
|
||||
# 确定配置文件路径
|
||||
# 根据发行版类型确定正确的 GRUB 目录名
|
||||
if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux", "opensuse"]:
|
||||
# RHEL 系使用 grub2
|
||||
preferred_grub_dir = "grub2"
|
||||
fallback_grub_dir = "grub"
|
||||
else:
|
||||
# Debian/Ubuntu/Arch 等使用 grub
|
||||
preferred_grub_dir = "grub"
|
||||
fallback_grub_dir = "grub2"
|
||||
|
||||
possible_config_paths = [
|
||||
f"/boot/{preferred_grub_dir}/grub.cfg",
|
||||
f"/boot/{fallback_grub_dir}/grub.cfg",
|
||||
"/boot/grub/grub.cfg",
|
||||
"/boot/grub2/grub.cfg",
|
||||
]
|
||||
|
||||
config_path = ""
|
||||
for cfg_path in possible_config_paths:
|
||||
full_path = os.path.join(mount_point, cfg_path.lstrip('/'))
|
||||
# 优先检查目录是否存在,但也考虑发行版偏好
|
||||
if os.path.exists(os.path.dirname(full_path)):
|
||||
config_path = cfg_path
|
||||
break
|
||||
|
||||
# 如果没有找到,使用发行版偏好路径
|
||||
if not config_path:
|
||||
config_path = f"/boot/{preferred_grub_dir}/grub.cfg"
|
||||
config_path = "/boot/grub/grub.cfg"
|
||||
|
||||
# 确定更新命令
|
||||
if distro_type in ["debian", "ubuntu"]:
|
||||
@@ -2478,188 +2165,6 @@ fi
|
||||
log_info(f"使用命令: {' '.join(grub_update_cmd)}")
|
||||
log_info(f"配置文件路径: {config_path}")
|
||||
|
||||
# ===== 确保 grubenv 文件存在 =====
|
||||
# CentOS/RHEL/Fedora 等系统需要 grubenv 文件,否则 grub2-mkconfig 会失败
|
||||
grubenv_dir = os.path.dirname(config_path) # /boot/grub2 或 /boot/grub
|
||||
grubenv_path = os.path.join(mount_point, grubenv_dir.lstrip('/'), "grubenv")
|
||||
|
||||
if not os.path.exists(grubenv_path):
|
||||
log_info(f"grubenv 文件不存在,尝试创建...")
|
||||
|
||||
# 首先确保目录存在(在 chroot 环境中创建)
|
||||
grubenv_dir_in_chroot = os.path.dirname(config_path) # /boot/grub2 或 /boot/grub
|
||||
success, _, _ = run_command(
|
||||
chroot_cmd_prefix + ["mkdir", "-p", grubenv_dir_in_chroot],
|
||||
"创建 GRUB 配置目录",
|
||||
timeout=5
|
||||
)
|
||||
if success:
|
||||
log_info(f"✓ 创建目录: {grubenv_dir_in_chroot}")
|
||||
|
||||
# 检查 /boot 是否已挂载(在 chroot 内)
|
||||
success, stdout, _ = run_command(
|
||||
chroot_cmd_prefix + ["mount"],
|
||||
"检查挂载状态",
|
||||
timeout=5
|
||||
)
|
||||
if success:
|
||||
boot_mounts = [line for line in stdout.split('\n') if 'boot' in line.lower()]
|
||||
if boot_mounts:
|
||||
log_info(f"/boot 挂载状态: {', '.join(boot_mounts)}")
|
||||
else:
|
||||
log_info("/boot 挂载状态: 未找到相关挂载")
|
||||
else:
|
||||
log_info("/boot 挂载状态: 检查失败")
|
||||
|
||||
# 方法1: 使用 grub2-editenv 创建
|
||||
editenv_cmd = None
|
||||
for cmd_name in ["grub2-editenv", "grub-editenv"]:
|
||||
for cmd_dir in ["/usr/bin", "/bin", "/usr/sbin", "/sbin"]:
|
||||
test_path = os.path.join(mount_point, cmd_dir.lstrip('/'), cmd_name)
|
||||
if os.path.exists(test_path):
|
||||
editenv_cmd = os.path.join(cmd_dir, cmd_name)
|
||||
break
|
||||
if editenv_cmd:
|
||||
break
|
||||
|
||||
if editenv_cmd:
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + [editenv_cmd, grubenv_dir_in_chroot + "/grubenv", "create"],
|
||||
"创建 grubenv 文件",
|
||||
timeout=10
|
||||
)
|
||||
# 重新检查文件是否存在(可能在不同路径)
|
||||
if success:
|
||||
log_success(f"✓ 成功创建 grubenv 文件")
|
||||
else:
|
||||
log_warning(f"grub2-editenv 创建失败: {stderr}")
|
||||
|
||||
# 方法2: 如果 /boot 是独立分区,尝试在挂载的主机路径创建
|
||||
if not os.path.exists(grubenv_path):
|
||||
# 根据发行版确定正确的目录名 (grub2 vs grub)
|
||||
if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux", "opensuse"]:
|
||||
grub_dir_name = "grub2"
|
||||
else:
|
||||
grub_dir_name = "grub"
|
||||
|
||||
# 首先确保首选目录存在(使用 shell 命令,因为 /boot 可能是独立分区)
|
||||
preferred_dir = os.path.dirname(grubenv_path) # 正确路径的目录
|
||||
|
||||
# 使用 mkdir 命令创建目录(在 chroot 内,确保在正确的文件系统中)
|
||||
grubenv_dir_in_chroot = os.path.dirname(config_path) # /boot/grub2 或 /boot/grub
|
||||
success, _, _ = run_command(
|
||||
chroot_cmd_prefix + ["mkdir", "-p", grubenv_dir_in_chroot],
|
||||
f"确保 {grubenv_dir_in_chroot} 目录存在",
|
||||
timeout=5
|
||||
)
|
||||
if success:
|
||||
log_info(f"✓ 确保目录存在: {grubenv_dir_in_chroot}")
|
||||
|
||||
# 再次检查 grubenv_path(主机路径)
|
||||
log_debug(f"检查 grubenv 路径: {grubenv_path}, 存在: {os.path.exists(grubenv_path)}")
|
||||
log_debug(f"检查目录存在: {preferred_dir}, 存在: {os.path.exists(preferred_dir)}")
|
||||
|
||||
# 尝试多种可能的路径,检查是否已有 grubenv 在错误位置
|
||||
possible_wrong_paths = [
|
||||
os.path.join(mount_point, "boot", "grub" if grub_dir_name == "grub2" else "grub2", "grubenv"),
|
||||
os.path.join(mount_point, "grub" if grub_dir_name == "grub2" else "grub2", "grubenv"),
|
||||
]
|
||||
|
||||
wrong_path_found = None
|
||||
for wrong_path in possible_wrong_paths:
|
||||
if os.path.exists(wrong_path):
|
||||
wrong_path_found = wrong_path
|
||||
log_info(f"发现 grubenv 在错误位置: {wrong_path}")
|
||||
break
|
||||
|
||||
# 如果找到错误位置的 grubenv,复制到正确位置
|
||||
if wrong_path_found and not os.path.exists(grubenv_path):
|
||||
try:
|
||||
import shutil
|
||||
# 确保目标目录存在(在主机上)
|
||||
os.makedirs(os.path.dirname(grubenv_path), exist_ok=True)
|
||||
shutil.copy2(wrong_path_found, grubenv_path)
|
||||
log_success(f"✓ 复制 grubenv 到正确位置: {grubenv_path}")
|
||||
except Exception as e:
|
||||
log_warning(f"复制失败: {e}")
|
||||
|
||||
# 检查是否是符号链接(CentOS 8 等系统的 grubenv 可能是指向 EFI 分区的符号链接)
|
||||
if not os.path.exists(grubenv_path) and os.path.islink(grubenv_path):
|
||||
log_info(f"检测到 grubenv 是符号链接,尝试创建链接目标...")
|
||||
try:
|
||||
link_target = os.readlink(grubenv_path)
|
||||
log_info(f" 链接目标: {link_target}")
|
||||
|
||||
# 解析链接目标为绝对路径
|
||||
if link_target.startswith('/'):
|
||||
# 绝对路径
|
||||
target_path = os.path.join(mount_point, link_target.lstrip('/'))
|
||||
else:
|
||||
# 相对路径(如 ../efi/EFI/centos/grubenv)
|
||||
link_dir = os.path.dirname(grubenv_path)
|
||||
target_path = os.path.normpath(os.path.join(link_dir, link_target))
|
||||
|
||||
log_info(f" 解析后的目标路径: {target_path}")
|
||||
|
||||
# 创建目标目录
|
||||
target_dir = os.path.dirname(target_path)
|
||||
if not os.path.exists(target_dir):
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
log_info(f"✓ 创建目录: {target_dir}")
|
||||
|
||||
# 创建目标文件(精确 4096 字节的 GRUB 环境块)
|
||||
header = "# GRUB Environment Block\n"
|
||||
saved_entry = "saved_entry=\n"
|
||||
padding_size = 4096 - len(header) - len(saved_entry) - 1
|
||||
grubenv_content = header + saved_entry + "#" * padding_size
|
||||
with open(target_path, 'w') as f:
|
||||
f.write(grubenv_content)
|
||||
log_success(f"✓ 创建符号链接目标文件: {target_path}")
|
||||
|
||||
except Exception as e:
|
||||
log_warning(f"创建符号链接目标失败: {e}")
|
||||
# 如果创建符号链接目标失败,删除损坏的符号链接并创建普通文件
|
||||
try:
|
||||
os.unlink(grubenv_path)
|
||||
log_info(f" 已删除损坏的符号链接: {grubenv_path}")
|
||||
except Exception as e2:
|
||||
log_warning(f" 删除符号链接失败: {e2}")
|
||||
|
||||
# 如果仍未创建成功,使用 shell 命令在 chroot 内创建
|
||||
if not os.path.exists(grubenv_path):
|
||||
log_info(f"尝试使用 shell 命令创建 grubenv 文件...")
|
||||
|
||||
# 方法: 使用 echo 和 tee 在 chroot 内创建文件
|
||||
grubenv_chroot_path = grubenv_dir_in_chroot + "/grubenv"
|
||||
# 精确 4096 字节的 grubenv
|
||||
header = "# GRUB Environment Block\n"
|
||||
saved_entry = "saved_entry=\n"
|
||||
padding_size = 4096 - len(header) - len(saved_entry) - 1
|
||||
grubenv_content = header + saved_entry + "#" * padding_size
|
||||
|
||||
# 使用 printf 创建文件(更可靠)
|
||||
success, _, stderr = run_command(
|
||||
chroot_cmd_prefix + ["sh", "-c", f'printf "%s" "{grubenv_content}" > "{grubenv_chroot_path}"'],
|
||||
"使用 shell 创建 grubenv 文件",
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if success or os.path.exists(grubenv_path):
|
||||
log_success(f"✓ 手动创建 grubenv 文件成功: {grubenv_path}")
|
||||
else:
|
||||
log_warning(f"Shell 创建失败: {stderr}")
|
||||
|
||||
# 最后尝试: 使用 touch 创建空文件
|
||||
success, _, _ = run_command(
|
||||
chroot_cmd_prefix + ["touch", grubenv_chroot_path],
|
||||
"创建空 grubenv 文件",
|
||||
timeout=5
|
||||
)
|
||||
if success or os.path.exists(grubenv_path):
|
||||
log_success(f"✓ 创建空 grubenv 文件成功: {grubenv_path}")
|
||||
else:
|
||||
log_warning(f"所有方法创建 grubenv 文件均失败")
|
||||
|
||||
# 执行配置更新
|
||||
success, stdout, stderr = run_command(
|
||||
chroot_cmd_prefix + grub_update_cmd,
|
||||
@@ -2669,163 +2174,7 @@ fi
|
||||
|
||||
if not success:
|
||||
log_error(f"GRUB 配置文件更新失败: {stderr}")
|
||||
|
||||
# 备选方案:手动创建基本 grub.cfg
|
||||
log_step("尝试手动创建基本 grub.cfg")
|
||||
|
||||
# 获取根分区信息
|
||||
root_part = None
|
||||
root_uuid = None
|
||||
try:
|
||||
# 从 /etc/fstab 获取根分区
|
||||
fstab_path = os.path.join(mount_point, "etc/fstab")
|
||||
if os.path.exists(fstab_path):
|
||||
with open(fstab_path, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('#') or not line.strip():
|
||||
continue
|
||||
parts = line.split()
|
||||
if len(parts) >= 2 and parts[1] == '/':
|
||||
root_part = parts[0]
|
||||
break
|
||||
|
||||
# 获取 UUID
|
||||
if root_part and root_part.startswith('UUID='):
|
||||
root_uuid = root_part[5:].strip('"')
|
||||
elif root_part and root_part.startswith('/dev/'):
|
||||
success_uuid, uuid_out, _ = run_command(
|
||||
["sudo", "blkid", "-s", "UUID", "-o", "value", root_part],
|
||||
f"获取 {root_part} 的 UUID",
|
||||
timeout=10
|
||||
)
|
||||
if success_uuid:
|
||||
root_uuid = uuid_out.strip()
|
||||
except Exception as e:
|
||||
log_warning(f"获取根分区信息失败: {e}")
|
||||
|
||||
# 查找内核文件
|
||||
boot_dir = os.path.join(mount_point, "boot")
|
||||
kernel_files = []
|
||||
initramfs_files = []
|
||||
try:
|
||||
for f in os.listdir(boot_dir):
|
||||
if f.startswith('vmlinuz-'):
|
||||
kernel_files.append(f)
|
||||
elif f.startswith('initramfs-') and f.endswith('.img') and 'kdump' not in f:
|
||||
initramfs_files.append(f)
|
||||
kernel_files.sort(reverse=True)
|
||||
initramfs_files.sort(reverse=True)
|
||||
except Exception as e:
|
||||
log_warning(f"查找内核文件失败: {e}")
|
||||
|
||||
if kernel_files and root_uuid:
|
||||
# 检测是否有独立 /boot 分区
|
||||
boot_uuid = None
|
||||
try:
|
||||
boot_mount_point = os.path.join(mount_point, "boot")
|
||||
if os.path.ismount(boot_mount_point):
|
||||
# 有独立 /boot 分区,获取其 UUID
|
||||
success_uuid, uuid_out, _ = run_command(
|
||||
["sudo", "blkid", "-s", "UUID", "-o", "value", boot_mount_point],
|
||||
"获取 /boot 分区 UUID",
|
||||
timeout=10
|
||||
)
|
||||
if success_uuid:
|
||||
boot_uuid = uuid_out.strip()
|
||||
log_info(f"检测到独立 /boot 分区,UUID: {boot_uuid}")
|
||||
except Exception as e:
|
||||
log_warning(f"获取 /boot UUID 失败: {e}")
|
||||
|
||||
# 创建基本 grub.cfg
|
||||
if boot_uuid:
|
||||
# 独立 /boot 分区配置 - 需要先搜索 /boot 分区
|
||||
grub_cfg_content = f"""# Minimal GRUB config generated by BootRepairTool
|
||||
# For system with separate /boot partition
|
||||
|
||||
set timeout=5
|
||||
set default=0
|
||||
|
||||
# Load necessary modules
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
insmod fat
|
||||
|
||||
# Search for the /boot partition by UUID, or try search by file as fallback
|
||||
if search --no-floppy --fs-uuid --set=root {boot_uuid}; then
|
||||
set prefix=($root)/grub2
|
||||
else
|
||||
# Fallback: search by file
|
||||
search --no-floppy --set=root --file /grub2/grub.cfg
|
||||
set prefix=($root)/grub2
|
||||
fi
|
||||
|
||||
menuentry 'CentOS Linux (Auto)' {{
|
||||
load_video
|
||||
set gfxpayload=keep
|
||||
insmod gzio
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
linux /{kernel_files[0]} root=UUID={root_uuid} ro rhgb quiet
|
||||
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||
}}
|
||||
|
||||
menuentry 'CentOS Linux (Rescue)' {{
|
||||
load_video
|
||||
set gfxpayload=keep
|
||||
insmod gzio
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
linux /{kernel_files[0]} root=UUID={root_uuid} ro rescue
|
||||
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||
}}
|
||||
"""
|
||||
else:
|
||||
# 无独立 /boot 分区配置
|
||||
grub_cfg_content = f"""# Minimal GRUB config generated by BootRepairTool
|
||||
|
||||
set timeout=5
|
||||
set default=0
|
||||
|
||||
# Load necessary modules
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
insmod fat
|
||||
|
||||
# Search for the root partition by UUID
|
||||
search --no-floppy --fs-uuid --set=root {root_uuid}
|
||||
|
||||
menuentry 'CentOS Linux (Auto)' {{
|
||||
load_video
|
||||
set gfxpayload=keep
|
||||
insmod gzio
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
linux /{kernel_files[0]} root=UUID={root_uuid} ro rhgb quiet
|
||||
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||
}}
|
||||
|
||||
menuentry 'CentOS Linux (Rescue)' {{
|
||||
load_video
|
||||
set gfxpayload=keep
|
||||
insmod gzio
|
||||
insmod part_gpt
|
||||
insmod xfs
|
||||
linux /{kernel_files[0]} root=UUID={root_uuid} ro rescue
|
||||
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||
}}
|
||||
"""
|
||||
try:
|
||||
with open(full_config_path, 'w') as f:
|
||||
f.write(grub_cfg_content)
|
||||
log_success(f"✓ 手动创建 grub.cfg: {full_config_path}")
|
||||
log_info(f" 内核: {kernel_files[0]}")
|
||||
log_info(f" UUID: {root_uuid}")
|
||||
success = True
|
||||
except Exception as e:
|
||||
log_error(f"手动创建 grub.cfg 失败: {e}")
|
||||
return False, f"GRUB配置失败: {stderr}"
|
||||
else:
|
||||
return False, f"GRUB配置失败,无法获取内核或UUID"
|
||||
return False, f"GRUB配置文件更新失败: {stderr}"
|
||||
|
||||
log_success("✓ GRUB 配置文件更新成功")
|
||||
|
||||
@@ -2839,30 +2188,10 @@ menuentry 'CentOS Linux (Rescue)' {{
|
||||
content = f.read()
|
||||
menu_entries = content.count('menuentry')
|
||||
log_info(f" 发现 {menu_entries} 个启动菜单项")
|
||||
|
||||
# 验证配置文件是否有效
|
||||
if size < 1000:
|
||||
log_warning(f"配置文件太小 ({size} 字节),可能有问题")
|
||||
if menu_entries == 0:
|
||||
log_warning("配置文件中没有找到启动菜单项!")
|
||||
log_info("尝试重新生成配置...")
|
||||
# 再次尝试生成配置
|
||||
success2, stdout2, stderr2 = run_command(
|
||||
chroot_cmd_prefix + grub_update_cmd,
|
||||
"重新生成GRUB配置",
|
||||
timeout=120
|
||||
)
|
||||
if success2:
|
||||
# 重新读取
|
||||
with open(full_config_path, 'r') as f2:
|
||||
content2 = f2.read()
|
||||
menu_entries2 = content2.count('menuentry')
|
||||
log_info(f"重新生成后: {len(content2)} 字节, {menu_entries2} 个菜单项")
|
||||
except Exception as e:
|
||||
log_warning(f" 无法读取配置文件: {e}")
|
||||
else:
|
||||
log_warning(f" 配置文件未找到: {full_config_path}")
|
||||
return False, f"grub.cfg 文件未生成: {full_config_path}"
|
||||
|
||||
# ===== 输出启动提示 =====
|
||||
if is_uefi or install_hybrid:
|
||||
|
||||
143
build.py
Executable file
143
build.py
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/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/4] 安装依赖...")
|
||||
|
||||
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/4] 清理构建文件...")
|
||||
|
||||
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/4] 开始打包...")
|
||||
|
||||
# 打包命令
|
||||
cmd = [
|
||||
sys.executable, "-m", "PyInstaller",
|
||||
"--name=LinuxGrubRepair",
|
||||
"--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 show_result():
|
||||
"""显示打包结果"""
|
||||
print("\n[4/4] 打包完成!")
|
||||
|
||||
dist_path = os.path.join(os.getcwd(), "dist")
|
||||
exe_name = "LinuxGrubRepair"
|
||||
exe_path = os.path.join(dist_path, exe_name)
|
||||
|
||||
if os.path.exists(exe_path):
|
||||
size = os.path.getsize(exe_path)
|
||||
size_mb = size / (1024 * 1024)
|
||||
print(f"\n 可执行文件: {exe_path}")
|
||||
print(f" 文件大小: {size_mb:.2f} MB")
|
||||
print("\n 使用方式:")
|
||||
print(f" sudo ./{exe_name}")
|
||||
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)
|
||||
|
||||
# 显示结果
|
||||
show_result()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
dist/LinuxGrubRepair
vendored
Executable file
BIN
dist/LinuxGrubRepair
vendored
Executable file
Binary file not shown.
@@ -13,11 +13,11 @@ class GrubRepairApp:
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
master.title("Linux GRUB 引导修复工具 v2.0")
|
||||
master.geometry("900x750")
|
||||
master.geometry("643x750")
|
||||
master.resizable(True, True)
|
||||
|
||||
# 设置窗口最小大小
|
||||
master.minsize(800, 600)
|
||||
master.minsize(643, 600)
|
||||
|
||||
self.mount_point = None
|
||||
self.selected_root_partition_info = None
|
||||
|
||||
40
linuxgrubrepair.spec
Normal file
40
linuxgrubrepair.spec
Normal file
@@ -0,0 +1,40 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['frontend.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,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='linuxgrubrepair',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None )
|
||||
Reference in New Issue
Block a user