Add GUI Support for OpCore Simplify (#512)

* 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
This commit is contained in:
Hoang Hong Quan
2025-12-30 14:19:47 +07:00
committed by GitHub
parent 871d826ea4
commit 0e608a56ce
38 changed files with 4948 additions and 1636 deletions

View File

@@ -1,482 +1,318 @@
from Scripts.datasets import os_data
from Scripts.datasets import chipset_data
from Scripts import acpi_guru
from Scripts import compatibility_checker
from Scripts import config_prodigy
from Scripts import gathering_files
from Scripts import hardware_customizer
from Scripts import kext_maestro
from Scripts import report_validator
from Scripts import run
from Scripts import smbios
from Scripts import utils
import updater
import os
import sys
import re
import shutil
import platform
import traceback
import time
class OCPE:
def __init__(self):
self.u = utils.Utils("OpCore Simplify")
self.u.clean_temporary_dir()
self.ac = acpi_guru.ACPIGuru()
self.c = compatibility_checker.CompatibilityChecker()
self.co = config_prodigy.ConfigProdigy()
self.o = gathering_files.gatheringFiles()
self.h = hardware_customizer.HardwareCustomizer()
self.k = kext_maestro.KextMaestro()
self.s = smbios.SMBIOS()
self.v = report_validator.ReportValidator()
self.r = run.Run()
self.result_dir = self.u.get_temporary_dir()
from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import QApplication
from qfluentwidgets import FluentWindow, NavigationItemPosition, FluentIcon, InfoBar, InfoBarPosition
def select_hardware_report(self):
self.ac.dsdt = self.ac.acpi.acpi_tables = None
from Scripts.datasets import os_data
from Scripts.state import HardwareReportState, macOSVersionState, SMBIOSState, BuildState
from Scripts.pages import HomePage, SelectHardwareReportPage, CompatibilityPage, ConfigurationPage, BuildPage, SettingsPage
from Scripts.backend import Backend
from Scripts import ui_utils
from Scripts.custom_dialogs import set_default_gui_handler
import updater
while True:
self.u.head("Select hardware report")
print("")
if os.name == "nt":
print("\033[1;93mNote:\033[0m")
print("- Ensure you are using the latest version of Hardware Sniffer before generating the hardware report.")
print("- Hardware Sniffer will not collect information related to Resizable BAR option of GPU (disabled by default) and monitor connections in Windows PE.")
print("")
print("E. Export hardware report (Recommended)")
print("")
print("Q. Quit")
print("")
WINDOW_MIN_SIZE = (1000, 700)
WINDOW_DEFAULT_SIZE = (1200, 800)
class OCS(FluentWindow):
open_result_folder_signal = pyqtSignal(str)
PLATFORM_FONTS = {
"Windows": "Segoe UI",
"Darwin": "SF Pro Display",
"Linux": "Ubuntu"
}
def __init__(self, backend):
super().__init__()
self.backend = backend
self.settings = self.backend.settings
self.ui_utils = ui_utils.UIUtils()
user_input = self.u.request_input("Drag and drop your hardware report here (.JSON){}: ".format(" or type \"E\" to export" if os.name == "nt" else ""))
if user_input.lower() == "q":
self.u.exit_program()
if user_input.lower() == "e":
hardware_sniffer = self.o.gather_hardware_sniffer()
self._init_state()
self._setup_window()
self._connect_signals()
self._setup_backend_handlers()
self.init_navigation()
if not hardware_sniffer:
continue
def _init_state(self):
self.hardware_state = HardwareReportState()
self.macos_state = macOSVersionState()
self.smbios_state = SMBIOSState()
self.build_state = BuildState()
self.build_btn = None
self.progress_bar = None
self.progress_label = None
self.build_log = None
self.open_result_btn = None
report_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "SysReport")
def _setup_window(self):
self.setWindowTitle("OpCore Simplify")
self.setMinimumSize(*WINDOW_MIN_SIZE)
self._restore_window_geometry()
self.u.head("Exporting Hardware Report")
print("")
print("Exporting hardware report to {}...".format(report_dir))
output = self.r.run({
"args":[hardware_sniffer, "-e", "-o", report_dir]
})
if output[-1] != 0:
error_code = output[-1]
if error_code == 3:
error_message = "Error collecting hardware."
elif error_code == 4:
error_message = "Error generating hardware report."
elif error_code == 5:
error_message = "Error dumping ACPI tables."
else:
error_message = "Unknown error."
print("")
print("Could not export the hardware report. {}".format(error_message))
print("Please try again or using Hardware Sniffer manually.")
print("")
self.u.request_input()
continue
else:
report_path = os.path.join(report_dir, "Report.json")
acpitables_dir = os.path.join(report_dir, "ACPI")
report_data = self.u.read_file(report_path)
self.ac.read_acpi_tables(acpitables_dir)
return report_path, report_data
path = self.u.normalize_path(user_input)
font = QFont()
system = platform.system()
font_family = self.PLATFORM_FONTS.get(system, "Ubuntu")
font.setFamily(font_family)
font.setStyleHint(QFont.StyleHint.SansSerif)
self.setFont(font)
def _restore_window_geometry(self):
saved_geometry = self.settings.get("window_geometry")
if saved_geometry and isinstance(saved_geometry, dict):
x = saved_geometry.get("x")
y = saved_geometry.get("y")
width = saved_geometry.get("width", WINDOW_DEFAULT_SIZE[0])
height = saved_geometry.get("height", WINDOW_DEFAULT_SIZE[1])
is_valid, errors, warnings, data = self.v.validate_report(path)
if x is not None and y is not None:
screen = QApplication.primaryScreen()
if screen:
screen_geometry = screen.availableGeometry()
if (screen_geometry.left() <= x <= screen_geometry.right() and
screen_geometry.top() <= y <= screen_geometry.bottom()):
self.setGeometry(x, y, width, height)
return
self._center_window()
def _center_window(self):
screen = QApplication.primaryScreen()
if screen:
screen_geometry = screen.availableGeometry()
window_width = WINDOW_DEFAULT_SIZE[0]
window_height = WINDOW_DEFAULT_SIZE[1]
self.v.show_validation_report(path, is_valid, errors, warnings)
if not is_valid or errors:
print("")
print("\033[32mSuggestion:\033[0m Please re-export the hardware report and try again.")
print("")
self.u.request_input("Press Enter to go back...")
else:
return path, data
x = screen_geometry.left() + (screen_geometry.width() - window_width) // 2
y = screen_geometry.top() + (screen_geometry.height() - window_height) // 2
def show_oclp_warning(self):
while True:
self.u.head("OpenCore Legacy Patcher Warning")
print("")
print("1. OpenCore Legacy Patcher is the only solution to enable dropped GPU and Broadcom WiFi")
print(" support in newer macOS versions, as well as to bring back AppleHDA for macOS Tahoe 26.")
print("")
print("2. OpenCore Legacy Patcher disables macOS security features including SIP and AMFI, which may")
print(" lead to issues such as requiring full installers for updates, application crashes, and")
print(" system instability.")
print("")
print("3. OpenCore Legacy Patcher is not officially supported for Hackintosh community.")
print("")
print("\033[1;91mImportant:\033[0m")
print("Please consider these risks carefully before proceeding.")
print("")
print("\033[1;96mSupport for macOS Tahoe 26:\033[0m")
print("To patch macOS Tahoe 26, you must download OpenCore-Patcher 3.0.0 or newer from")
print("my repository: \033[4mlzhoang2801/OpenCore-Legacy-Patcher\033[0m on GitHub.")
print("Older or official Dortania releases are NOT supported for Tahoe 26.")
print("")
option = self.u.request_input("Do you want to continue with OpenCore Legacy Patcher? (yes/No): ").strip().lower()
if option == "yes":
return True
elif option == "no":
self.setGeometry(x, y, window_width, window_height)
else:
self.resize(*WINDOW_DEFAULT_SIZE)
def _save_window_geometry(self):
geometry = self.geometry()
window_geometry = {
"x": geometry.x(),
"y": geometry.y(),
"width": geometry.width(),
"height": geometry.height()
}
self.settings.set("window_geometry", window_geometry)
def closeEvent(self, event):
self._save_window_geometry()
super().closeEvent(event)
def _connect_signals(self):
self.backend.log_message_signal.connect(
lambda message, level, to_build_log: (
[
self.build_log.append(line)
for line in (message.splitlines() or [""])
]
if to_build_log and getattr(self, "build_log", None) else None
)
)
self.backend.update_status_signal.connect(self.update_status)
self.open_result_folder_signal.connect(self._handle_open_result_folder)
def _setup_backend_handlers(self):
self.backend.u.gui_handler = self
set_default_gui_handler(self)
def init_navigation(self):
self.homePage = HomePage(self, ui_utils_instance=self.ui_utils)
self.SelectHardwareReportPage = SelectHardwareReportPage(self, ui_utils_instance=self.ui_utils)
self.compatibilityPage = CompatibilityPage(self, ui_utils_instance=self.ui_utils)
self.configurationPage = ConfigurationPage(self, ui_utils_instance=self.ui_utils)
self.buildPage = BuildPage(self, ui_utils_instance=self.ui_utils)
self.settingsPage = SettingsPage(self)
self.addSubInterface(
self.homePage,
FluentIcon.HOME,
"Home",
NavigationItemPosition.TOP
)
self.addSubInterface(
self.SelectHardwareReportPage,
FluentIcon.FOLDER_ADD,
"1. Select Hardware Report",
NavigationItemPosition.TOP
)
self.addSubInterface(
self.compatibilityPage,
FluentIcon.CHECKBOX,
"2. Check Compatibility",
NavigationItemPosition.TOP
)
self.addSubInterface(
self.configurationPage,
FluentIcon.EDIT,
"3. Configure OpenCore EFI",
NavigationItemPosition.TOP
)
self.addSubInterface(
self.buildPage,
FluentIcon.DEVELOPER_TOOLS,
"4. Build & Review",
NavigationItemPosition.TOP
)
self.navigationInterface.addSeparator()
self.addSubInterface(
self.settingsPage,
FluentIcon.SETTING,
"Settings",
NavigationItemPosition.BOTTOM
)
def _handle_open_result_folder(self, folder_path):
self.backend.u.open_folder(folder_path)
def update_status(self, message, status_type="INFO"):
if status_type == "success":
InfoBar.success(
title="Success",
content=message,
orient=Qt.Orientation.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=3000,
parent=self
)
elif status_type == "ERROR":
InfoBar.error(
title="ERROR",
content=message,
orient=Qt.Orientation.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=5000,
parent=self
)
elif status_type == "WARNING":
InfoBar.warning(
title="WARNING",
content=message,
orient=Qt.Orientation.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=4000,
parent=self
)
else:
InfoBar.info(
title="INFO",
content=message,
orient=Qt.Orientation.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=3000,
parent=self
)
def validate_prerequisites(self, require_hardware_report=True, require_dsdt=True, require_darwin_version=True, check_compatibility_error=True, require_customized_hardware=True, show_status=True):
if require_hardware_report:
if not self.hardware_state.hardware_report:
if show_status:
self.update_status("Please select hardware report first", "WARNING")
return False
if require_dsdt:
if not self.backend.ac._ensure_dsdt():
if show_status:
self.update_status("Please load ACPI tables first", "WARNING")
return False
if check_compatibility_error:
if self.hardware_state.compatibility_error:
if show_status:
self.update_status("Incompatible hardware detected, please select different hardware report and try again", "WARNING")
return False
if require_darwin_version:
if not self.macos_state.darwin_version:
if show_status:
self.update_status("Please select target macOS version first", "WARNING")
return False
def select_macos_version(self, hardware_report, native_macos_version, ocl_patched_macos_version):
suggested_macos_version = native_macos_version[1]
version_pattern = re.compile(r'^(\d+)(?:\.(\d+)(?:\.(\d+))?)?$')
for device_type in ("GPU", "Network", "Bluetooth", "SD Controller"):
if device_type in hardware_report:
for device_name, device_props in hardware_report[device_type].items():
if device_props.get("Compatibility", (None, None)) != (None, None):
if device_type == "GPU" and device_props.get("Device Type") == "Integrated GPU":
device_id = device_props.get("Device ID", ""*8)[5:]
if device_props.get("Manufacturer") == "AMD" or device_id.startswith(("59", "87C0")):
suggested_macos_version = "22.99.99"
elif device_id.startswith(("09", "19")):
suggested_macos_version = "21.99.99"
if self.u.parse_darwin_version(suggested_macos_version) > self.u.parse_darwin_version(device_props.get("Compatibility")[0]):
suggested_macos_version = device_props.get("Compatibility")[0]
while True:
if "Beta" in os_data.get_macos_name_by_darwin(suggested_macos_version):
suggested_macos_version = "{}{}".format(int(suggested_macos_version[:2]) - 1, suggested_macos_version[2:])
else:
break
while True:
self.u.head("Select macOS Version")
if native_macos_version[1][:2] != suggested_macos_version[:2]:
print("")
print("\033[1;36mSuggested macOS version:\033[0m")
print("- For better compatibility and stability, we suggest you to use only {} or older.".format(os_data.get_macos_name_by_darwin(suggested_macos_version)))
print("")
print("Available macOS versions:")
print("")
oclp_min = int(ocl_patched_macos_version[-1][:2]) if ocl_patched_macos_version else 99
oclp_max = int(ocl_patched_macos_version[0][:2]) if ocl_patched_macos_version else 0
min_version = min(int(native_macos_version[0][:2]), oclp_min)
max_version = max(int(native_macos_version[-1][:2]), oclp_max)
for darwin_version in range(min_version, max_version + 1):
name = os_data.get_macos_name_by_darwin(str(darwin_version))
label = " (\033[1;93mRequires OpenCore Legacy Patcher\033[0m)" if oclp_min <= darwin_version <= oclp_max else ""
print(" {}. {}{}".format(darwin_version, name, label))
print("")
print("\033[1;93mNote:\033[0m")
print("- To select a major version, enter the number (e.g., 19).")
print("- To specify a full version, use the Darwin version format (e.g., 22.4.6).")
print("")
print("Q. Quit")
print("")
option = self.u.request_input("Please enter the macOS version you want to use (default: {}): ".format(os_data.get_macos_name_by_darwin(suggested_macos_version))) or suggested_macos_version
if option.lower() == "q":
self.u.exit_program()
match = version_pattern.match(option)
if match:
target_version = "{}.{}.{}".format(match.group(1), match.group(2) if match.group(2) else 99, match.group(3) if match.group(3) else 99)
if ocl_patched_macos_version and self.u.parse_darwin_version(ocl_patched_macos_version[-1]) <= self.u.parse_darwin_version(target_version) <= self.u.parse_darwin_version(ocl_patched_macos_version[0]):
return target_version
elif self.u.parse_darwin_version(native_macos_version[0]) <= self.u.parse_darwin_version(target_version) <= self.u.parse_darwin_version(native_macos_version[-1]):
return target_version
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"
]
if require_customized_hardware:
if not self.hardware_state.customized_hardware:
if show_status:
self.update_status("Please reload hardware report and select target macOS version to continue", "WARNING")
return False
title = "Building OpenCore EFI"
return True
self.u.progress_bar(title, steps, 0)
self.u.create_folder(self.result_dir, remove_content=True)
def apply_macos_version(self, version):
self.macos_state.darwin_version = version
self.macos_state.selected_version_name = os_data.get_macos_name_by_darwin(version)
if not os.path.exists(self.k.ock_files_dir):
raise Exception("Directory '{}' does not exist.".format(self.k.ock_files_dir))
self.hardware_state.customized_hardware, self.hardware_state.disabled_devices, self.macos_state.needs_oclp = self.backend.h.hardware_customization(self.hardware_state.hardware_report, version)
self.smbios_state.model_name = self.backend.s.select_smbios_model(self.hardware_state.customized_hardware, version)
source_efi_dir = os.path.join(self.k.ock_files_dir, "OpenCorePkg")
shutil.copytree(source_efi_dir, self.result_dir, dirs_exist_ok=True)
config_file = os.path.join(self.result_dir, "EFI", "OC", "config.plist")
config_data = self.u.read_file(config_file)
self.backend.ac.select_acpi_patches(self.hardware_state.customized_hardware, self.hardware_state.disabled_devices)
if not config_data:
raise Exception("Error: The file {} does not exist.".format(config_file))
self.macos_state.needs_oclp, audio_layout_id, audio_controller_properties = self.backend.k.select_required_kexts(self.hardware_state.customized_hardware, version, self.macos_state.needs_oclp, self.backend.ac.patches)
self.u.progress_bar(title, steps, 1)
config_data["ACPI"]["Add"] = []
config_data["ACPI"]["Delete"] = []
config_data["ACPI"]["Patch"] = []
if self.ac.ensure_dsdt():
self.ac.hardware_report = hardware_report
self.ac.disabled_devices = disabled_devices
self.ac.acpi_directory = os.path.join(self.result_dir, "EFI", "OC", "ACPI")
self.ac.smbios_model = smbios_model
self.ac.lpc_bus_device = self.ac.get_lpc_name()
if audio_layout_id is not None:
self.hardware_state.audio_layout_id = audio_layout_id
self.hardware_state.audio_controller_properties = audio_controller_properties
for patch in self.ac.patches:
if patch.checked:
if patch.name == "BATP":
patch.checked = getattr(self.ac, patch.function_name)()
self.k.kexts[kext_maestro.kext_data.kext_index_by_name.get("ECEnabler")].checked = patch.checked
continue
self.backend.s.smbios_specific_options(self.hardware_state.customized_hardware, self.smbios_state.model_name, version, self.backend.ac.patches, self.backend.k)
acpi_load = getattr(self.ac, patch.function_name)()
self.configurationPage.update_display()
if not isinstance(acpi_load, dict):
continue
def setup_exception_hook(self):
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
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(self.ac.dsdt_patches)
config_data["ACPI"]["Patch"] = self.ac.apply_acpi_patches(config_data["ACPI"]["Patch"])
self.u.progress_bar(title, steps, 2)
kexts_directory = os.path.join(self.result_dir, "EFI", "OC", "Kexts")
self.k.install_kexts_to_efi(macos_version, kexts_directory)
config_data["Kernel"]["Add"] = self.k.load_kexts(hardware_report, macos_version, kexts_directory)
self.u.progress_bar(title, steps, 3)
self.co.genarate(hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp, self.k.kexts, config_data)
self.u.write_file(config_file, config_data)
self.u.progress_bar(title, steps, 4)
files_to_remove = []
drivers_directory = os.path.join(self.result_dir, "EFI", "OC", "Drivers")
driver_list = self.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(self.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(self.result_dir, "EFI", "OC", "Resources", "Image")
available_picker_variants = self.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(self.result_dir, "EFI", "OC", "Tools")
tool_list = self.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(self.result_dir):
files_to_remove.append(os.path.join(self.result_dir, "manifest.json"))
for file_path in files_to_remove:
error_details = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
error_message = "Uncaught exception detected:\n{}".format(error_details)
self.backend.u.log_message(error_message, level="ERROR")
try:
if os.path.isdir(file_path):
shutil.rmtree(file_path)
else:
os.remove(file_path)
except Exception as e:
print("Failed to remove file: {}".format(e))
self.u.progress_bar(title, steps, len(steps), done=True)
print("OpenCore EFI build complete.")
time.sleep(2)
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))")
sys.__stderr__.write("\n[CRITICAL ERROR] {}\n".format(error_message))
except:
pass
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
sys.excepthook = handle_exception
def before_using_efi(self, org_hardware_report, hardware_report):
while True:
self.u.head("Before Using EFI")
print("")
print("\033[93mPlease complete the following steps:\033[0m")
print("")
bios_requirements = self.check_bios_requirements(org_hardware_report, hardware_report)
if bios_requirements:
print("* BIOS/UEFI Settings Required:")
for requirement in bios_requirements:
print(" - {}".format(requirement))
print("")
print("* USB Mapping:")
print(" - Use USBToolBox tool to map USB ports.")
print(" - Add created UTBMap.kext into the {} folder.".format("EFI\\OC\\Kexts" if os.name == "nt" else "EFI/OC/Kexts"))
print(" - Remove UTBDefault.kext in the {} folder.".format("EFI\\OC\\Kexts" if os.name == "nt" else "EFI/OC/Kexts"))
print(" - Edit config.plist:")
print(" - Use ProperTree to open your config.plist.")
print(" - Run OC Snapshot by pressing Command/Ctrl + R.")
print(" - If you have more than 15 ports on a single controller, enable the XhciPortLimit patch.")
print(" - Save the file when finished.")
print("")
print("Type \"AGREE\" to open the built EFI for you\n")
response = self.u.request_input("")
if response.lower() == "agree":
self.u.open_folder(self.result_dir)
break
else:
print("\033[91mInvalid input. Please try again.\033[0m")
def main(self):
hardware_report_path = None
native_macos_version = None
disabled_devices = None
macos_version = None
ocl_patched_macos_version = None
needs_oclp = False
smbios_model = None
while True:
self.u.head()
print("")
print(" Hardware Report: {}".format(hardware_report_path or 'Not selected'))
if hardware_report_path:
print("")
print(" macOS Version: {}".format(os_data.get_macos_name_by_darwin(macos_version) if macos_version else 'Not selected') + (' (' + macos_version + ')' if macos_version else '') + ('. \033[1;93mRequires OpenCore Legacy Patcher\033[0m' if needs_oclp else ''))
print(" SMBIOS: {}".format(smbios_model or 'Not selected'))
if disabled_devices:
print(" Disabled Devices:")
for device, _ in disabled_devices.items():
print(" - {}".format(device))
print("")
print("1. Select Hardware Report")
print("2. Select macOS Version")
print("3. Customize ACPI Patch")
print("4. Customize Kexts")
print("5. Customize SMBIOS Model")
print("6. Build OpenCore EFI")
print("")
print("Q. Quit")
print("")
option = self.u.request_input("Select an option: ")
if option.lower() == "q":
self.u.exit_program()
if option == "1":
hardware_report_path, hardware_report = self.select_hardware_report()
hardware_report, native_macos_version, ocl_patched_macos_version = self.c.check_compatibility(hardware_report)
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version)
smbios_model = self.s.select_smbios_model(customized_hardware, macos_version)
if not self.ac.ensure_dsdt():
self.ac.select_acpi_tables()
self.ac.select_acpi_patches(customized_hardware, disabled_devices)
needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
if not hardware_report_path:
self.u.head()
print("\n\n")
print("\033[1;93mPlease select a hardware report first.\033[0m")
print("\n\n")
self.u.request_input("Press Enter to go back...")
continue
if option == "2":
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version)
smbios_model = self.s.select_smbios_model(customized_hardware, macos_version)
needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
elif option == "3":
self.ac.customize_patch_selection()
elif option == "4":
self.k.kext_configuration_menu(macos_version)
elif option == "5":
smbios_model = self.s.customize_smbios_model(customized_hardware, smbios_model, macos_version)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
elif option == "6":
if needs_oclp and not self.show_oclp_warning():
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version)
smbios_model = self.s.select_smbios_model(customized_hardware, macos_version)
needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
continue
try:
self.o.gather_bootloader_kexts(self.k.kexts, macos_version)
except Exception as e:
print("\033[91mError: {}\033[0m".format(e))
print("")
self.u.request_input("Press Enter to continue...")
continue
self.build_opencore_efi(customized_hardware, disabled_devices, smbios_model, macos_version, needs_oclp)
self.before_using_efi(hardware_report, customized_hardware)
self.u.head("Result")
print("")
print("Your OpenCore EFI for {} has been built at:".format(customized_hardware.get("Motherboard").get("Name")))
print("\t{}".format(self.result_dir))
print("")
self.u.request_input("Press Enter to main menu...")
if __name__ == '__main__':
update_flag = updater.Updater().run_update()
if update_flag:
os.execv(sys.executable, ['python3'] + sys.argv)
o = OCPE()
while True:
try:
o.main()
except Exception as e:
o.u.head("An Error Occurred")
print("")
print(traceback.format_exc())
o.u.request_input()
if __name__ == "__main__":
backend = Backend()
app = QApplication(sys.argv)
set_default_gui_handler(app)
window = OCS(backend)
window.setup_exception_hook()
window.show()
if backend.settings.get_auto_update_check():
updater.Updater(
utils_instance=backend.u,
github_instance=backend.github,
resource_fetcher_instance=backend.resource_fetcher,
run_instance=backend.r,
integrity_checker_instance=backend.integrity_checker
).run_update()
sys.exit(app.exec())