Merge branch 'main' into pullrequests/Ausdauersportler/main

This commit is contained in:
Mykola Grymalyuk
2023-03-11 20:37:38 -07:00
committed by GitHub
46 changed files with 2786 additions and 3335 deletions
+191 -65
View File
@@ -3,28 +3,51 @@
# Currently Work in Progress
import plistlib
import wx
import sys
import webbrowser
import subprocess
import time
import os
import wx.adv
from wx.lib.agw import hyperlink
import threading
from pathlib import Path
from datetime import datetime
import os
import sys
import subprocess
import threading
import webbrowser
import time
import binascii
import hashlib
from datetime import datetime
import py_sip_xnu
import logging
from resources import constants, defaults, install, installer, utilities, run, generate_smbios, updates, integrity_verification, global_settings, kdk_handler, network_handler
import logging
import tempfile
import wx
import wx.adv
from wx.lib.agw import hyperlink
import py_sip_xnu
from resources import (
constants,
defaults,
install,
utilities,
generate_smbios,
updates,
integrity_verification,
global_settings,
kdk_handler,
network_handler,
macos_installer_handler
)
from resources.sys_patch import sys_patch_detect, sys_patch
from resources.build import build
from data import model_array, os_data, smbios_data, sip_data, cpu_data
from resources.gui import menu_redirect, gui_help
from data import model_array, os_data, smbios_data, sip_data, cpu_data
class wx_python_gui:
def __init__(self, versions, frame=None, frame_modal=None):
@@ -232,7 +255,7 @@ class wx_python_gui:
if local_build_date <= installed_build_date:
return False
elif updates.check_binary_updates(self.constants).check_if_build_newer(local_version, application_version) is False:
elif updates.CheckBinaryUpdates(self.constants)._check_if_build_newer(local_version, application_version) is False:
return False
# Ask user if they want to move the application to the Applications folder
@@ -283,11 +306,11 @@ class wx_python_gui:
return
did_find_update = False
ignore_updates = global_settings.global_settings().read_property("IgnoreAppUpdates")
ignore_updates = global_settings.GlobalEnviromentSettings().read_property("IgnoreAppUpdates")
if ignore_updates is not True:
self.constants.ignore_updates = False
self.constants.has_checked_updates = True
dict = updates.check_binary_updates(self.constants).check_binary_updates()
dict = updates.CheckBinaryUpdates(self.constants).check_binary_updates()
if dict:
for entry in dict:
version = dict[entry]["Version"]
@@ -307,7 +330,7 @@ class wx_python_gui:
elif response == wx.ID_NO:
logging.info("- Setting IgnoreAppUpdates to True")
self.constants.ignore_updates = True
global_settings.global_settings().write_property("IgnoreAppUpdates", True)
global_settings.GlobalEnviromentSettings().write_property("IgnoreAppUpdates", True)
else:
self.constants.ignore_updates = True
logging.info("- Ignoring App Updates due to defaults")
@@ -565,10 +588,10 @@ class wx_python_gui:
if self.constants.start_build_install is True:
self.build_install_menu()
elif "--gui_patch" in sys.argv:
self.patches = sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).detect_patch_set()
self.patches = sys_patch_detect.DetectRootPatch(self.computer.real_model, self.constants).detect_patch_set()
self.root_patch_start()
elif "--gui_unpatch" in sys.argv:
self.patches = sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).detect_patch_set()
self.patches = sys_patch_detect.DetectRootPatch(self.computer.real_model, self.constants).detect_patch_set()
self.root_patch_revert()
self.finished_auto_patch = True
self.constants.start_build_install = False
@@ -1055,7 +1078,7 @@ class wx_python_gui:
)
self.subheader.Centre(wx.HORIZONTAL)
patches = sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).detect_patch_set()
patches = sys_patch_detect.DetectRootPatch(self.computer.real_model, self.constants).detect_patch_set()
self.patches = patches
can_unpatch = patches["Validation: Unpatching Possible"]
if not any(not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True for patch in patches):
@@ -1263,24 +1286,36 @@ class wx_python_gui:
self.pulse_alternative(self.progress_bar)
wx.GetApp().Yield()
self.progress_bar.Hide()
if self.patches["Settings: Kernel Debug Kit missing"] is True:
# Download KDK (if needed)
self.subheader.SetLabel("Downloading Kernel Debug Kit")
self.subheader.Centre(wx.HORIZONTAL)
self.developer_note.SetLabel("Starting shortly")
wx.GetApp().Yield()
kdk_result = False
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
if kdk_obj.success is True:
kdk_download_obj = kdk_obj.retrieve_download()
self.kdk_obj = None
def kdk_thread_spawn():
self.kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, self.constants.detected_os_build, self.constants.detected_os_version)
kdk_thread = threading.Thread(target=kdk_thread_spawn)
kdk_thread.start()
while kdk_thread.is_alive():
self.pulse_alternative(self.progress_bar)
wx.GetApp().Yield()
self.progress_bar.Hide()
if self.kdk_obj.success is True:
kdk_download_obj = self.kdk_obj.retrieve_download()
if not kdk_download_obj:
kdk_result = True
else:
kdk_download_obj.download()
self.header.SetLabel(f"Downloading KDK Build: {kdk_obj.kdk_url_build}")
self.header.SetLabel(f"Downloading KDK Build: {self.kdk_obj.kdk_url_build}")
self.header.Centre(wx.HORIZONTAL)
self.progress_bar.SetValue(0)
@@ -1304,7 +1339,7 @@ class wx_python_gui:
)
self.developer_note.Centre(wx.HORIZONTAL)
self.progress_bar.SetValue(kdk_download_obj.get_percent())
self.progress_bar.SetValue(int(kdk_download_obj.get_percent()))
wx.GetApp().Yield()
time.sleep(0.1)
@@ -1314,12 +1349,12 @@ class wx_python_gui:
logging.error(kdk_download_obj.error_msg)
error_msg = kdk_download_obj.error_msg
else:
kdk_result = kdk_obj.validate_kdk_checksum()
error_msg = kdk_obj.error_msg
kdk_result = self.kdk_obj.validate_kdk_checksum()
error_msg = self.kdk_obj.error_msg
else:
logging.error("Failed to download KDK")
logging.error(kdk_obj.error_msg)
error_msg = kdk_obj.error_msg
logging.error(self.kdk_obj.error_msg)
error_msg = self.kdk_obj.error_msg
if kdk_result is False:
# Create popup window to inform user of error
@@ -1617,7 +1652,9 @@ class wx_python_gui:
# Download installer catalog
if ias is None:
def ia():
self.available_installers = installer.list_downloadable_macOS_installers(self.constants.payload_path, "DeveloperSeed")
remote_obj = macos_installer_handler.RemoteInstallerCatalog(seed_override=macos_installer_handler.SeedType.DeveloperSeed)
self.available_installers = remote_obj.available_apps
self.available_installers_latest = remote_obj.available_apps_latest
logging.info("- Downloading installer catalog...")
thread_ia = threading.Thread(target=ia)
@@ -1655,7 +1692,7 @@ class wx_python_gui:
i = -20
if available_installers:
if ias is None:
available_installers = installer.only_list_newest_installers(available_installers)
available_installers = self.available_installers_latest
for app in available_installers:
logging.info(f"macOS {available_installers[app]['Version']} ({available_installers[app]['Build']}):\n - Size: {utilities.human_fmt(available_installers[app]['Size'])}\n - Source: {available_installers[app]['Source']}\n - Variant: {available_installers[app]['Variant']}\n - Link: {available_installers[app]['Link']}\n")
if available_installers[app]['Variant'] in ["DeveloperSeed" , "PublicSeed"]:
@@ -1823,7 +1860,7 @@ class wx_python_gui:
)
self.download_label_2.Centre(wx.HORIZONTAL)
self.download_progress.SetValue(ia_download.get_percent())
self.download_progress.SetValue(int(ia_download.get_percent()))
wx.GetApp().Yield()
time.sleep(0.1)
@@ -1929,7 +1966,7 @@ class wx_python_gui:
self.header.Centre(wx.HORIZONTAL)
self.verifying_chunk_label.SetLabel("Installing into Applications folder")
self.verifying_chunk_label.Centre(wx.HORIZONTAL)
thread_install = threading.Thread(target=installer.install_macOS_installer, args=(self.constants.payload_path,))
thread_install = threading.Thread(target=macos_installer_handler.InstallerCreation().install_macOS_installer, args=(self.constants.payload_path,))
thread_install.start()
self.progress_bar.Pulse()
while thread_install.is_alive():
@@ -1966,7 +2003,7 @@ class wx_python_gui:
# Spawn thread to get list of installers
def get_installers():
self.available_installers = installer.list_local_macOS_installers()
self.available_installers = macos_installer_handler.LocalInstallerCatalog().available_apps
thread_get_installers = threading.Thread(target=get_installers)
thread_get_installers.start()
@@ -2070,7 +2107,7 @@ class wx_python_gui:
self.usb_selection_label.Centre(wx.HORIZONTAL)
i = -15
available_disks = installer.list_disk_to_format()
available_disks = macos_installer_handler.InstallerCreation().list_disk_to_format()
if available_disks:
logging.info("Disks found")
for disk in available_disks:
@@ -2153,7 +2190,7 @@ class wx_python_gui:
self.developer_note_label_2.Centre(wx.HORIZONTAL)
# Progress Bar
max_file_size = 1024 * 1024 * 1024 * 18 # 18GB, best guess for installer + chainloaded packages
max_file_size = 19000 # Best guess for installer + chainloaded packages
self.progress_bar = wx.Gauge(self.frame, range=max_file_size, size=(-1, 20))
self.progress_bar.SetPosition(
wx.Point(
@@ -2225,7 +2262,7 @@ class wx_python_gui:
output = float(utilities.monitor_disk_output(disk))
bytes_written = output - default_output
if install_thread.is_alive():
self.progress_bar.SetValue(bytes_written)
self.progress_bar.SetValue(int(bytes_written))
self.progress_label.SetLabel(f"Bytes Written: {round(bytes_written, 2)}MB")
wx.GetApp().Yield()
else:
@@ -2270,12 +2307,15 @@ class wx_python_gui:
self.return_to_main_menu.Enable()
def prepare_script(self, installer_path, disk):
self.prepare_result = installer.generate_installer_creation_script(self.constants.payload_path, installer_path, disk)
self.prepare_result = macos_installer_handler.InstallerCreation().generate_installer_creation_script(self.constants.payload_path, installer_path, disk)
def start_script(self):
utilities.disable_sleep_while_running()
args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path]
output, error, returncode = run.Run()._stream_output(comm=args)
args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path]
result = subprocess.run(args, capture_output=True, text=True)
output = result.stdout
error = result.stderr if result.stderr else ""
if "Install media now available at" in output:
logging.info("- Successfully created macOS installer")
while self.download_thread.is_alive():
@@ -2325,18 +2365,104 @@ class wx_python_gui:
subprocess.run(["ditto", "-V", "-x", "-k", "--sequesterRsrc", "--rsrc", self.constants.installer_pkg_zip_path, self.constants.payload_path])
def _kdk_chainload(self, build: str, version: str, download_dir: str):
"""
Download the correct KDK to be chainloaded in the macOS installer
Parameters
build (str): The build number of the macOS installer (e.g. 20A5343j)
version (str): The version of the macOS installer (e.g. 11.0.1)
"""
kdk_dmg_path = Path(download_dir) / "KDK.dmg"
kdk_pkg_path = Path(download_dir) / "KDK.pkg"
if kdk_dmg_path.exists():
kdk_dmg_path.unlink()
if kdk_pkg_path.exists():
kdk_pkg_path.unlink()
logging.info("- Initiating KDK download")
logging.info(f" - Build: {build}")
logging.info(f" - Version: {version}")
logging.info(f" - Working Directory: {download_dir}")
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, build, version, ignore_installed=True)
if kdk_obj.success is False:
logging.info("- Failed to retrieve KDK")
logging.info(kdk_obj.error_msg)
return
kdk_download_obj = kdk_obj.retrieve_download(override_path=kdk_dmg_path)
if kdk_download_obj is None:
logging.info("- Failed to retrieve KDK")
logging.info(kdk_obj.error_msg)
# Check remaining disk space before downloading
space = utilities.get_free_space(download_dir)
if space < (kdk_obj.kdk_url_expected_size * 2):
logging.info("- Not enough disk space to download and install KDK")
logging.info(f"- Attempting to download locally first")
if space < kdk_obj.kdk_url_expected_size:
logging.info("- Not enough disk space to install KDK, skipping")
return
# Ideally we'd download the KDK onto the disk to display progress in the UI
# However we'll just download to our temp directory and move it to the target disk
kdk_dmg_path = self.constants.kdk_download_path
kdk_download_obj.download(spawn_thread=False)
if kdk_download_obj.download_complete is False:
logging.info("- Failed to download KDK")
logging.info(kdk_download_obj.error_msg)
return
if not kdk_dmg_path.exists():
logging.info(f"- KDK missing: {kdk_dmg_path}")
return
# Now that we have a KDK, extract it to get the pkg
with tempfile.TemporaryDirectory() as mount_point:
logging.info("- Mounting KDK")
result = subprocess.run(["hdiutil", "attach", kdk_dmg_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Failed to mount KDK")
logging.info(result.stdout.decode("utf-8"))
return
logging.info("- Copying KDK")
subprocess.run(["cp", "-r", f"{mount_point}/KernelDebugKit.pkg", kdk_pkg_path])
logging.info("- Unmounting KDK")
result = subprocess.run(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Failed to unmount KDK")
logging.info(result.stdout.decode("utf-8"))
return
logging.info("- Removing KDK Disk Image")
kdk_dmg_path.unlink()
def install_installer_pkg(self, disk):
disk = disk + "s2" # ESP sits at 1, and we know macOS will have created the main partition at 2
if Path(self.constants.installer_pkg_path).exists():
path = utilities.grab_mount_point_from_disk(disk)
if Path(path + "/System/Library/CoreServices/SystemVersion.plist").exists():
os_version = plistlib.load(Path(path + "/System/Library/CoreServices/SystemVersion.plist").open("rb"))
kernel_version = os_data.os_conversion.os_to_kernel(os_version["ProductVersion"])
if int(kernel_version) >= os_data.os_data.big_sur:
subprocess.run(["mkdir", "-p", f"{path}/Library/Packages/"])
subprocess.run(["cp", "-r", self.constants.installer_pkg_path, f"{path}/Library/Packages/"])
else:
logging.info("- Installer unsupported, requires Big Sur or newer")
if not Path(self.constants.installer_pkg_path).exists():
return
path = utilities.grab_mount_point_from_disk(disk)
if not Path(path + "/System/Library/CoreServices/SystemVersion.plist").exists():
return
os_version = plistlib.load(Path(path + "/System/Library/CoreServices/SystemVersion.plist").open("rb"))
kernel_version = os_data.os_conversion.os_to_kernel(os_version["ProductVersion"])
if int(kernel_version) < os_data.os_data.big_sur:
logging.info("- Installer unsupported, requires Big Sur or newer")
return
subprocess.run(["mkdir", "-p", f"{path}/Library/Packages/"])
subprocess.run(["cp", "-r", self.constants.installer_pkg_path, f"{path}/Library/Packages/"])
self._kdk_chainload(os_version["ProductBuildVersion"], os_version["ProductVersion"], Path(path + "/Library/Packages/"))
def settings_menu(self, event=None):
@@ -2523,11 +2649,11 @@ class wx_python_gui:
if user_choice == self.computer.real_model:
logging.info(f"Using Real Model: {user_choice}")
self.constants.custom_model = None
defaults.generate_defaults(self.computer.real_model, True, self.constants)
defaults.GenerateDefaults(self.computer.real_model, True, self.constants)
else:
logging.info(f"Using Custom Model: {user_choice}")
self.constants.custom_model = user_choice
defaults.generate_defaults(self.constants.custom_model, False, self.constants)
defaults.GenerateDefaults(self.constants.custom_model, False, self.constants)
# Reload Settings
self.settings_menu(None)
@@ -2864,7 +2990,7 @@ class wx_python_gui:
else:
logging.info("Nuke KDKs disabled")
self.constants.should_nuke_kdks = False
global_settings.global_settings().write_property("ShouldNukeKDKs", self.constants.should_nuke_kdks)
global_settings.GlobalEnviromentSettings().write_property("ShouldNukeKDKs", self.constants.should_nuke_kdks)
def disable_library_validation_click(self, event):
if self.disable_library_validation_checkbox.GetValue():
@@ -2887,9 +3013,9 @@ class wx_python_gui:
def set_ignore_app_updates_click(self, event):
self.constants.ignore_updates = self.set_ignore_app_updates_checkbox.GetValue()
if self.constants.ignore_updates is True:
global_settings.global_settings().write_property("IgnoreAppUpdates", True)
global_settings.GlobalEnviromentSettings().write_property("IgnoreAppUpdates", True)
else:
global_settings.global_settings().write_property("IgnoreAppUpdates", False)
global_settings.GlobalEnviromentSettings().write_property("IgnoreAppUpdates", False)
def firewire_click(self, event=None):
if self.firewire_boot_checkbox.GetValue():
@@ -2974,21 +3100,21 @@ class wx_python_gui:
def ts2_accel_click(self, event=None):
if self.set_terascale_accel_checkbox.GetValue():
logging.info("TS2 Acceleration Enabled")
global_settings.global_settings().write_property("MacBookPro_TeraScale_2_Accel", True)
global_settings.GlobalEnviromentSettings().write_property("MacBookPro_TeraScale_2_Accel", True)
self.constants.allow_ts2_accel = True
else:
logging.info("TS2 Acceleration Disabled")
global_settings.global_settings().write_property("MacBookPro_TeraScale_2_Accel", False)
global_settings.GlobalEnviromentSettings().write_property("MacBookPro_TeraScale_2_Accel", False)
self.constants.allow_ts2_accel = False
def force_web_drivers_click(self, event=None):
if self.force_web_drivers_checkbox.GetValue():
logging.info("Force Web Drivers Enabled")
global_settings.global_settings().write_property("Force_Web_Drivers", True)
global_settings.GlobalEnviromentSettings().write_property("Force_Web_Drivers", True)
self.constants.force_nv_web = True
else:
logging.info("Force Web Drivers Disabled")
global_settings.global_settings().write_property("Force_Web_Drivers", False)
global_settings.GlobalEnviromentSettings().write_property("Force_Web_Drivers", False)
self.constants.force_nv_web = False
def windows_gmux_click(self, event=None):
@@ -3698,19 +3824,19 @@ OpenCore Legacy Patcher by default knows the most ideal
self.subheader_4.SetPosition(wx.Point(0, self.subheader2_2.GetPosition().y + self.subheader2_2.GetSize().height+ 5))
self.subheader_4.Centre(wx.HORIZONTAL)
is_dark_menu_bar = subprocess.run(["defaults", "read", "-g", "Moraea_DarkMenuBar"], stdout=subprocess.PIPE).stdout.decode("utf-8").strip()
is_dark_menu_bar = subprocess.run(["defaults", "read", "-g", "Moraea_DarkMenuBar"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode("utf-8").strip()
if is_dark_menu_bar in ["1", "true"]:
is_dark_menu_bar = True
else:
is_dark_menu_bar = False
is_blur_enabled = subprocess.run(["defaults", "read", "-g", "Moraea_BlurBeta"], stdout=subprocess.PIPE).stdout.decode("utf-8").strip()
is_blur_enabled = subprocess.run(["defaults", "read", "-g", "Moraea_BlurBeta"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode("utf-8").strip()
if is_blur_enabled in ["1", "true"]:
is_blur_enabled = True
else:
is_blur_enabled = False
is_rim_disabled = subprocess.run(["defaults", "read", "-g", "Moraea_RimBetaDisabled"], stdout=subprocess.PIPE).stdout.decode("utf-8").strip()
is_rim_disabled = subprocess.run(["defaults", "read", "-g", "Moraea_RimBetaDisabled"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode("utf-8").strip()
if is_rim_disabled in ["1", "true"]:
is_rim_disabled = True
else: