mirror of
https://github.com/outbackdingo/OpCore-Simplify.git
synced 2026-01-27 10:19:49 +00:00
* Refactor OpCore-Simplify to GUI version * New ConfigEditor * Add requirement checks and installation in launchers * Add GitHub Actions workflow to generate manifest.json * Set compression level for asset * Skip .git and __pycache__ folders * Refactor update process to include integrity checker * Add SMBIOS model selection * Update README.md * Update to main branch
552 lines
25 KiB
Python
552 lines
25 KiB
Python
import platform
|
|
import os
|
|
import shutil
|
|
import threading
|
|
|
|
from PyQt6.QtCore import Qt, pyqtSignal
|
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel
|
|
from qfluentwidgets import (
|
|
SubtitleLabel, BodyLabel, CardWidget, TextEdit,
|
|
StrongBodyLabel, ProgressBar, PrimaryPushButton, FluentIcon,
|
|
ScrollArea
|
|
)
|
|
|
|
from Scripts.datasets import chipset_data
|
|
from Scripts.datasets import kext_data
|
|
from Scripts.custom_dialogs import show_confirmation
|
|
from Scripts.styles import SPACING, COLORS, RADIUS
|
|
from Scripts import ui_utils
|
|
from Scripts.widgets.config_editor import ConfigEditor
|
|
|
|
|
|
class BuildPage(ScrollArea):
|
|
build_progress_signal = pyqtSignal(str, list, int, int, bool)
|
|
build_complete_signal = pyqtSignal(bool, object)
|
|
|
|
def __init__(self, parent, ui_utils_instance=None):
|
|
super().__init__(parent)
|
|
self.setObjectName("buildPage")
|
|
self.controller = parent
|
|
self.scrollWidget = QWidget()
|
|
self.expandLayout = QVBoxLayout(self.scrollWidget)
|
|
self.build_in_progress = False
|
|
self.build_successful = False
|
|
self.ui_utils = ui_utils_instance if ui_utils_instance else ui_utils.UIUtils()
|
|
|
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
|
self.setWidget(self.scrollWidget)
|
|
self.setWidgetResizable(True)
|
|
self.enableTransparentBackground()
|
|
|
|
self._init_ui()
|
|
self._connect_signals()
|
|
|
|
def _init_ui(self):
|
|
self.expandLayout.setContentsMargins(SPACING["xxlarge"], SPACING["xlarge"], SPACING["xxlarge"], SPACING["xlarge"])
|
|
self.expandLayout.setSpacing(SPACING["large"])
|
|
|
|
self.expandLayout.addWidget(self.ui_utils.create_step_indicator(4))
|
|
|
|
header_layout = QVBoxLayout()
|
|
header_layout.setSpacing(SPACING["small"])
|
|
title = SubtitleLabel("Build OpenCore EFI")
|
|
subtitle = BodyLabel("Build your customized OpenCore EFI ready for installation")
|
|
subtitle.setStyleSheet("color: {};".format(COLORS["text_secondary"]))
|
|
header_layout.addWidget(title)
|
|
header_layout.addWidget(subtitle)
|
|
self.expandLayout.addLayout(header_layout)
|
|
|
|
self.expandLayout.addSpacing(SPACING["medium"])
|
|
|
|
self.instructions_after_content = QWidget()
|
|
self.instructions_after_content_layout = QVBoxLayout(self.instructions_after_content)
|
|
self.instructions_after_content_layout.setContentsMargins(0, 0, 0, 0)
|
|
self.instructions_after_content_layout.setSpacing(SPACING["medium"])
|
|
|
|
self.instructions_after_build_card = self.ui_utils.custom_card(
|
|
card_type="warning",
|
|
title="Before Using Your EFI",
|
|
body="Please complete these important steps before using the built EFI:",
|
|
custom_widget=self.instructions_after_content,
|
|
parent=self.scrollWidget
|
|
)
|
|
|
|
self.instructions_after_build_card.setVisible(False)
|
|
self.expandLayout.addWidget(self.instructions_after_build_card)
|
|
|
|
build_control_card = CardWidget(self.scrollWidget)
|
|
build_control_card.setBorderRadius(RADIUS["card"])
|
|
build_control_layout = QVBoxLayout(build_control_card)
|
|
build_control_layout.setContentsMargins(SPACING["large"], SPACING["large"], SPACING["large"], SPACING["large"])
|
|
build_control_layout.setSpacing(SPACING["medium"])
|
|
|
|
title = StrongBodyLabel("Build Control")
|
|
build_control_layout.addWidget(title)
|
|
|
|
btn_layout = QHBoxLayout()
|
|
btn_layout.setSpacing(SPACING["medium"])
|
|
|
|
self.build_btn = PrimaryPushButton(FluentIcon.DEVELOPER_TOOLS, "Build OpenCore EFI")
|
|
self.build_btn.clicked.connect(self.start_build)
|
|
btn_layout.addWidget(self.build_btn)
|
|
self.controller.build_btn = self.build_btn
|
|
|
|
self.open_result_btn = PrimaryPushButton(FluentIcon.FOLDER, "Open Result Folder")
|
|
self.open_result_btn.clicked.connect(self.open_result)
|
|
self.open_result_btn.setEnabled(False)
|
|
btn_layout.addWidget(self.open_result_btn)
|
|
self.controller.open_result_btn = self.open_result_btn
|
|
|
|
build_control_layout.addLayout(btn_layout)
|
|
|
|
self.progress_container = QWidget()
|
|
progress_layout = QVBoxLayout(self.progress_container)
|
|
progress_layout.setContentsMargins(0, SPACING["small"], 0, 0)
|
|
progress_layout.setSpacing(SPACING["medium"])
|
|
|
|
status_row = QHBoxLayout()
|
|
status_row.setSpacing(SPACING["medium"])
|
|
|
|
self.status_icon_label = QLabel()
|
|
self.status_icon_label.setFixedSize(28, 28)
|
|
status_row.addWidget(self.status_icon_label)
|
|
|
|
self.progress_label = StrongBodyLabel("Ready to build")
|
|
self.progress_label.setStyleSheet("color: {}; font-size: 15px; font-weight: 600;".format(COLORS["text_secondary"]))
|
|
status_row.addWidget(self.progress_label)
|
|
status_row.addStretch()
|
|
|
|
progress_layout.addLayout(status_row)
|
|
|
|
self.progress_bar = ProgressBar()
|
|
self.progress_bar.setValue(0)
|
|
self.progress_bar.setFixedHeight(10)
|
|
self.progress_bar.setTextVisible(True)
|
|
self.controller.progress_bar = self.progress_bar
|
|
progress_layout.addWidget(self.progress_bar)
|
|
|
|
self.controller.progress_label = self.progress_label
|
|
self.progress_container.setVisible(False)
|
|
|
|
self.progress_helper = ui_utils.ProgressStatusHelper(
|
|
self.status_icon_label,
|
|
self.progress_label,
|
|
self.progress_bar,
|
|
self.progress_container
|
|
)
|
|
|
|
build_control_layout.addWidget(self.progress_container)
|
|
self.expandLayout.addWidget(build_control_card)
|
|
|
|
log_card = CardWidget(self.scrollWidget)
|
|
log_card.setBorderRadius(RADIUS["card"])
|
|
log_card_layout = QVBoxLayout(log_card)
|
|
log_card_layout.setContentsMargins(SPACING["large"], SPACING["large"], SPACING["large"], SPACING["large"])
|
|
log_card_layout.setSpacing(SPACING["medium"])
|
|
|
|
log_title = StrongBodyLabel("Build Log")
|
|
log_card_layout.addWidget(log_title)
|
|
|
|
log_description = BodyLabel("Detailed build process information and status updates")
|
|
log_description.setStyleSheet("color: {}; font-size: 13px;".format(COLORS["text_secondary"]))
|
|
log_card_layout.addWidget(log_description)
|
|
|
|
self.build_log = TextEdit()
|
|
self.build_log.setReadOnly(True)
|
|
self.build_log.setMinimumHeight(400)
|
|
self.build_log.setStyleSheet(f"""
|
|
TextEdit {{
|
|
background-color: rgba(0, 0, 0, 0.03);
|
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
border-radius: {RADIUS["small"]}px;
|
|
padding: {SPACING["large"]}px;
|
|
font-family: "Consolas", "Monaco", "Courier New", monospace;
|
|
font-size: 13px;
|
|
line-height: 1.7;
|
|
}}
|
|
""")
|
|
self.controller.build_log = self.build_log
|
|
log_card_layout.addWidget(self.build_log)
|
|
|
|
self.log_card = log_card
|
|
self.log_card.setVisible(False)
|
|
self.expandLayout.addWidget(log_card)
|
|
|
|
self.config_editor = ConfigEditor(self.scrollWidget)
|
|
self.config_editor.setVisible(False)
|
|
self.expandLayout.addWidget(self.config_editor)
|
|
|
|
self.expandLayout.addStretch()
|
|
|
|
def _connect_signals(self):
|
|
self.build_progress_signal.connect(self._handle_build_progress)
|
|
self.build_complete_signal.connect(self._handle_build_complete)
|
|
|
|
def _handle_build_progress(self, title, steps, current_step_index, progress, done):
|
|
status = "success" if done else "loading"
|
|
|
|
if done:
|
|
message = "{} complete!".format(title)
|
|
else:
|
|
step_text = steps[current_step_index] if current_step_index < len(steps) else "Processing"
|
|
step_counter = "Step {}/{}".format(current_step_index + 1, len(steps))
|
|
message = "{}: {}...".format(step_counter, step_text)
|
|
|
|
if done:
|
|
final_progress = 100
|
|
else:
|
|
if "Building" in title:
|
|
final_progress = 40 + int(progress * 0.6)
|
|
else:
|
|
final_progress = progress
|
|
|
|
if hasattr(self, "progress_helper"):
|
|
self.progress_helper.update(status, message, final_progress)
|
|
|
|
if done:
|
|
self.controller.backend.u.log_message("[BUILD] {} complete!".format(title), "SUCCESS", to_build_log=True)
|
|
else:
|
|
step_text = steps[current_step_index] if current_step_index < len(steps) else "Processing"
|
|
self.controller.backend.u.log_message("[BUILD] Step {}/{}: {}...".format(current_step_index + 1, len(steps), step_text), "INFO", to_build_log=True)
|
|
|
|
def start_build(self):
|
|
if not self.controller.validate_prerequisites():
|
|
return
|
|
|
|
if self.controller.macos_state.needs_oclp:
|
|
content = (
|
|
"1. OpenCore Legacy Patcher allows restoring support for dropped GPUs and Broadcom WiFi on newer versions of macOS, and also enables AppleHDA on macOS Tahoe 26.<br>"
|
|
"2. OpenCore Legacy Patcher needs SIP disabled for applying custom kernel patches, which can cause instability, security risks and update issues.<br>"
|
|
"3. OpenCore Legacy Patcher does not officially support the Hackintosh community.<br><br>"
|
|
"<b><font color=\"{info_color}\">Support for macOS Tahoe 26:</font></b><br>"
|
|
"To patch macOS Tahoe 26, you must download OpenCore-Patcher 3.0.0 or newer from my repository: <a href=\"https://github.com/lzhoang2801/OpenCore-Legacy-Patcher/releases/tag/3.0.0\">lzhoang2801/OpenCore-Legacy-Patcher</a>.<br>"
|
|
"Official Dortania releases or older patches will NOT work with macOS Tahoe 26."
|
|
).format(error_color=COLORS["error"], info_color="#00BCD4")
|
|
if not show_confirmation("OpenCore Legacy Patcher Warning", content):
|
|
return
|
|
|
|
self.build_in_progress = True
|
|
self.build_successful = False
|
|
self.build_btn.setEnabled(False)
|
|
self.build_btn.setText("Building...")
|
|
self.open_result_btn.setEnabled(False)
|
|
|
|
self.progress_helper.update("loading", "Preparing to build...", 0)
|
|
|
|
self.instructions_after_build_card.setVisible(False)
|
|
self.build_log.clear()
|
|
self.log_card.setVisible(True)
|
|
|
|
thread = threading.Thread(target=self._start_build_thread, daemon=True)
|
|
thread.start()
|
|
|
|
def _start_build_thread(self):
|
|
try:
|
|
backend = self.controller.backend
|
|
backend.o.gather_bootloader_kexts(backend.k.kexts, self.controller.macos_state.darwin_version)
|
|
|
|
self._build_opencore_efi(
|
|
self.controller.hardware_state.customized_hardware,
|
|
self.controller.hardware_state.disabled_devices,
|
|
self.controller.smbios_state.model_name,
|
|
self.controller.macos_state.darwin_version,
|
|
self.controller.macos_state.needs_oclp
|
|
)
|
|
|
|
bios_requirements = self._check_bios_requirements(
|
|
self.controller.hardware_state.customized_hardware,
|
|
self.controller.hardware_state.customized_hardware
|
|
)
|
|
|
|
self.build_complete_signal.emit(True, bios_requirements)
|
|
except Exception as e:
|
|
self.build_complete_signal.emit(False, None)
|
|
|
|
def _check_bios_requirements(self, org_hardware_report, hardware_report):
|
|
requirements = []
|
|
|
|
org_firmware_type = org_hardware_report.get("BIOS", {}).get("Firmware Type", "Unknown")
|
|
firmware_type = hardware_report.get("BIOS", {}).get("Firmware Type", "Unknown")
|
|
if org_firmware_type == "Legacy" and firmware_type == "UEFI":
|
|
requirements.append("Enable UEFI mode (disable Legacy/CSM (Compatibility Support Module))")
|
|
|
|
secure_boot = hardware_report.get("BIOS", {}).get("Secure Boot", "Unknown")
|
|
if secure_boot != "Disabled":
|
|
requirements.append("Disable Secure Boot")
|
|
|
|
if hardware_report.get("Motherboard", {}).get("Platform") == "Desktop" and hardware_report.get("Motherboard", {}).get("Chipset") in chipset_data.IntelChipsets[112:]:
|
|
resizable_bar_enabled = any(gpu_props.get("Resizable BAR", "Disabled") == "Enabled" for gpu_props in hardware_report.get("GPU", {}).values())
|
|
if not resizable_bar_enabled:
|
|
requirements.append("Enable Above 4G Decoding")
|
|
requirements.append("Disable Resizable BAR/Smart Access Memory")
|
|
|
|
return requirements
|
|
|
|
def _build_opencore_efi(self, hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp):
|
|
steps = [
|
|
"Copying EFI base to results folder",
|
|
"Applying ACPI patches",
|
|
"Copying kexts and snapshotting to config.plist",
|
|
"Generating config.plist",
|
|
"Cleaning up unused drivers, resources, and tools"
|
|
]
|
|
|
|
title = "Building OpenCore EFI"
|
|
current_step = 0
|
|
|
|
progress = int((current_step / len(steps)) * 100)
|
|
self.build_progress_signal.emit(title, steps, current_step, progress, False)
|
|
current_step += 1
|
|
|
|
backend = self.controller.backend
|
|
backend.u.create_folder(backend.result_dir, remove_content=True)
|
|
|
|
if not os.path.exists(backend.k.ock_files_dir):
|
|
raise Exception("Directory \"{}\" does not exist.".format(backend.k.ock_files_dir))
|
|
|
|
source_efi_dir = os.path.join(backend.k.ock_files_dir, "OpenCorePkg")
|
|
shutil.copytree(source_efi_dir, backend.result_dir, dirs_exist_ok=True)
|
|
|
|
config_file = os.path.join(backend.result_dir, "EFI", "OC", "config.plist")
|
|
config_data = backend.u.read_file(config_file)
|
|
|
|
if not config_data:
|
|
raise Exception("Error: The file {} does not exist.".format(config_file))
|
|
|
|
progress = int((current_step / len(steps)) * 100)
|
|
self.build_progress_signal.emit(title, steps, current_step, progress, False)
|
|
current_step += 1
|
|
|
|
config_data["ACPI"]["Add"] = []
|
|
config_data["ACPI"]["Delete"] = []
|
|
config_data["ACPI"]["Patch"] = []
|
|
|
|
acpi_directory = os.path.join(backend.result_dir, "EFI", "OC", "ACPI")
|
|
|
|
if backend.ac.ensure_dsdt():
|
|
backend.ac.hardware_report = hardware_report
|
|
backend.ac.disabled_devices = disabled_devices
|
|
backend.ac.acpi_directory = acpi_directory
|
|
backend.ac.smbios_model = smbios_model
|
|
backend.ac.lpc_bus_device = backend.ac.get_lpc_name()
|
|
|
|
for patch in backend.ac.patches:
|
|
if patch.checked:
|
|
if patch.name == "BATP":
|
|
patch.checked = getattr(backend.ac, patch.function_name)()
|
|
backend.k.kexts[kext_data.kext_index_by_name.get("ECEnabler")].checked = patch.checked
|
|
continue
|
|
|
|
acpi_load = getattr(backend.ac, patch.function_name)()
|
|
if not isinstance(acpi_load, dict):
|
|
continue
|
|
|
|
config_data["ACPI"]["Add"].extend(acpi_load.get("Add", []))
|
|
config_data["ACPI"]["Delete"].extend(acpi_load.get("Delete", []))
|
|
config_data["ACPI"]["Patch"].extend(acpi_load.get("Patch", []))
|
|
|
|
config_data["ACPI"]["Patch"].extend(backend.ac.dsdt_patches)
|
|
config_data["ACPI"]["Patch"] = backend.ac.apply_acpi_patches(config_data["ACPI"]["Patch"])
|
|
|
|
progress = int((current_step / len(steps)) * 100)
|
|
self.build_progress_signal.emit(title, steps, current_step, progress, False)
|
|
current_step += 1
|
|
|
|
kexts_directory = os.path.join(backend.result_dir, "EFI", "OC", "Kexts")
|
|
backend.k.install_kexts_to_efi(macos_version, kexts_directory)
|
|
config_data["Kernel"]["Add"] = backend.k.load_kexts(hardware_report, macos_version, kexts_directory)
|
|
|
|
progress = int((current_step / len(steps)) * 100)
|
|
self.build_progress_signal.emit(title, steps, current_step, progress, False)
|
|
current_step += 1
|
|
|
|
audio_layout_id = self.controller.hardware_state.audio_layout_id
|
|
audio_controller_properties = self.controller.hardware_state.audio_controller_properties
|
|
|
|
backend.co.genarate(
|
|
hardware_report,
|
|
disabled_devices,
|
|
smbios_model,
|
|
macos_version,
|
|
needs_oclp,
|
|
backend.k.kexts,
|
|
config_data,
|
|
audio_layout_id,
|
|
audio_controller_properties
|
|
)
|
|
|
|
backend.u.write_file(config_file, config_data)
|
|
|
|
progress = int((current_step / len(steps)) * 100)
|
|
self.build_progress_signal.emit(title, steps, current_step, progress, False)
|
|
files_to_remove = []
|
|
|
|
drivers_directory = os.path.join(backend.result_dir, "EFI", "OC", "Drivers")
|
|
driver_list = backend.u.find_matching_paths(drivers_directory, extension_filter=".efi")
|
|
driver_loaded = [kext.get("Path") for kext in config_data.get("UEFI").get("Drivers")]
|
|
for driver_path, type in driver_list:
|
|
if not driver_path in driver_loaded:
|
|
files_to_remove.append(os.path.join(drivers_directory, driver_path))
|
|
|
|
resources_audio_dir = os.path.join(backend.result_dir, "EFI", "OC", "Resources", "Audio")
|
|
if os.path.exists(resources_audio_dir):
|
|
files_to_remove.append(resources_audio_dir)
|
|
|
|
picker_variant = config_data.get("Misc", {}).get("Boot", {}).get("PickerVariant")
|
|
if picker_variant in (None, "Auto"):
|
|
picker_variant = "Acidanthera/GoldenGate"
|
|
if os.name == "nt":
|
|
picker_variant = picker_variant.replace("/", "\\")
|
|
|
|
resources_image_dir = os.path.join(backend.result_dir, "EFI", "OC", "Resources", "Image")
|
|
available_picker_variants = backend.u.find_matching_paths(resources_image_dir, type_filter="dir")
|
|
|
|
for variant_name, variant_type in available_picker_variants:
|
|
variant_path = os.path.join(resources_image_dir, variant_name)
|
|
if ".icns" in ", ".join(os.listdir(variant_path)):
|
|
if picker_variant not in variant_name:
|
|
files_to_remove.append(variant_path)
|
|
|
|
tools_directory = os.path.join(backend.result_dir, "EFI", "OC", "Tools")
|
|
tool_list = backend.u.find_matching_paths(tools_directory, extension_filter=".efi")
|
|
tool_loaded = [tool.get("Path") for tool in config_data.get("Misc").get("Tools")]
|
|
for tool_path, type in tool_list:
|
|
if not tool_path in tool_loaded:
|
|
files_to_remove.append(os.path.join(tools_directory, tool_path))
|
|
|
|
if "manifest.json" in os.listdir(backend.result_dir):
|
|
files_to_remove.append(os.path.join(backend.result_dir, "manifest.json"))
|
|
|
|
for file_path in files_to_remove:
|
|
try:
|
|
if os.path.isdir(file_path):
|
|
shutil.rmtree(file_path)
|
|
else:
|
|
os.remove(file_path)
|
|
except Exception as e:
|
|
backend.u.log_message("[BUILD] Failed to remove file {}: {}".format(os.path.basename(file_path), e), level="WARNING", to_build_log=True)
|
|
|
|
self.build_progress_signal.emit(title, steps, len(steps) - 1, 100, True)
|
|
|
|
def show_post_build_instructions(self, bios_requirements):
|
|
while self.instructions_after_content_layout.count():
|
|
item = self.instructions_after_content_layout.takeAt(0)
|
|
if item.widget():
|
|
item.widget().deleteLater()
|
|
|
|
if bios_requirements:
|
|
bios_header = StrongBodyLabel("1. BIOS/UEFI Settings Required:")
|
|
bios_header.setStyleSheet("color: {}; font-size: 14px;".format(COLORS["warning_text"]))
|
|
self.instructions_after_content_layout.addWidget(bios_header)
|
|
|
|
bios_text = "\n".join([" • {}".format(req) for req in bios_requirements])
|
|
bios_label = BodyLabel(bios_text)
|
|
bios_label.setWordWrap(True)
|
|
bios_label.setStyleSheet("color: #424242; line-height: 1.6;")
|
|
self.instructions_after_content_layout.addWidget(bios_label)
|
|
|
|
self.instructions_after_content_layout.addSpacing(SPACING["medium"])
|
|
|
|
usb_header = StrongBodyLabel("{}. USB Port Mapping:".format(2 if bios_requirements else 1))
|
|
usb_header.setStyleSheet("color: {}; font-size: 14px;".format(COLORS["warning_text"]))
|
|
self.instructions_after_content_layout.addWidget(usb_header)
|
|
|
|
path_sep = "\\" if platform.system() == "Windows" else "/"
|
|
|
|
usb_mapping_instructions = (
|
|
"1. Use USBToolBox tool to map USB ports<br>"
|
|
"2. Add created UTBMap.kext into the EFI{path_sep}OC{path_sep}Kexts folder<br>"
|
|
"3. Remove UTBDefault.kext from the EFI{path_sep}OC{path_sep}Kexts folder<br>"
|
|
"4. Edit config.plist using ProperTree:<br>"
|
|
" a. Run OC Snapshot (Command/Ctrl + R)<br>"
|
|
" b. Enable XhciPortLimit quirk if you have more than 15 ports per controller<br>"
|
|
" c. Save the file when finished."
|
|
).format(path_sep=path_sep)
|
|
|
|
usb_label = BodyLabel(usb_mapping_instructions)
|
|
usb_label.setWordWrap(True)
|
|
usb_label.setStyleSheet("color: #424242; line-height: 1.6;")
|
|
self.instructions_after_content_layout.addWidget(usb_label)
|
|
|
|
self.instructions_after_build_card.setVisible(True)
|
|
|
|
def _handle_build_complete(self, success, bios_requirements):
|
|
self.build_in_progress = False
|
|
self.build_successful = success
|
|
|
|
if success:
|
|
self.log_card.setVisible(False)
|
|
self.progress_helper.update("success", "Build completed successfully!", 100)
|
|
|
|
self.show_post_build_instructions(bios_requirements)
|
|
self._load_configs_after_build()
|
|
|
|
self.build_btn.setText("Build OpenCore EFI")
|
|
self.build_btn.setEnabled(True)
|
|
self.open_result_btn.setEnabled(True)
|
|
|
|
success_message = "Your OpenCore EFI has been built successfully!"
|
|
if bios_requirements is not None:
|
|
success_message += " Review the important instructions below."
|
|
|
|
self.controller.update_status(success_message, "success")
|
|
else:
|
|
self.progress_helper.update("error", "Build OpenCore EFI failed", None)
|
|
|
|
self.config_editor.setVisible(False)
|
|
|
|
self.build_btn.setText("Retry Build OpenCore EFI")
|
|
self.build_btn.setEnabled(True)
|
|
self.open_result_btn.setEnabled(False)
|
|
|
|
self.controller.update_status("An error occurred during the build. Check the log for details.", "error")
|
|
|
|
def open_result(self):
|
|
result_dir = self.controller.backend.result_dir
|
|
try:
|
|
self.controller.backend.u.open_folder(result_dir)
|
|
except Exception as e:
|
|
self.controller.update_status("Failed to open result folder: {}".format(e), "warning")
|
|
|
|
def _load_configs_after_build(self):
|
|
backend = self.controller.backend
|
|
|
|
source_efi_dir = os.path.join(backend.k.ock_files_dir, "OpenCorePkg")
|
|
original_config_file = os.path.join(source_efi_dir, "EFI", "OC", "config.plist")
|
|
|
|
if not os.path.exists(original_config_file):
|
|
return
|
|
|
|
original_config = backend.u.read_file(original_config_file)
|
|
if not original_config:
|
|
return
|
|
|
|
modified_config_file = os.path.join(backend.result_dir, "EFI", "OC", "config.plist")
|
|
|
|
if not os.path.exists(modified_config_file):
|
|
return
|
|
|
|
modified_config = backend.u.read_file(modified_config_file)
|
|
if not modified_config:
|
|
return
|
|
|
|
context = {
|
|
"hardware_report": self.controller.hardware_state.hardware_report,
|
|
"macos_version": self.controller.macos_state.darwin_version,
|
|
"smbios_model": self.controller.smbios_state.model_name,
|
|
}
|
|
|
|
self.config_editor.load_configs(original_config, modified_config, context)
|
|
self.config_editor.setVisible(True)
|
|
|
|
def refresh(self):
|
|
if not self.build_in_progress:
|
|
if self.build_successful:
|
|
self.progress_container.setVisible(True)
|
|
self.open_result_btn.setEnabled(True)
|
|
else:
|
|
log_text = self.build_log.toPlainText()
|
|
if not log_text or log_text == DEFAULT_LOG_TEXT:
|
|
self.progress_container.setVisible(False)
|
|
self.log_card.setVisible(False)
|
|
self.open_result_btn.setEnabled(False) |