diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000..56c34a3f39 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,13 @@ +[MASTER] + +init-hook="from pylint.config import find_pylintrc; import os, sys; sys.path.append(os.path.dirname(find_pylintrc()))" + +[MESSAGES CONTROL] + +disable=unused-import, + subprocess-run-check, + line-too-long, + too-few-public-methods, + missing-module-docstring, + missing-class-docstring, + missing-function-docstring \ No newline at end of file diff --git a/Build-App.command b/Build-App.command new file mode 100755 index 0000000000..d5ecf2a0cb --- /dev/null +++ b/Build-App.command @@ -0,0 +1,52 @@ +#!/usr/bin/env python +from __future__ import print_function + +from shutil import copy +from shutil import rmtree +from distutils.dir_util import copy_tree + +import os +import json +import subprocess +import sys +import zipfile + +os.chdir(os.path.dirname(os.path.realpath(__file__))) +current_path = os.getcwd() + +print(current_path) + +# File location +command_path = os.path.join(current_path, "OpenCore-Patcher.command") +resources_path = os.path.join(current_path, "Resources/") +payloads_path = os.path.join(current_path, "payloads/") +icns_path = os.path.join(current_path, "OC-Patcher.icns") +plist_path = os.path.join(current_path, "Info.plist") + +app_path = os.path.join(current_path, "App/") +app_app_path = os.path.join(current_path, "App/OpenCore-Patcher.app/") +contents_path = os.path.join(current_path, "App/OpenCore-Patcher.app/Contents/") +app_macos_path = os.path.join(current_path, "App/OpenCore-Patcher.app/Contents/MacOS/") +app_macos_payload_path = os.path.join(current_path, "App/OpenCore-Patcher.app/Contents/MacOS/payloads") +app_macos_resources_path = os.path.join(current_path, "App/OpenCore-Patcher.app/Contents/MacOS/Resources") +app_resources_path = os.path.join(current_path, "App/OpenCore-Patcher.app/Contents/Resources/") + + +if os.path.exists(app_path): + print("Cleaning App folder") + rmtree(app_path) + +print("Creating new App folder") +os.mkdir(app_path) +os.mkdir(app_app_path) +os.mkdir(contents_path) +os.mkdir(app_macos_path) +os.mkdir(app_resources_path) + +copy(command_path, app_macos_path) +copy_tree(resources_path, app_macos_resources_path) +copy_tree(payloads_path, app_macos_payload_path) +copy(icns_path, app_resources_path) +copy(plist_path, contents_path) +copy(icns_path, app_macos_path) + diff --git a/OpenCore-Patcher.command b/OpenCore-Patcher.command index d8e113c95e..676ad22fdf 100755 --- a/OpenCore-Patcher.command +++ b/OpenCore-Patcher.command @@ -1,234 +1,108 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 -from shutil import copy -from shutil import rmtree +from __future__ import print_function -import os -import json import subprocess -import sys -import zipfile - -from Resources import * - - -# Allow py2 and 3 support -try: - input = raw_input -except NameError: - pass - -# List build versions -patcher_version = "0.0.9" - -CustomSMBIOS=False -MainMenu=True -MenuWidth = 52 -header = '#' * MenuWidth -subheader = '-' * MenuWidth - -while MainMenu: - os.system('clear') - - print(header) - print(" OpenCore Legacy patcher v%s" % patcher_version) - print(" Current Model: %s" % BuildOpenCore.current_model) - print(header) - print("") - if BuildOpenCore.current_model not in ModelArray.SupportedSMBIOS: - print(" Your model is not supported by this patcher!") - print("") - print(" If you plan to create the USB for another machine,") - print(" please select option 5") - print(subheader) - print("") - elif BuildOpenCore.current_model in ("MacPro3,1", "iMac7,1"): - print(" This model is supported") - print(" However please ensure the CPU have been upgraded") - print(" to support SSE4.1+") - print(subheader) - print("") - else: - print(" This model is supported") - print(subheader) - print("") - print(" 1. Build OpenCore") - print(" 2. Install OpenCore to USB/internal drive") - print(" 3. Change model") - print(" 4. Credits") - print(" 5. Exit") - print("") - - MainMenu = input('Please select an option: ') - - if MainMenu=="1": - OpenCoreBuilderMenu=True - while OpenCoreBuilderMenu: - os.system('clear') - - print(header) - print(" Build OpenCore v%s for model: %s" % (Versions.opencore_version, BuildOpenCore.current_model)) - print(header) - print("") - print(" 1. Auto build OpenCore") - print(" 2. Change OpenCore version") - print(" 3. Return to main menu") - print("") - - OpenCoreBuilderMenu = input('Please select an option: ') - - if OpenCoreBuilderMenu=="1": - AutoBuilderMenu=True - while AutoBuilderMenu: - os.system('clear') - print(header) - print(" Building OpenCore for model: %s" % BuildOpenCore.current_model) - print(header) - print("") - print("The current working directory:") - print (" %s" % Versions.current_path) - print("") - BuildOpenCore.BuildEFI() - #BuildOpenCore.BuildGUI() - BuildOpenCore.BuildSMBIOS() - BuildOpenCore.SavePlist() - BuildOpenCore.CleanBuildFolder() - print("") - print("Your OpenCore EFI has been built at:") - print(" %s" % Versions.opencore_path_done) - print("") - AutoBuilderMenu = input("Press any key to return to previous menu: ") - if AutoBuilderMenu=="1": - print("Returning to previous menu...") - AutoBuilderMenu=False - OpenCoreBuilderMenu=False - elif OpenCoreBuilderMenu=="2": - ChangeOCversion=True - while ChangeOCversion: - os.system('clear') - print(header) - print(" Current OpenCore version: %s" % Versions.opencore_version) - print(header) - print("") - print(" Supported versions: 0.6.3, 0.6.4") - print("") - OpenCoreOption = input('Please enter the OpenCore you want (Press enter to exit): ') - if OpenCoreOption == "": - print("Exiting...") - ChangeOCversion=False - MainMenu=True - else: - print("") - print(" New SMBIOS: %s" % OpenCoreOption) - print("") - ChangeOCversionYN = input("Is this correct? (y/n)") - if ChangeOCversionYN in {"y", "Y", "yes", "Yes"}: - ChangeOCversion=False - Versions.opencore_version = OpenCoreOption - MainMenu=True - elif OpenCoreBuilderMenu=="3": - print("\n Returning to main menu...") - OpenCoreBuilderMenu=False - MainMenu=True - else: - print("\n Not Valid Choice Try again") - OpenCoreBuilderMenu = True - - - elif MainMenu=="2": - print("\n Not yet implemented") - OpenCoreInstallerMenu=True - while OpenCoreInstallerMenu: - os.system('clear') - - print(header) - print(" Install OpenCore to drive") - print(header) - print("") - print(" 1. Install to USB/internal drive") - print(" 2. Return to main menu") - print("") - - OpenCoreInstallerMenu = input('Please select an option: ') - - if OpenCoreInstallerMenu=="1": - os.system('clear') - if os.path.exists(Versions.opencore_path_done): - print("Found OpenCore in Build Folder") - BuildOpenCore.ListDiskutil() - BuildOpenCore.MoveOpenCore() - - else: - print("OpenCore folder missing!") - print("Please build OpenCore first") - print("") - OpenCoreInstallerMenu = input("Press any key to exit: ") - if OpenCoreInstallerMenu=="1": - print("Returning to main menu...") - OpenCoreInstallerMenu=False - elif OpenCoreInstallerMenu=="2": - print("\n Returning to main menu...") - OpenCoreInstallerMenu=False - MainMenu=True +from pathlib import Path + +from Resources import build, ModelArray, Versions, utilities + +PATCHER_VERSION = "0.0.9" + + +class OpenCoreLegacyPatcher(): + def __init__(self): + self.custom_model: str = None + self.current_model: str = None + opencore_model: str = subprocess.run("nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode() + if not opencore_model.startswith("nvram: Error getting variable"): + opencore_model = subprocess.run("nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + opencore_model = [line.strip().split(":oem-product ", 1)[1] for line in opencore_model.stdout.decode().split("\n") if line.strip().startswith("4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:")][0] + self.current_model = opencore_model + else: + self.current_model = subprocess.run("system_profiler SPHardwareDataType".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + self.current_model = [line.strip().split(": ", 1)[1] for line in self.current_model.stdout.decode().split("\n") if line.strip().startswith("Model Identifier")][0] + + def build_opencore(self): + build.OpenCoreMenus().build_opencore_menu(self.custom_model or self.current_model) + + def install_opencore(self): + utilities.cls() + utilities.header(["Installing OpenCore to Drive"]) + + if Path(Versions.opencore_path_done).exists(): + print("\nFound OpenCore in Build Folder") + build.BuildOpenCore.copy_efi() + input("Press [Enter] to go back.") + + else: + utilities.TUIOnlyPrint(["Installing OpenCore to Drive"], + "Press [Enter] to go back.\n", + ["""OpenCore folder missing! +Please build OpenCore first!"""]).start() + + def change_model(self): + utilities.cls() + utilities.header(["Select Different Model"]) + print(""" +Tip: Run the following command on the target machine to find the model identifier: + +system_profiler SPHardwareDataType | grep 'Model Identifier' + """) + self.custom_model = input("Please enter the model identifier of the target machine: ").strip() + + def credits(self): + utilities.TUIOnlyPrint(["Credits"], "Press enter to go back\n", + ["""Many thanks to the following: + + - Acidanthera:\tOpenCore, kexts and other tools + - DhinakG:\t\tWriting and maintaining this patcher + - Khronokernel:\tWriting and maintaining this patcher + - Syncretic:\t\tAAAMouSSE and telemetrap + - Slice:\t\tVoodooHDA"""]).start() + + def main_menu(self): + response = None + while not (response and response == -1): + title = [ + f"OpenCore Legacy Patcher v{PATCHER_VERSION}", + f"Selected Model: {self.custom_model or self.current_model}" + ] + + if (self.custom_model or self.current_model) not in ModelArray.SupportedSMBIOS: + in_between = [ + 'Your model is not supported by this patcher!', + '', + 'If you plan to create the USB for another machine, please select the "Change Model" option in the menu.' + ] + elif not self.custom_model and self.current_model in ("MacPro3,1", "iMac7,1") and \ + "SSE4.1" not in subprocess.run("sysctl machdep.cpu.features".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode(): + in_between = [ + 'Your model requires a CPU upgrade to a CPU supporting SSE4.1+ to be supported by this patcher!', + '', + 'If you plan to create the USB for another machine, please select option 5' + ] + elif self.custom_model in ("MacPro3,1", "iMac7,1"): + in_between = ["This model is supported", + "However please ensure the CPU has been upgraded to support SSE4.1+" + ] else: - print("\n Not Valid Choice Try again") - OpenCoreInstallerMenu = True - - elif MainMenu=="3": - SMBIOSMenu=True - while SMBIOSMenu: - os.system('clear') - - print(header) - print(" Enter a new SMBIOS") - print(header) - print("") - print(" Tip: Run this command on the machine to find the SMBIOS") - print("") - print(" system_profiler SPHardwareDataType | grep 'Model Identifier'") - print("") - SMBIOSOption = input('Please enter the SMBIOS of your machine (Press enter to exit): ') - if SMBIOSOption == "": - print("Exiting...") - SMBIOSMenu=False - MainMenu=True - else: - print("") - print(" New SMBIOS: %s" % SMBIOSOption) - print("") - SMBIOSMenuYN = input("Is this correct? (y/n)") - if SMBIOSMenuYN in {"y", "Y", "yes", "Yes"}: - SMBIOSMenu=False - BuildOpenCore.current_model = SMBIOSOption - MainMenu=True - CustomSMBIOS=True - elif MainMenu=="4": - CreditMenu=True - while CreditMenu: - os.system('clear') - - print(header) - print(" Credits") - print(header) - print("") - print(" Many thanks to the following:") - print("") - print(" - Acidanthera: OpenCore, kexts and other tools") - print(" - DhinakG: Writing and maintaining this Patcher") - print(" - Khronokernel: Writing and maintaining this Patcher") - print(" - Syncretic: AAAMouSSE and telemetrap") - print(" - Slice: VoodooHDA") - print("") - CreditMenu = input(" Press any key to exit: ") - print("Returning to main menu...") - CreditMenu=False - MainMenu=True - - elif MainMenu=="5": - print("\n Closing program...") - sys.exit(1) - else: - print("\n Not Valid Choice Try again") - MainMenu=True + in_between = ["This model is supported"] + + menu = utilities.TUIMenu(title, "Please select an option: ", in_between=in_between, auto_number=True, top_level=True) + + options = ([["Build OpenCore", self.build_opencore]] if ((self.custom_model or self.current_model) in ModelArray.SupportedSMBIOS) else []) + [ + ["Install OpenCore to USB/internal drive", self.install_opencore], + ["Change Model", self.change_model], + ["Credits", self.credits] + ] + + for option in options: + menu.add_menu_option(option[0], function=option[1]) + + response = menu.start() + + print("Bye") + +OpenCoreLegacyPatcher().main_menu() diff --git a/OpenCore-Patcher.spec b/OpenCore-Patcher.spec new file mode 100644 index 0000000000..17e72ff41f --- /dev/null +++ b/OpenCore-Patcher.spec @@ -0,0 +1,37 @@ +# -*- mode: python ; coding: utf-8 -*- + +block_cipher = None + + +a = Analysis(['OpenCore-Patcher.command'], + pathex=['/Users/dhinak/Documents/GitHub/Opencore-Legacy-Patcher'], + binaries=[], + datas=[('payloads', 'payloads'), ('Resources', 'Resources')], + hiddenimports=[], + hookspath=[], + 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='OpenCore-Patcher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True ) +app = BUNDLE(exe, + name='OpenCore-Patcher.app', + icon=None, + bundle_identifier=None) diff --git a/Resources/BuildOpenCore.py b/Resources/BuildOpenCore.py deleted file mode 100644 index c6ffb4cdf1..0000000000 --- a/Resources/BuildOpenCore.py +++ /dev/null @@ -1,399 +0,0 @@ -# Commands for building the EFI and SMBIOS - -from __future__ import print_function - -from shutil import copy -from shutil import rmtree -from distutils.dir_util import copy_tree - -import os -import json -import subprocess -import sys -import zipfile - -from Resources import Versions -from Resources import ModelArray - -# Allow py2 and 3 support -try: - input = raw_input -except NameError: - pass - -# Find SMBIOS of machine -opencore_model = subprocess.Popen(["NVRAM", "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product"], stdout=subprocess.PIPE).communicate()[0] -if opencore_model not in ("NVRAM: Error getting variable - '4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product': (iokit/common) data was not found"): - print("Detected OpenCore machine") - opencore_model = subprocess.Popen("nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product".split(), stdout=subprocess.PIPE) - opencore_model = [line.strip().split(":oem-product ", 1)[1] for line in opencore_model.stdout.read().split("\n") if line.strip().startswith("4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:")][0] - current_model = opencore_model -else: - print("No OpenCore detected") - current_model = subprocess.Popen("system_profiler SPHardwareDataType".split(), stdout=subprocess.PIPE) - current_model = [line.strip().split(": ", 1)[1] for line in current_model.stdout.read().split("\n") if line.strip().startswith("Model Identifier")][0] - print("Current Model: %s" % current_model) - -OCExist = False - -def BuildEFI(): - - if not os.path.exists(Versions.build_path): - os.makedirs(Versions.build_path) - print("Created Build Folder") - else: - print("Build Folder already present, skipping") - # Copy OpenCore into Build Folder - - if os.path.exists(Versions.opencore_path_build): - print("Deleting old copy of OpenCore zip") - os.remove(Versions.opencore_path_build) - if os.path.exists(Versions.opencore_path_done): - print("Deleting old copy of OpenCore folder") - rmtree(Versions.opencore_path_done) - print("") - print("- Adding OpenCore v%s" % Versions.opencore_version) - copy(Versions.opencore_path, Versions.build_path) - zipfile.ZipFile(Versions.opencore_path_build).extractall(Versions.build_path) - - print("- Adding config.plist v%s" % Versions.opencore_version) - # Setup config.plist for editing - copy(Versions.plist_path, Versions.plist_path_build) - with open(Versions.plist_path_build_full, 'r') as file : - Versions.plist_data = file.read() - # Adding must have kexts - print("- Adding Lilu v%s" % Versions.lilu_version) - copy(Versions.lilu_path, Versions.kext_path_build) - - print("- Adding WhateverGreen v%s" % Versions.whatevergreen_version) - copy(Versions.whatevergreen_path, Versions.kext_path_build) - - if current_model in ModelArray.MacPro71: - print("- Adding RestrictEvents v%s" % Versions.restrictevents_version) - copy(Versions.restrictevents_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - # Checks for kexts - # CPU Kext Patches - if current_model in ModelArray.DualSocket: - print("- Adding AppleMCEReporterDisabler v%s" % Versions.mce_version) - copy(Versions.mce_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - if current_model in ModelArray.SSEEmulator: - print("- Adding AAAMouSSE v%s" % Versions.mousse_version) - copy(Versions.mousse_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - if current_model in ModelArray.MissingSSE42: - print("- Adding telemetrap v%s" % Versions.telemetrap_version) - copy(Versions.telemetrap_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - # Ethernet Patches - - if current_model in ModelArray.EthernetNvidia: - print("- Adding nForceEthernet v%s" % Versions.nforce_version) - copy(Versions.nforce_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - if current_model in ModelArray.EthernetMarvell: - print("- Adding MarvelYukonEthernet v%s" % Versions.marvel_version) - copy(Versions.marvel_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - if current_model in ModelArray.EthernetBroadcom: - print("- Adding CatalinaBCM5701Ethernet v%s" % Versions.bcm570_version) - copy(Versions.bcm570_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - # Wifi Patches - - if current_model in ModelArray.WifiAtheros: - print("- Adding IO80211HighSierra v%s" % Versions.io80211high_sierra_version) - copy(Versions.io80211high_sierra_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - #if current_model in ModelArray.WifiBCM94328: - # print("- Wifi patches currently unsupported") - #if current_model in ModelArray.WifiBCM94322: - # print("- Adding IO80211Mojave %s" % Versions.io80211mojave_version) - # copy(Versions.io80211mojave_path, Versions.kext_path_build) - # Versions.plist_data = Versions.plist_data.replace( - # "", - # "" - # ) - # Versions.plist_data = Versions.plist_data.replace( - # "", - # "" - # ) - #if current_model in ModelArray.WifiBCM943224: - # print("- Adding IO80211Mojave %s" % Versions.io80211mojave_version) - # copy(Versions.io80211mojave_path, Versions.kext_path_build) - # Versions.plist_data = Versions.plist_data.replace( - # "", - # "" - # ) - # Versions.plist_data = Versions.plist_data.replace( - # "", - # "" - # ) - if current_model in ModelArray.WifiBCM94331: - print("- Adding AirportBrcmFixup and appling fake ID") - copy(Versions.airportbcrmfixup_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - if current_model in ModelArray.EthernetNvidia: - # Nvidia chipsets all have the same path to ARPT - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x15,0x0)/Pci(0x0,0x0)" - ) - if current_model in ("MacBookAir2,1", "MacBookAir3,1", "MacBookAir3,2" ): - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x15,0x0)/Pci(0x0,0x0)" - ) - elif current_model in ("iMac7,1", "iMac8,1" ): - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x0)" - ) - elif current_model in ("iMac13,1", "iMac13,2"): - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x1C,0x3)/Pci(0x0,0x0)" - ) - elif current_model in ("MacPro5,1"): - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x1C,0x5)/Pci(0x0,0x0)" - ) - else: - # Assumes we have a laptop with Intel chipset - Versions.plist_data = Versions.plist_data.replace( - "#PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)", - "PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)" - ) - if current_model in ModelArray.LegacyHID: - print("- Adding legacy IOHIDFamily Patch") - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - if current_model in ModelArray.LegacyAudio: - print("- Adding VoodooHDA v%s" % Versions.voodoohda_version) - copy(Versions.voodoohda_path, Versions.kext_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - if current_model in ModelArray.pciSSDT: - print("- Adding SSDT-CPBG") - copy(Versions.pci_ssdt_path, Versions.acpi_path_build) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - - usb_map_path = os.path.join(Versions.current_path, "payloads/Kexts/Maps/Zip/" "USB-Map-%s.zip" % current_model) - if os.path.exists(usb_map_path): - print("- Adding USB Map for %s" % current_model) - copy(usb_map_path, Versions.kext_path_build) - map_name = ("USB-Map-%s.kext" % current_model) - Versions.plist_data = Versions.plist_data.replace( - "", - "" - ) - Versions.plist_data = Versions.plist_data.replace( - "USB-Map-SMBIOS.kext", - map_name - ) - - if current_model in ModelArray.DualGPUPatch: - print("- Adding dual GPU patch") - Versions.plist_data = Versions.plist_data.replace( - "debug=0x100", - "debug=0x100 agdpmod=pikera" - ) - if current_model in ModelArray.HiDPIpicker: - print("- Setting HiDPI picker") - Versions.plist_data = Versions.plist_data.replace( - "AQ==", - "Ag==" - ) - - -def BuildGUI(): - print("- Adding OpenCanopy GUI") - rmtree(Versions.gui_path_build) - copy(Versions.gui_path, Versions.plist_path_build) - Versions.plist_data = Versions.plist_data.replace( - "#OpenCanopy.efi", - "OpenCanopy.efi" - ) - -def BuildSMBIOS(): - # Set new SMBIOS - new_model = current_model - if current_model in ModelArray.MacBookAir61: - print("- Spoofing to MacBookAir6,1") - new_model = "MacBookAir6,1" - elif current_model in ModelArray.MacBookAir62: - print("- Spoofing to MacBookAir6,2") - new_model = "MacBookAir6,2" - elif current_model in ModelArray.MacBookPro111: - print("- Spoofing to MacBookPro11,1") - new_model = "MacBookPro11,1" - elif current_model in ModelArray.MacBookPro112: - print("- Spoofing to MacBookPro11,2") - new_model = "MacBookPro11,2" - elif current_model in ModelArray.Macmini71: - print("- Spoofing to Macmini7,1") - new_model = "Macmini7,1" - elif current_model in ModelArray.iMac151: - print("- Spoofing to iMac15,1") - new_model = "iMac15,1" - elif current_model in ModelArray.iMac144: - print("- Spoofing to iMac14,4") - new_model = "iMac14,4" - elif current_model in ModelArray.MacPro71: - print("- Spoofing to MacPro7,1") - new_model = "MacPro7,1" - - # Grab serials from macserial - serialPatch = subprocess.Popen(["xattr", "-cr", "./payloads/tools/macserial"], stdout=subprocess.PIPE).communicate()[0] - print(serialPatch) - serialData = subprocess.Popen((r"./payloads/tools/macserial -g -m " + new_model + " -n 1").split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - serialData = serialData.stdout.read().strip().split(" | ") - - # Patch SMBIOS - Versions.plist_data = Versions.plist_data.replace( - "iMac19,1", - new_model - ) - - if serialData == "['']": - # Used as a backup for when macserial fails - print("Failed to load macserial") - else: - # Patch Number Serial - Versions.plist_data = Versions.plist_data.replace( - "W00000000001", - serialData[0] - ) - # Patch MLB - Versions.plist_data = Versions.plist_data.replace( - "M0000000000000001", - serialData[1] - ) - - # Patch UUID - uuidGen = subprocess.Popen(["uuidgen"], stdout=subprocess.PIPE).communicate()[0] - Versions.plist_data = Versions.plist_data.replace( - "00000000-0000-0000-0000-000000000000", - uuidGen - ) - -def SavePlist(): - with open(Versions.plist_path_build_full, 'w') as file: - file.write(Versions.plist_data) - -def CleanBuildFolder(): - # Clean up Build Folder - print("") - print("Cleaning build folder") - os.chdir(Versions.kext_path_build) - for item in os.listdir(Versions.kext_path_build): - if item.endswith(".zip"): - file_name = os.path.abspath(item) - zip_ref = zipfile.ZipFile(file_name) - zip_ref.extractall(Versions.kext_path_build) - zip_ref.close() - os.remove(file_name) - # Clean up Python's unzip - if os.path.exists("__MACOSX"): - rmtree("__MACOSX") - os.chdir(Versions.plist_path_build) - os.chdir(Versions.plist_path_build) - for item in os.listdir(Versions.plist_path_build): - if item.endswith(".zip"): - file_name = os.path.abspath(item) - zip_ref = zipfile.ZipFile(file_name) - zip_ref.extractall(Versions.plist_path_build) - zip_ref.close() - os.remove(file_name) - if os.path.exists("__MACOSX"): - rmtree("__MACOSX") - os.chdir(Versions.build_path) - if os.path.exists("__MACOSX"): - rmtree("__MACOSX") - os.remove(Versions.opencore_path_build) - os.chdir(Versions.current_path) - -def ListDiskutil(): - DiskMenu = True - while DiskMenu: - os.system('clear') - print("Loading diskutil...(This may take some time)") - diskList = subprocess.Popen(["diskutil", "list"], stdout=subprocess.PIPE).communicate()[0] - print(diskList) - ChosenDisk = input('Please select the disk you want to install OpenCore to(ie. disk1): ') - ChosenDisk = ChosenDisk + "s1" - print("Trying to mount %s" % ChosenDisk) - diskMount = subprocess.Popen(["sudo", "diskutil", "mount", ChosenDisk], stdout=subprocess.PIPE).communicate()[0] - print(diskMount) - DiskMenu = input("Press any key to continue: ") - -def MoveOpenCore(): - print("") - efiVol = "/Volumes/EFI" - if os.path.exists(efiVol): - print("Coping OpenCore onto Volumes/EFI") - if os.path.exists("/Volumes/EFI/EFI"): - print("Cleaning EFI folder") - rmtree("/Volumes/EFI/EFI") - if os.path.exists(Versions.opencore_path_done): - copy_tree(Versions.opencore_path_done, efiVol) - copy(Versions.icon_path, efiVol) - print("OpenCore transfer complete") - print("") - else: - print("Couldn't find EFI partition") - print("Please ensure your drive is formatted as GUID Partition Table") - print("") - -def MountOpenCore(): - subprocess.Popen((r"sudo diskutil mount $(nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:boot-path | sed 's/.*GPT,\([^,]*\),.*/\1/')").split()) \ No newline at end of file diff --git a/Resources/Versions.py b/Resources/Versions.py index b0b6f8d5d5..ce28ea431c 100644 --- a/Resources/Versions.py +++ b/Resources/Versions.py @@ -9,6 +9,7 @@ import json import subprocess import sys +from pathlib import Path # List build versions opencore_version = "0.6.6" @@ -29,33 +30,34 @@ # List current location os.chdir(os.path.dirname(os.path.realpath(__file__))) os.chdir("..") -current_path = os.getcwd() +resource_path = os.getcwd() +current_path = Path(sys.executable).parent # Payload Location # OpenCore -opencore_path = os.path.join(current_path, "payloads/OpenCore/" "OpenCore-v%s.zip" % opencore_version) -plist_path = os.path.join(current_path, "payloads/Config/v%s/" "config.plist" % opencore_version) +opencore_path = os.path.join(resource_path, "payloads/OpenCore/" "OpenCore-v%s.zip" % opencore_version) +plist_path = os.path.join(resource_path, "payloads/Config/v%s/" "config.plist" % opencore_version) # ACPI -pci_ssdt_path = os.path.join(current_path, "payloads/ACPI/" "SSDT-CPBG.aml") +pci_ssdt_path = os.path.join(resource_path, "payloads/ACPI/" "SSDT-CPBG.aml") # Drivers -nvme_driver_path = os.path.join(current_path, "payloads/Drivers/" "NvmExpressDxe.efi") +nvme_driver_path = os.path.join(resource_path, "payloads/Drivers/" "NvmExpressDxe.efi") # Kexts -lilu_path = os.path.join(current_path, "payloads/Kexts/Acidanthera/" "Lilu-v%s.zip" % lilu_version) -whatevergreen_path = os.path.join(current_path, "payloads/Kexts/Acidanthera/" "WhateverGreen-v%s.zip" % whatevergreen_version) -airportbcrmfixup_path = os.path.join(current_path, "payloads/Kexts/Acidanthera/" "AirportBrcmFixup-v%s.zip" % airportbcrmfixup_version) -restrictevents_path = os.path.join(current_path, "payloads/Kexts/Acidanthera/" "RestrictEvents-v%s.zip" % restrictevents_version) -bcm570_path = os.path.join(current_path, "payloads/Kexts/Ethernet/" "CatalinaBCM5701Ethernet-v%s.zip" % bcm570_version) -marvel_path = os.path.join(current_path, "payloads/Kexts/Ethernet/" "MarvelYukonEthernet-v%s.zip" % marvel_version) -nforce_path = os.path.join(current_path, "payloads/Kexts/Ethernet/" "nForceEthernet-v%s.zip" % nforce_version) -mce_path = os.path.join(current_path, "payloads/Kexts/Misc/" "AppleMCEReporterDisabler-v%s.zip" % mce_version) -mousse_path = os.path.join(current_path, "payloads/Kexts/SSE/" "AAAMouSSE-v%s.zip" % mousse_version) -telemetrap_path = os.path.join(current_path, "payloads/Kexts/SSE/" "telemetrap-v%s.zip" % telemetrap_version) -io80211high_sierra_path = os.path.join(current_path, "payloads/Kexts/Wifi/" "IO80211HighSierra-v%s.zip" % io80211high_sierra_version) -io80211mojave_path = os.path.join(current_path, "payloads/Kexts/Wifi/" "IO80211Mojave-v%s.zip" % io80211mojave_version) -voodoohda_path = os.path.join(current_path, "payloads/Kexts/Audio/" "VoodooHDA-v%s.zip" % voodoohda_version) +lilu_path = os.path.join(resource_path, "payloads/Kexts/Acidanthera/" "Lilu-v%s.zip" % lilu_version) +whatevergreen_path = os.path.join(resource_path, "payloads/Kexts/Acidanthera/" "WhateverGreen-v%s.zip" % whatevergreen_version) +airportbcrmfixup_path = os.path.join(resource_path, "payloads/Kexts/Acidanthera/" "AirportBrcmFixup-v%s.zip" % airportbcrmfixup_version) +restrictevents_path = os.path.join(resource_path, "payloads/Kexts/Acidanthera/" "RestrictEvents-v%s.zip" % restrictevents_version) +bcm570_path = os.path.join(resource_path, "payloads/Kexts/Ethernet/" "CatalinaBCM5701Ethernet-v%s.zip" % bcm570_version) +marvel_path = os.path.join(resource_path, "payloads/Kexts/Ethernet/" "MarvelYukonEthernet-v%s.zip" % marvel_version) +nforce_path = os.path.join(resource_path, "payloads/Kexts/Ethernet/" "nForceEthernet-v%s.zip" % nforce_version) +mce_path = os.path.join(resource_path, "payloads/Kexts/Misc/" "AppleMCEReporterDisabler-v%s.zip" % mce_version) +mousse_path = os.path.join(resource_path, "payloads/Kexts/SSE/" "AAAMouSSE-v%s.zip" % mousse_version) +telemetrap_path = os.path.join(resource_path, "payloads/Kexts/SSE/" "telemetrap-v%s.zip" % telemetrap_version) +io80211high_sierra_path = os.path.join(resource_path, "payloads/Kexts/Wifi/" "IO80211HighSierra-v%s.zip" % io80211high_sierra_version) +io80211mojave_path = os.path.join(resource_path, "payloads/Kexts/Wifi/" "IO80211Mojave-v%s.zip" % io80211mojave_version) +voodoohda_path = os.path.join(resource_path, "payloads/Kexts/Audio/" "VoodooHDA-v%s.zip" % voodoohda_version) # Build Location opencore_path_build = os.path.join(current_path, "Build-Folder/" "OpenCore-v%s.zip" % opencore_version) @@ -65,13 +67,13 @@ drivers_path_build = os.path.join(current_path, "Build-Folder/" "OpenCore-v%s/EFI/OC/Drivers" % opencore_version) kext_path_build = os.path.join(current_path, "Build-Folder/" "OpenCore-v%s/EFI/OC/Kexts" % opencore_version) opencore_path_done = os.path.join(current_path, "Build-Folder/" "OpenCore-v%s" % opencore_version) -build_path = os.path.join(current_path, r'Build-Folder/') +build_path = os.path.join(current_path, "Build-Folder/") gui_path_build = os.path.join(current_path, "Build-Folder/" "OpenCore-v%s/EFI/OC/Resources" % opencore_version) # Tools -macserial_path = os.path.join(current_path, "payloads/" "Tools") +macserial_path = os.path.join(resource_path, "payloads/" "Tools") # Icons -app_icon_path = os.path.join(current_path, "OC-Patcher.icns") -icon_path = os.path.join(current_path, "payloads/Icon/" ".VolumeIcon.icns") -gui_path = os.path.join(current_path, "payloads/Icon/" "Resources.zip") \ No newline at end of file +app_icon_path = os.path.join(resource_path, "OC-Patcher.icns") +icon_path = os.path.join(resource_path, "payloads/Icon/" ".VolumeIcon.icns") +gui_path = os.path.join(resource_path, "payloads/Icon/" "Resources.zip") diff --git a/Resources/build.py b/Resources/build.py new file mode 100644 index 0000000000..74949f18ec --- /dev/null +++ b/Resources/build.py @@ -0,0 +1,275 @@ +# Commands for building the EFI and SMBIOS + +from __future__ import print_function + +import binascii +import plistlib +import re +import shutil +import subprocess +import uuid +import zipfile +from pathlib import Path + +from Resources import ModelArray, Versions, utilities + + +class BuildOpenCore(): + def __init__(self, model, version): + self.model = model + self.config = None + Versions.opencore_version = version + + def build_efi(self): + utilities.cls() + if not Path(Versions.build_path).exists(): + Path(Versions.build_path).mkdir() + print("Created build folder") + else: + print("Build folder already present, skipping") + + if Path(Versions.opencore_path_build).exists(): + print("Deleting old copy of OpenCore zip") + Path(Versions.opencore_path_build).unlink() + if Path(Versions.opencore_path_done).exists(): + print("Deleting old copy of OpenCore folder") + shutil.rmtree(Versions.opencore_path_done) + + print() + print("- Adding OpenCore v" + Versions.opencore_version) + shutil.copy(Versions.opencore_path, Versions.build_path) + zipfile.ZipFile(Versions.opencore_path_build).extractall(Versions.build_path) + + print("- Adding config.plist for OpenCore") + # Setup config.plist for editing + shutil.copy(Versions.plist_path, Versions.plist_path_build) + self.config = plistlib.load(Path(Versions.plist_path_build_full).open("rb")) + + for name, version, path, check in [ + # Essential kexts + ("Lilu.kext", Versions.lilu_version, Versions.lilu_path, lambda: True), + ("WhateverGreen.kext", Versions.whatevergreen_version, Versions.whatevergreen_path, lambda: True), + ("RestrictEvents.kext", Versions.restrictevents_version, Versions.restrictevents_path, lambda: self.model in ModelArray.MacPro71), + # CPU patches + ("AppleMCEReporterDisabler.kext", Versions.mce_version, Versions.mce_path, lambda: self.model in ModelArray.DualSocket), + ("AAAMouSSE.kext", Versions.mousse_version, Versions.mousse_path, lambda: self.model in ModelArray.SSEEmulator), + ("telemetrap.kext", Versions.telemetrap_version, Versions.telemetrap_path, lambda: self.model in ModelArray.MissingSSE42), + # Ethernet patches + ("nForceEthernet.kext", Versions.nforce_version, Versions.nforce_path, lambda: self.model in ModelArray.EthernetNvidia), + ("MarvelYukonEthernet.kext", Versions.marvel_version, Versions.marvel_path, lambda: self.model in ModelArray.EthernetMarvell), + ("CatalinaBCM5701Ethernet.kext", Versions.bcm570_version, Versions.bcm570_path, lambda: self.model in ModelArray.EthernetBroadcom), + # Legacy audio + ("VoodooHDA.kext", Versions.voodoohda_version, Versions.voodoohda_path, lambda: self.model in ModelArray.LegacyAudio) + ]: + self.enable_kext(name, version, path, check) + + # WiFi patches + + if self.model in ModelArray.WifiAtheros: + self.enable_kext("IO80211HighSierra.kext", Versions.io80211high_sierra_version, Versions.io80211high_sierra_path) + self.get_kext_by_bundle_path("IO80211HighSierra.kext/Contents/PlugIns/AirPortAtheros40.kext")["Enabled"] = True + + if self.model in ModelArray.WifiBCM94331: + self.enable_kext("AirportBrcmFixup.kext", Versions.airportbcrmfixup_version, Versions.airportbcrmfixup_path) + self.get_kext_by_bundle_path("AirportBrcmFixup.kext/Contents/PlugIns/AirPortBrcmNIC_Injector.kext")["Enabled"] = True + + if self.model in ModelArray.EthernetNvidia: + # Nvidia chipsets all have the same path to ARPT + property_path = "PciRoot(0x0)/Pci(0x15,0x0)/Pci(0x0,0x0)" + if self.model in ("MacBookAir2,1", "MacBookAir3,1", "MacBookAir3,2"): + property_path = "PciRoot(0x0)/Pci(0x15,0x0)/Pci(0x0,0x0)" + elif self.model in ("iMac7,1", "iMac8,1"): + property_path = "PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x0)" + elif self.model in ("iMac13,1", "iMac13,2"): + property_path = "PciRoot(0x0)/Pci(0x1C,0x3)/Pci(0x0,0x0)" + elif self.model in ("MacPro5,1"): + property_path = "PciRoot(0x0)/Pci(0x1C,0x5)/Pci(0x0,0x0)" + else: + # Assumes we have a laptop with Intel chipset + property_path = "PciRoot(0x0)/Pci(0x1C,0x1)/Pci(0x0,0x0)" + print("- Applying fake ID for WiFi") + self.config["DeviceProperties"]["Add"][property_path] = { + "device-id": binascii.unhexlify("ba430000"), + "compatible": "pci14e4,43ba" + } + + # HID patches + if self.model in ModelArray.LegacyHID: + print("- Adding IOHIDFamily patch") + self.get_item_by_kv(self.config["Kernel"]["Patch"], "Identifier", "com.apple.iokit.IOHIDFamily")["Enabled"] = True + + # SSDT patches + if self.model in ModelArray.pciSSDT: + print("- Adding SSDT-CPBG.aml") + self.get_item_by_kv(self.config["ACPI"]["Add"], "Path", "SSDT-CPBG.aml")["Enabled"] = True + + # USB map + map_name = f"USB-Map-{self.model}.zip" + map_entry = f"USB-Map-{self.model}.kext" + usb_map_path = Path(Versions.current_path) / Path(f"payloads/Kexts/Maps/Zip/{map_name}") + if usb_map_path.exists(): + print(f"- Adding {map_entry}") + shutil.copy(usb_map_path, Versions.kext_path_build) + self.get_kext_by_bundle_path("USB-Map-SMBIOS.kext")["Enabled"] = True + self.get_kext_by_bundle_path("USB-Map-SMBIOS.kext")["BundlePath"] = map_entry + + if self.model in ModelArray.DualGPUPatch: + print("- Adding dual GPU patch") + self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += " agdpmod=pikera" + + if self.model in ModelArray.HiDPIpicker: + print("- Setting HiDPI picker") + self.config["NVRAM"]["Add"]["4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14"]["UIScale"] = binascii.unhexlify("02") + + # Add OpenCanopy + print("- Adding OpenCanopy GUI") + shutil.rmtree(Versions.gui_path_build) + shutil.copy(Versions.gui_path, Versions.plist_path_build) + self.config["UEFI"]["Drivers"] = ["OpenCanopy.efi", "OpenRuntime.efi"] + + plistlib.dump(self.config, Path(Versions.plist_path_build_full).open("wb"), sort_keys=True) + + def set_smbios(self): + spoofed_model = self.model + if self.model in ModelArray.MacBookAir61: + print("- Spoofing to MacBookAir6,1") + spoofed_model = "MacBookAir6,1" + elif self.model in ModelArray.MacBookAir62: + print("- Spoofing to MacBookAir6,2") + spoofed_model = "MacBookAir6,2" + elif self.model in ModelArray.MacBookPro111: + print("- Spoofing to MacBookPro11,1") + spoofed_model = "MacBookPro11,1" + elif self.model in ModelArray.MacBookPro112: + print("- Spoofing to MacBookPro11,2") + spoofed_model = "MacBookPro11,2" + elif self.model in ModelArray.Macmini71: + print("- Spoofing to Macmini7,1") + spoofed_model = "Macmini7,1" + elif self.model in ModelArray.iMac151: + print("- Spoofing to iMac15,1") + spoofed_model = "iMac15,1" + elif self.model in ModelArray.iMac144: + print("- Spoofing to iMac14,4") + spoofed_model = "iMac14,4" + elif self.model in ModelArray.MacPro71: + print("- Spoofing to MacPro7,1") + spoofed_model = "MacPro7,1" + macserial_output = subprocess.run((f"./payloads/tools/macserial -g -m {spoofed_model} -n 1").split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + macserial_output = macserial_output.stdout.decode().strip().split(" | ") + self.config["PlatformInfo"]["Generic"]["SystemProductName"] = spoofed_model + self.config["PlatformInfo"]["Generic"]["SystemSerialNumber"] = macserial_output[0] + self.config["PlatformInfo"]["Generic"]["MLB"] = macserial_output[1] + self.config["PlatformInfo"]["Generic"]["SystemUUID"] = str(uuid.uuid4()).upper() + + @staticmethod + def get_item_by_kv(iterable, key, value): + item = None + for i in iterable: + if i[key] == value: + item = i + break + return item + + def get_kext_by_bundle_path(self, bundle_path): + kext = self.get_item_by_kv(self.config["Kernel"]["Add"], "BundlePath", bundle_path) + if not kext: + print(f"- Could not find kext {bundle_path}!") + raise IndexError + return kext + + def enable_kext(self, kext_name, kext_version, kext_path, check=False): + kext = self.get_kext_by_bundle_path(kext_name) + + if callable(check) and not check(): + # Check failed + return + + print(f"- Adding {kext_name} {kext_version}") + shutil.copy(kext_path, Versions.kext_path_build) + kext["Enabled"] = True + + def cleanup(self): + print("- Cleaning up files") + for kext in Path(Versions.kext_path_build).glob("*.zip"): + with zipfile.ZipFile(kext) as zip_file: + zip_file.extractall(Versions.kext_path_build) + kext.unlink() + shutil.rmtree((Path(Versions.kext_path_build) / Path("__MACOSX")), ignore_errors=True) + + for item in Path(Versions.plist_path_build).glob("*.zip"): + with zipfile.ZipFile(item) as zip_file: + zip_file.extractall(Versions.plist_path_build) + item.unlink() + shutil.rmtree((Path(Versions.build_path) / Path("__MACOSX")), ignore_errors=True) + Path(Versions.opencore_path_build).unlink() + + def build_opencore(self): + self.build_efi() + self.set_smbios() + self.cleanup() + print("") + print("Your OpenCore EFI has been built at:") + print(f" {Versions.opencore_path_done}") + print("") + input("Press enter to go back") + + @staticmethod + def copy_efi(): + diskutil = [subprocess.run("diskutil list".split(), stdout=subprocess.PIPE).stdout.decode().strip()] + menu = utilities.TUIMenu(["Select Disk"], "Please select the disk you want to install OpenCore to: ", in_between=diskutil, return_number_instead_of_direct_call=True, add_quit=False) + for disk in [i for i in Path("/dev").iterdir() if re.fullmatch("disk[0-9]+", i.stem)]: + menu.add_menu_option(disk.stem, key=disk.stem[4:]) + disk_num = menu.start() + print(subprocess.run(("sudo diskutil mount disk" + disk_num).split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout) + + utilities.cls() + utilities.header(["Copying OpenCore"]) + efi_dir = Path("/Volumes/EFI") + if efi_dir.exists(): + print("- Coping OpenCore onto EFI partition") + if (efi_dir / Path("EFI")).exists(): + print("Removing preexisting EFI folder") + shutil.rmtree(efi_dir / Path("EFI")) + if Path(Versions.opencore_path_done).exists(): + shutil.copytree(Versions.opencore_path_done, efi_dir) + shutil.copy(Versions.icon_path, efi_dir) + print("OpenCore transfer complete") + print("") + else: + print("Couldn't find EFI partition") + print("Please ensure your drive is formatted as GUID Partition Table") + print("") + + +class OpenCoreMenus(): + def __init__(self): + self.version = Versions.opencore_version + + def change_opencore_version(self): + utilities.cls() + utilities.header(["Change OpenCore Version"]) + print(f"\nCurrent OpenCore version: {self.version}\nSupported versions: 0.6.3, 0.6.4") + version = input("Please enter the desired OpenCore version: ").strip() + if version: + self.version = version + + def build_opencore_menu(self, model): + response = None + while not (response and response == -1): + title = [ + f"Build OpenCore v{self.version} EFI", + "Selected Model: " + model + ] + menu = utilities.TUIMenu(title, "Please select an option: ", auto_number=True) + + options = [ + ["Build OpenCore", lambda: BuildOpenCore(model, self.version).build_opencore()], + ["Change OpenCore Version", self.change_opencore_version], + ] + + for option in options: + menu.add_menu_option(option[0], function=option[1]) + + response = menu.start() + # response = utilities.menu(title, "zoomer, Please select an option: ", options, auto_number=True, top_level=True) diff --git a/Resources/utilities.py b/Resources/utilities.py new file mode 100644 index 0000000000..e55a0fff6d --- /dev/null +++ b/Resources/utilities.py @@ -0,0 +1,114 @@ +from __future__ import print_function + +import os +import math as m + + +def header(lines): + lines = [i for i in lines if i is not None] + total_length = len(max(lines, key=len)) + 4 + print("#" * (total_length)) + for line in lines: + left_side = m.floor(((total_length - 2 - len(line.strip())) / 2)) + print("#" + " " * left_side + line.strip() + " " * (total_length - len("#" + " " * left_side + line.strip()) - 1) + "#") + print("#" * total_length) + + +def cls(): + os.system('cls' if os.name == 'nt' else 'clear') + +# def menu(title, prompt, menu_options, add_quit=True, auto_number=False, in_between=[], top_level=False): +# return_option = ["Q", "Quit", None] if top_level else ["B", "Back", None] +# if add_quit: menu_options.append(return_option) + +# cls() +# header(title) +# print() + +# for i in in_between: print(i) +# if in_between: print() + +# for index, option in enumerate(menu_options): +# if auto_number and not (index == (len(menu_options) - 1) and add_quit): +# option[0] = str((index + 1)) +# print(option[0] + ". " + option[1]) + +# print() +# selected = input(prompt) + +# keys = [option[0].upper() for option in menu_options] +# if not selected or selected.upper() not in keys: +# return +# if selected.upper() == return_option[0]: +# return -1 +# else: +# menu_options[keys.index(selected.upper())][2]() if menu_options[keys.index(selected.upper())][2] else None + + +class TUIMenu(): + def __init__(self, title, prompt, options=None, return_number_instead_of_direct_call=False, add_quit=True, auto_number=False, in_between=None, top_level=False): + self.title = title + self.prompt = prompt + self.in_between = in_between or [] + self.options = options or [] + self.return_number_instead_of_direct_call = return_number_instead_of_direct_call + self.auto_number = auto_number + self.add_quit = add_quit + self.top_level = top_level + + def add_menu_option(self, name, description="", function=None, key=""): + self.options.append([key, name, description, function]) + + def start(self): + return_option = ["Q", "Quit"] if self.top_level else ["B", "Back"] + if self.add_quit: + self.add_menu_option( + return_option[1], function=None, key=return_option[0]) + + cls() + header(self.title) + print() + + for i in self.in_between: + print(i) + if self.in_between: + print() + + for index, option in enumerate(self.options): + if self.auto_number and not (index == (len(self.options) - 1) and self.add_quit): + option[0] = str((index + 1)) + print(option[0] + ". " + option[1]) + for i in option[2]: + print("\t" + i) + + print() + selected = input(self.prompt) + + keys = [option[0].upper() for option in self.options] + if not selected or selected.upper() not in keys: + return + if self.add_quit and selected.upper() == return_option[0]: + return -1 + elif self.return_number_instead_of_direct_call: + return self.options[keys.index(selected.upper())][0] + else: + self.options[keys.index(selected.upper())][3]() if self.options[keys.index(selected.upper())][3] else None + + +class TUIOnlyPrint(): + def __init__(self, title, prompt, in_between=None): + self.title = title + self.prompt = prompt + self.in_between = in_between or [] + + def start(self): + cls() + header(self.title) + print() + + for i in self.in_between: + print(i) + if self.in_between: + print() + + input(self.prompt)