Reformat logging system

This commit is contained in:
Mykola Grymalyuk
2023-05-24 12:24:09 -06:00
parent 80ea0cd217
commit d8a79cf67e
30 changed files with 311 additions and 240 deletions
+42 -42
View File
@@ -30,7 +30,7 @@ class CreateBinary:
def __init__(self): def __init__(self):
start = time.time() start = time.time()
print("- Starting build script") print("Starting build script")
self.args = self._parse_arguments() self.args = self._parse_arguments()
@@ -39,7 +39,7 @@ class CreateBinary:
self._preflight_processes() self._preflight_processes()
self._build_binary() self._build_binary()
self._postflight_processes() self._postflight_processes()
print(f"- Build script completed in {str(round(time.time() - start, 2))} seconds") print(f"Build script completed in {str(round(time.time() - start, 2))} seconds")
def _set_cwd(self): def _set_cwd(self):
@@ -48,7 +48,7 @@ class CreateBinary:
""" """
os.chdir(Path(__file__).resolve().parent) os.chdir(Path(__file__).resolve().parent)
print(f"- Current Working Directory: \n\t{os.getcwd()}") print(f"Current Working Directory: \n\t{os.getcwd()}")
def _parse_arguments(self): def _parse_arguments(self):
@@ -88,7 +88,7 @@ class CreateBinary:
pyinstaller_path = f"{python_bin_dir}pyinstaller" pyinstaller_path = f"{python_bin_dir}pyinstaller"
if not Path(pyinstaller_path).exists(): if not Path(pyinstaller_path).exists():
print(f" - pyinstaller not found:\n\t{pyinstaller_path}") print(f"- pyinstaller not found:\n\t{pyinstaller_path}")
raise Exception("pyinstaller not found") raise Exception("pyinstaller not found")
self.pyinstaller_path = pyinstaller_path self.pyinstaller_path = pyinstaller_path
@@ -99,7 +99,7 @@ class CreateBinary:
Start preflight processes Start preflight processes
""" """
print("- Starting preflight processes") print("Starting preflight processes")
self._setup_pathing() self._setup_pathing()
self._delete_extra_binaries() self._delete_extra_binaries()
self._download_resources() self._download_resources()
@@ -111,7 +111,7 @@ class CreateBinary:
Start postflight processes Start postflight processes
""" """
print("- Starting postflight processes") print("Starting postflight processes")
self._patch_load_command() self._patch_load_command()
self._add_commit_data() self._add_commit_data()
self._post_flight_cleanup() self._post_flight_cleanup()
@@ -124,19 +124,19 @@ class CreateBinary:
""" """
if Path(f"./dist/OpenCore-Patcher.app").exists(): if Path(f"./dist/OpenCore-Patcher.app").exists():
print("- Found OpenCore-Patcher.app, removing...") print("Found OpenCore-Patcher.app, removing...")
rm_output = subprocess.run( rm_output = subprocess.run(
["rm", "-rf", "./dist/OpenCore-Patcher.app"], ["rm", "-rf", "./dist/OpenCore-Patcher.app"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
if rm_output.returncode != 0: if rm_output.returncode != 0:
print("- Remove failed") print("Remove failed")
print(rm_output.stderr.decode('utf-8')) print(rm_output.stderr.decode('utf-8'))
raise Exception("Remove failed") raise Exception("Remove failed")
self._embed_key() self._embed_key()
print("- Building GUI binary...") print("Building GUI binary...")
build_args = [self.pyinstaller_path, "./OpenCore-Patcher-GUI.spec", "--noconfirm"] build_args = [self.pyinstaller_path, "./OpenCore-Patcher-GUI.spec", "--noconfirm"]
build_result = subprocess.run(build_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) build_result = subprocess.run(build_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -144,12 +144,12 @@ class CreateBinary:
self._strip_key() self._strip_key()
if build_result.returncode != 0: if build_result.returncode != 0:
print("- Build failed") print("Build failed")
print(build_result.stderr.decode('utf-8')) print(build_result.stderr.decode('utf-8'))
raise Exception("Build failed") raise Exception("Build failed")
# Next embed support icns into ./Resources # Next embed support icns into ./Resources
print("- Embedding icns...") print("Embedding icns...")
for file in Path("payloads/Icon/AppIcons").glob("*.icns"): for file in Path("payloads/Icon/AppIcons").glob("*.icns"):
subprocess.run( subprocess.run(
["cp", str(file), "./dist/OpenCore-Patcher.app/Contents/Resources/"], ["cp", str(file), "./dist/OpenCore-Patcher.app/Contents/Resources/"],
@@ -165,15 +165,15 @@ class CreateBinary:
""" """
if not self.args.key: if not self.args.key:
print("- No developer key provided, skipping...") print("No developer key provided, skipping...")
return return
if not self.args.site: if not self.args.site:
print("- No site provided, skipping...") print("No site provided, skipping...")
return return
print("- Embedding developer key...") print("Embedding developer key...")
if not Path("./resources/analytics_handler.py").exists(): if not Path("./resources/analytics_handler.py").exists():
print("- analytics_handler.py not found") print("analytics_handler.py not found")
return return
lines = [] lines = []
@@ -196,15 +196,15 @@ class CreateBinary:
""" """
if not self.args.key: if not self.args.key:
print("- No developer key provided, skipping...") print("No developer key provided, skipping...")
return return
if not self.args.site: if not self.args.site:
print("- No site provided, skipping...") print("No site provided, skipping...")
return return
print("- Stripping developer key...") print("Stripping developer key...")
if not Path("./resources/analytics_handler.py").exists(): if not Path("./resources/analytics_handler.py").exists():
print("- analytics_handler.py not found") print("analytics_handler.py not found")
return return
lines = [] lines = []
@@ -247,17 +247,17 @@ class CreateBinary:
] ]
print("- Deleting extra binaries...") print("Deleting extra binaries...")
for file in Path("payloads").glob(pattern="*"): for file in Path("payloads").glob(pattern="*"):
if file.is_dir(): if file.is_dir():
if file.name in whitelist_folders: if file.name in whitelist_folders:
continue continue
print(f" - Deleting {file.name}") print(f"- Deleting {file.name}")
subprocess.run(["rm", "-rf", file]) subprocess.run(["rm", "-rf", file])
else: else:
if file.name in whitelist_files: if file.name in whitelist_files:
continue continue
print(f" - Deleting {file.name}") print(f"- Deleting {file.name}")
subprocess.run(["rm", "-f", file]) subprocess.run(["rm", "-f", file])
@@ -271,23 +271,23 @@ class CreateBinary:
"Universal-Binaries.dmg" "Universal-Binaries.dmg"
] ]
print("- Downloading required resources...") print("Downloading required resources...")
for resource in required_resources: for resource in required_resources:
if Path(f"./{resource}").exists(): if Path(f"./{resource}").exists():
if self.args.reset_binaries: if self.args.reset_binaries:
print(f" - Removing old {resource}") print(f"- Removing old {resource}")
rm_output = subprocess.run( rm_output = subprocess.run(
["rm", "-rf", f"./{resource}"], ["rm", "-rf", f"./{resource}"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
if rm_output.returncode != 0: if rm_output.returncode != 0:
print("- Remove failed") print("Remove failed")
print(rm_output.stderr.decode('utf-8')) print(rm_output.stderr.decode('utf-8'))
raise Exception("Remove failed") raise Exception("Remove failed")
else: else:
print(f" - {resource} already exists, skipping download") print(f"- {resource} already exists, skipping download")
continue continue
print(f" - Downloading {resource}...") print(f"- Downloading {resource}...")
download_result = subprocess.run( download_result = subprocess.run(
[ [
@@ -298,11 +298,11 @@ class CreateBinary:
) )
if download_result.returncode != 0: if download_result.returncode != 0:
print(" - Download failed") print("- Download failed")
print(download_result.stderr.decode('utf-8')) print(download_result.stderr.decode('utf-8'))
raise Exception("Download failed") raise Exception("Download failed")
if not Path(f"./{resource}").exists(): if not Path(f"./{resource}").exists():
print(f" - {resource} not found") print(f"- {resource} not found")
raise Exception(f"{resource} not found") raise Exception(f"{resource} not found")
@@ -315,20 +315,20 @@ class CreateBinary:
if Path("./payloads.dmg").exists(): if Path("./payloads.dmg").exists():
if not self.args.reset_binaries: if not self.args.reset_binaries:
print(" - payloads.dmg already exists, skipping creation") print("- payloads.dmg already exists, skipping creation")
return return
print(" - Removing old payloads.dmg") print("- Removing old payloads.dmg")
rm_output = subprocess.run( rm_output = subprocess.run(
["rm", "-rf", "./payloads.dmg"], ["rm", "-rf", "./payloads.dmg"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
if rm_output.returncode != 0: if rm_output.returncode != 0:
print("- Remove failed") print("Remove failed")
print(rm_output.stderr.decode('utf-8')) print(rm_output.stderr.decode('utf-8'))
raise Exception("Remove failed") raise Exception("Remove failed")
print(" - Generating DMG...") print("- Generating DMG...")
dmg_output = subprocess.run([ dmg_output = subprocess.run([
'hdiutil', 'create', './payloads.dmg', 'hdiutil', 'create', './payloads.dmg',
'-megabytes', '32000', # Overlays can only be as large as the disk image allows '-megabytes', '32000', # Overlays can only be as large as the disk image allows
@@ -339,11 +339,11 @@ class CreateBinary:
'-passphrase', 'password', '-encryption' '-passphrase', 'password', '-encryption'
], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if dmg_output.returncode != 0: if dmg_output.returncode != 0:
print(" - DMG generation failed") print("- DMG generation failed")
print(dmg_output.stderr.decode('utf-8')) print(dmg_output.stderr.decode('utf-8'))
raise Exception("DMG generation failed") raise Exception("DMG generation failed")
print(" - DMG generation complete") print("- DMG generation complete")
def _add_commit_data(self): def _add_commit_data(self):
@@ -352,7 +352,7 @@ class CreateBinary:
""" """
if not self.args.branch and not self.args.commit and not self.args.commit_date: if not self.args.branch and not self.args.commit and not self.args.commit_date:
print(" - No commit data provided, adding source info") print("- No commit data provided, adding source info")
branch = "Built from source" branch = "Built from source"
commit_url = "" commit_url = ""
commit_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) commit_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
@@ -360,7 +360,7 @@ class CreateBinary:
branch = self.args.branch branch = self.args.branch
commit_url = self.args.commit commit_url = self.args.commit
commit_date = self.args.commit_date commit_date = self.args.commit_date
print(" - Adding commit data to Info.plist") print("- Adding commit data to Info.plist")
plist_path = Path("./dist/OpenCore-Patcher.app/Contents/Info.plist") plist_path = Path("./dist/OpenCore-Patcher.app/Contents/Info.plist")
plist = plistlib.load(Path(plist_path).open("rb")) plist = plistlib.load(Path(plist_path).open("rb"))
plist["Github"] = { plist["Github"] = {
@@ -389,7 +389,7 @@ class CreateBinary:
""" """
print(" - Patching LC_VERSION_MIN_MACOSX") print("- Patching LC_VERSION_MIN_MACOSX")
path = './dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher' path = './dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher'
find = b'\x00\x0D\x0A\x00' # 10.13 (0xA0D) find = b'\x00\x0D\x0A\x00' # 10.13 (0xA0D)
replace = b'\x00\x0A\x0A\x00' # 10.10 (0xA0A) replace = b'\x00\x0A\x0A\x00' # 10.10 (0xA0A)
@@ -406,13 +406,13 @@ class CreateBinary:
""" """
path = "./dist/OpenCore-Patcher" path = "./dist/OpenCore-Patcher"
print(f" - Removing {path}") print(f"- Removing {path}")
rm_output = subprocess.run( rm_output = subprocess.run(
["rm", "-rf", path], ["rm", "-rf", path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
if rm_output.returncode != 0: if rm_output.returncode != 0:
print(f" - Remove failed: {path}") print(f"- Remove failed: {path}")
print(rm_output.stderr.decode('utf-8')) print(rm_output.stderr.decode('utf-8'))
raise Exception(f"Remove failed: {path}") raise Exception(f"Remove failed: {path}")
@@ -422,13 +422,13 @@ class CreateBinary:
Validate generated binary Validate generated binary
""" """
print(" - Validating binary") print("- Validating binary")
validate_output = subprocess.run( validate_output = subprocess.run(
["./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher", "--build", "--model", "MacPro3,1"], ["./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher", "--build", "--model", "MacPro3,1"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
if validate_output.returncode != 0: if validate_output.returncode != 0:
print(" - Validation failed") print("- Validation failed")
print(validate_output.stderr.decode('utf-8')) print(validate_output.stderr.decode('utf-8'))
raise Exception("Validation failed") raise Exception("Validation failed")
+5 -4
View File
@@ -59,9 +59,9 @@ class arguments:
Start root volume patching Start root volume patching
""" """
logging.info("- Set System Volume patching") logging.info("Set System Volume patching")
if "Library/InstallerSandboxes/" in str(self.constants.payload_path): if "Library/InstallerSandboxes/" in str(self.constants.payload_path):
logging.info("- Running from Installer Sandbox") logging.info("- Running from Installer Sandbox, blocking OS updaters")
thread = threading.Thread(target=sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, None).start_patch) thread = threading.Thread(target=sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, None).start_patch)
thread.start() thread.start()
while thread.is_alive(): while thread.is_alive():
@@ -75,7 +75,7 @@ class arguments:
""" """
Start root volume unpatching Start root volume unpatching
""" """
logging.info("- Set System Volume unpatching") logging.info("Set System Volume unpatching")
sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, None).start_unpatch() sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, None).start_unpatch()
@@ -84,7 +84,7 @@ class arguments:
Start root volume auto patching Start root volume auto patching
""" """
logging.info("- Set Auto patching") logging.info("Set Auto patching")
sys_patch_auto.AutomaticSysPatch(self.constants).start_auto_patch() sys_patch_auto.AutomaticSysPatch(self.constants).start_auto_patch()
@@ -92,6 +92,7 @@ class arguments:
""" """
Start config building process Start config building process
""" """
logging.info("Set OpenCore Build")
if self.args.model: if self.args.model:
if self.args.model: if self.args.model:
+4 -4
View File
@@ -136,7 +136,7 @@ class BuildSupport:
for acpi in config_plist["ACPI"]["Add"]: for acpi in config_plist["ACPI"]["Add"]:
if not Path(self.constants.opencore_release_folder / Path("EFI/OC/ACPI") / Path(acpi["Path"])).exists(): if not Path(self.constants.opencore_release_folder / Path("EFI/OC/ACPI") / Path(acpi["Path"])).exists():
logging.info(f" - Missing ACPI Table: {acpi['Path']}") logging.info(f"- Missing ACPI Table: {acpi['Path']}")
raise Exception(f"Missing ACPI Table: {acpi['Path']}") raise Exception(f"Missing ACPI Table: {acpi['Path']}")
for kext in config_plist["Kernel"]["Add"]: for kext in config_plist["Kernel"]["Add"]:
@@ -155,19 +155,19 @@ class BuildSupport:
for tool in config_plist["Misc"]["Tools"]: for tool in config_plist["Misc"]["Tools"]:
if not Path(self.constants.opencore_release_folder / Path("EFI/OC/Tools") / Path(tool["Path"])).exists(): if not Path(self.constants.opencore_release_folder / Path("EFI/OC/Tools") / Path(tool["Path"])).exists():
logging.info(f" - Missing tool: {tool['Path']}") logging.info(f"- Missing tool: {tool['Path']}")
raise Exception(f"Missing tool: {tool['Path']}") raise Exception(f"Missing tool: {tool['Path']}")
for driver in config_plist["UEFI"]["Drivers"]: for driver in config_plist["UEFI"]["Drivers"]:
if not Path(self.constants.opencore_release_folder / Path("EFI/OC/Drivers") / Path(driver["Path"])).exists(): if not Path(self.constants.opencore_release_folder / Path("EFI/OC/Drivers") / Path(driver["Path"])).exists():
logging.info(f" - Missing driver: {driver['Path']}") logging.info(f"- Missing driver: {driver['Path']}")
raise Exception(f"Missing driver: {driver['Path']}") raise Exception(f"Missing driver: {driver['Path']}")
# Validating local files # Validating local files
# Report if they have no associated config.plist entry (i.e. they're not being used) # Report if they have no associated config.plist entry (i.e. they're not being used)
for tool_files in Path(self.constants.opencore_release_folder / Path("EFI/OC/Tools")).glob("*"): for tool_files in Path(self.constants.opencore_release_folder / Path("EFI/OC/Tools")).glob("*"):
if tool_files.name not in [x["Path"] for x in config_plist["Misc"]["Tools"]]: if tool_files.name not in [x["Path"] for x in config_plist["Misc"]["Tools"]]:
logging.info(f" - Missing tool from config: {tool_files.name}") logging.info(f"- Missing tool from config: {tool_files.name}")
raise Exception(f"Missing tool from config: {tool_files.name}") raise Exception(f"Missing tool from config: {tool_files.name}")
for driver_file in Path(self.constants.opencore_release_folder / Path("EFI/OC/Drivers")).glob("*"): for driver_file in Path(self.constants.opencore_release_folder / Path("EFI/OC/Drivers")).glob("*"):
+5 -5
View File
@@ -48,7 +48,7 @@ class GlobalEnviromentSettings:
try: try:
plistlib.dump(plist, Path(self.global_settings_plist).open("wb")) plistlib.dump(plist, Path(self.global_settings_plist).open("wb"))
except PermissionError: except PermissionError:
logging.info("- Failed to write to global settings file") logging.info("Failed to write to global settings file")
def _generate_settings_file(self) -> None: def _generate_settings_file(self) -> None:
@@ -57,7 +57,7 @@ class GlobalEnviromentSettings:
try: try:
plistlib.dump({"Developed by Dortania": True,}, Path(self.global_settings_plist).open("wb")) plistlib.dump({"Developed by Dortania": True,}, Path(self.global_settings_plist).open("wb"))
except PermissionError: except PermissionError:
logging.info("- Permission error: Unable to write to global settings file") logging.info("Permission error: Unable to write to global settings file")
def _convert_defaults_to_global_settings(self) -> None: def _convert_defaults_to_global_settings(self) -> None:
@@ -76,14 +76,14 @@ class GlobalEnviromentSettings:
try: try:
plistlib.dump(global_settings_plist, Path(self.global_settings_plist).open("wb")) plistlib.dump(global_settings_plist, Path(self.global_settings_plist).open("wb"))
except PermissionError: except PermissionError:
logging.info("- Permission error: Unable to write to global settings file") logging.info("Permission error: Unable to write to global settings file")
return return
# delete defaults plist # delete defaults plist
try: try:
Path(defaults_path).unlink() Path(defaults_path).unlink()
except PermissionError: except PermissionError:
logging.info("- Permission error: Unable to delete defaults plist") logging.info("Permission error: Unable to delete defaults plist")
def _fix_file_permission(self) -> None: def _fix_file_permission(self) -> None:
@@ -100,6 +100,6 @@ class GlobalEnviromentSettings:
# Set file permission to allow any user to write to log file # Set file permission to allow any user to write to log file
result = subprocess.run(["chmod", "777", self.global_settings_plist], capture_output=True) result = subprocess.run(["chmod", "777", self.global_settings_plist], capture_output=True)
if result.returncode != 0: if result.returncode != 0:
logging.warning("- Failed to fix settings file permissions:") logging.warning("Failed to fix settings file permissions:")
if result.stderr: if result.stderr:
logging.warning(result.stderr.decode("utf-8")) logging.warning(result.stderr.decode("utf-8"))
+15 -15
View File
@@ -88,13 +88,13 @@ class tui_disk_installation:
def install_opencore(self, full_disk_identifier: str): def install_opencore(self, full_disk_identifier: str):
# TODO: Apple Script fails in Yosemite(?) and older # TODO: Apple Script fails in Yosemite(?) and older
logging.info(f"- Mounting partition: {full_disk_identifier}") logging.info(f"Mounting partition: {full_disk_identifier}")
if self.constants.detected_os >= os_data.os_data.el_capitan and not self.constants.recovery_status: if self.constants.detected_os >= os_data.os_data.el_capitan and not self.constants.recovery_status:
try: try:
applescript.AppleScript(f'''do shell script "diskutil mount {full_disk_identifier}" with prompt "OpenCore Legacy Patcher needs administrator privileges to mount this volume." with administrator privileges without altering line endings''').run() applescript.AppleScript(f'''do shell script "diskutil mount {full_disk_identifier}" with prompt "OpenCore Legacy Patcher needs administrator privileges to mount this volume." with administrator privileges without altering line endings''').run()
except applescript.ScriptError as e: except applescript.ScriptError as e:
if "User canceled" in str(e): if "User canceled" in str(e):
logging.info("- Mount cancelled by user") logging.info("Mount cancelled by user")
return return
logging.info(f"An error occurred: {e}") logging.info(f"An error occurred: {e}")
if utilities.check_boot_mode() == "safe_boot": if utilities.check_boot_mode() == "safe_boot":
@@ -104,7 +104,7 @@ class tui_disk_installation:
else: else:
result = subprocess.run(f"diskutil mount {full_disk_identifier}".split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = subprocess.run(f"diskutil mount {full_disk_identifier}".split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Mount failed") logging.info("Mount failed")
logging.info(result.stderr.decode()) logging.info(result.stderr.decode())
return return
@@ -124,18 +124,18 @@ class tui_disk_installation:
return False return False
if (mount_path / Path("EFI/OC")).exists(): if (mount_path / Path("EFI/OC")).exists():
logging.info("- Removing preexisting EFI/OC folder") logging.info("Removing preexisting EFI/OC folder")
subprocess.run(["rm", "-rf", mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["rm", "-rf", mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if (mount_path / Path("System")).exists(): if (mount_path / Path("System")).exists():
logging.info("- Removing preexisting System folder") logging.info("Removing preexisting System folder")
subprocess.run(["rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if (mount_path / Path("boot.efi")).exists(): if (mount_path / Path("boot.efi")).exists():
logging.info("- Removing preexisting boot.efi") logging.info("Removing preexisting boot.efi")
subprocess.run(["rm", mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["rm", mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
logging.info("- Copying OpenCore onto EFI partition") logging.info("Copying OpenCore onto EFI partition")
subprocess.run(["mkdir", "-p", mount_path / Path("EFI")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["mkdir", "-p", mount_path / Path("EFI")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.run(["cp", "-r", self.constants.opencore_release_folder / Path("EFI/OC"), mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", "-r", self.constants.opencore_release_folder / Path("EFI/OC"), mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.run(["cp", "-r", self.constants.opencore_release_folder / Path("System"), mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", "-r", self.constants.opencore_release_folder / Path("System"), mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -144,7 +144,7 @@ class tui_disk_installation:
subprocess.run(["cp", self.constants.opencore_release_folder / Path("boot.efi"), mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", self.constants.opencore_release_folder / Path("boot.efi"), mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if self.constants.boot_efi is True: if self.constants.boot_efi is True:
logging.info("- Converting Bootstrap to BOOTx64.efi") logging.info("Converting Bootstrap to BOOTx64.efi")
if (mount_path / Path("EFI/BOOT")).exists(): if (mount_path / Path("EFI/BOOT")).exists():
subprocess.run(["rm", "-rf", mount_path / Path("EFI/BOOT")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["rm", "-rf", mount_path / Path("EFI/BOOT")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Path(mount_path / Path("EFI/BOOT")).mkdir() Path(mount_path / Path("EFI/BOOT")).mkdir()
@@ -152,23 +152,23 @@ class tui_disk_installation:
subprocess.run(["rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if self._determine_sd_card(sd_type) is True: if self._determine_sd_card(sd_type) is True:
logging.info("- Adding SD Card icon") logging.info("Adding SD Card icon")
subprocess.run(["cp", self.constants.icon_path_sd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", self.constants.icon_path_sd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
elif ssd_type is True: elif ssd_type is True:
logging.info("- Adding SSD icon") logging.info("Adding SSD icon")
subprocess.run(["cp", self.constants.icon_path_ssd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", self.constants.icon_path_ssd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
elif disk_type == "USB": elif disk_type == "USB":
logging.info("- Adding External USB Drive icon") logging.info("Adding External USB Drive icon")
subprocess.run(["cp", self.constants.icon_path_external, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", self.constants.icon_path_external, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else: else:
logging.info("- Adding Internal Drive icon") logging.info("Adding Internal Drive icon")
subprocess.run(["cp", self.constants.icon_path_internal, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.run(["cp", self.constants.icon_path_internal, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
logging.info("- Cleaning install location") logging.info("Cleaning install location")
if not self.constants.recovery_status: if not self.constants.recovery_status:
logging.info("- Unmounting EFI partition") logging.info("Unmounting EFI partition")
subprocess.run(["diskutil", "umount", mount_path], stdout=subprocess.PIPE).stdout.decode().strip().encode() subprocess.run(["diskutil", "umount", mount_path], stdout=subprocess.PIPE).stdout.decode().strip().encode()
logging.info("- OpenCore transfer complete") logging.info("OpenCore transfer complete")
return True return True
+58 -58
View File
@@ -94,7 +94,7 @@ class KernelDebugKitObject:
global KDK_ASSET_LIST global KDK_ASSET_LIST
logging.info("- Pulling KDK list from KdkSupportPkg API") logging.info("Pulling KDK list from KdkSupportPkg API")
if KDK_ASSET_LIST: if KDK_ASSET_LIST:
return KDK_ASSET_LIST return KDK_ASSET_LIST
@@ -107,11 +107,11 @@ class KernelDebugKitObject:
timeout=5 timeout=5
) )
except (requests.exceptions.Timeout, requests.exceptions.TooManyRedirects, requests.exceptions.ConnectionError): except (requests.exceptions.Timeout, requests.exceptions.TooManyRedirects, requests.exceptions.ConnectionError):
logging.info("- Could not contact KDK API") logging.info("Could not contact KDK API")
return None return None
if results.status_code != 200: if results.status_code != 200:
logging.info("- Could not fetch KDK list") logging.info("Could not fetch KDK list")
return None return None
KDK_ASSET_LIST = sorted(results.json(), key=lambda x: (packaging.version.parse(x["version"]), datetime.datetime.fromisoformat(x["date"])), reverse=True) KDK_ASSET_LIST = sorted(results.json(), key=lambda x: (packaging.version.parse(x["version"]), datetime.datetime.fromisoformat(x["date"])), reverse=True)
@@ -138,12 +138,12 @@ class KernelDebugKitObject:
if os_data.os_conversion.os_to_kernel(str(parsed_version.major)) < os_data.os_data.ventura: if os_data.os_conversion.os_to_kernel(str(parsed_version.major)) < os_data.os_data.ventura:
self.error_msg = "KDKs are not required for macOS Monterey or older" self.error_msg = "KDKs are not required for macOS Monterey or older"
logging.warning(f"- {self.error_msg}") logging.warning(f"{self.error_msg}")
return return
self.kdk_installed_path = self._local_kdk_installed() self.kdk_installed_path = self._local_kdk_installed()
if self.kdk_installed_path: if self.kdk_installed_path:
logging.info(f"- KDK already installed ({Path(self.kdk_installed_path).name}), skipping") logging.info(f"KDK already installed ({Path(self.kdk_installed_path).name}), skipping")
self.kdk_already_installed = True self.kdk_already_installed = True
self.success = True self.success = True
return return
@@ -151,29 +151,29 @@ class KernelDebugKitObject:
remote_kdk_version = self._get_remote_kdks() remote_kdk_version = self._get_remote_kdks()
if remote_kdk_version is None: if remote_kdk_version is None:
logging.warning("- Failed to fetch KDK list, falling back to local KDK matching") logging.warning("Failed to fetch KDK list, falling back to local KDK matching")
# First check if a KDK matching the current macOS version is installed # First check if a KDK matching the current macOS version is installed
# ex. 13.0.1 vs 13.0 # ex. 13.0.1 vs 13.0
loose_version = f"{parsed_version.major}.{parsed_version.minor}" loose_version = f"{parsed_version.major}.{parsed_version.minor}"
logging.info(f"- Checking for KDKs loosely matching {loose_version}") logging.info(f"Checking for KDKs loosely matching {loose_version}")
self.kdk_installed_path = self._local_kdk_installed(match=loose_version, check_version=True) self.kdk_installed_path = self._local_kdk_installed(match=loose_version, check_version=True)
if self.kdk_installed_path: if self.kdk_installed_path:
logging.info(f"- Found matching KDK: {Path(self.kdk_installed_path).name}") logging.info(f"Found matching KDK: {Path(self.kdk_installed_path).name}")
self.kdk_already_installed = True self.kdk_already_installed = True
self.success = True self.success = True
return return
older_version = f"{parsed_version.major}.{parsed_version.minor - 1 if parsed_version.minor > 0 else 0}" older_version = f"{parsed_version.major}.{parsed_version.minor - 1 if parsed_version.minor > 0 else 0}"
logging.info(f"- Checking for KDKs matching {older_version}") logging.info(f"Checking for KDKs matching {older_version}")
self.kdk_installed_path = self._local_kdk_installed(match=older_version, check_version=True) self.kdk_installed_path = self._local_kdk_installed(match=older_version, check_version=True)
if self.kdk_installed_path: if self.kdk_installed_path:
logging.info(f"- Found matching KDK: {Path(self.kdk_installed_path).name}") logging.info(f"Found matching KDK: {Path(self.kdk_installed_path).name}")
self.kdk_already_installed = True self.kdk_already_installed = True
self.success = True self.success = True
return return
logging.warning(f"- Couldn't find KDK matching {host_version} or {older_version}, please install one manually") logging.warning(f"Couldn't find KDK matching {host_version} or {older_version}, please install one manually")
self.error_msg = f"Could not contact KdkSupportPkg API, and no KDK matching {host_version} ({host_build}) or {older_version} was installed.\nPlease ensure you have a network connection or manually install a KDK." self.error_msg = f"Could not contact KdkSupportPkg API, and no KDK matching {host_version} ({host_build}) or {older_version} was installed.\nPlease ensure you have a network connection or manually install a KDK."
@@ -211,32 +211,32 @@ class KernelDebugKitObject:
if self.kdk_url == "": if self.kdk_url == "":
if self.kdk_closest_match_url == "": if self.kdk_closest_match_url == "":
logging.warning(f"- No KDKs found for {host_build} ({host_version})") logging.warning(f"No KDKs found for {host_build} ({host_version})")
self.error_msg = f"No KDKs found for {host_build} ({host_version})" self.error_msg = f"No KDKs found for {host_build} ({host_version})"
return return
logging.info(f"- No direct match found for {host_build}, falling back to closest match") logging.info(f"No direct match found for {host_build}, falling back to closest match")
logging.info(f"- Closest Match: {self.kdk_closest_match_url_build} ({self.kdk_closest_match_url_version})") logging.info(f"Closest Match: {self.kdk_closest_match_url_build} ({self.kdk_closest_match_url_version})")
self.kdk_url = self.kdk_closest_match_url self.kdk_url = self.kdk_closest_match_url
self.kdk_url_build = self.kdk_closest_match_url_build self.kdk_url_build = self.kdk_closest_match_url_build
self.kdk_url_version = self.kdk_closest_match_url_version self.kdk_url_version = self.kdk_closest_match_url_version
self.kdk_url_expected_size = self.kdk_closest_match_url_expected_size self.kdk_url_expected_size = self.kdk_closest_match_url_expected_size
else: else:
logging.info(f"- Direct match found for {host_build} ({host_version})") logging.info(f"Direct match found for {host_build} ({host_version})")
# Check if this KDK is already installed # Check if this KDK is already installed
self.kdk_installed_path = self._local_kdk_installed(match=self.kdk_url_build) self.kdk_installed_path = self._local_kdk_installed(match=self.kdk_url_build)
if self.kdk_installed_path: if self.kdk_installed_path:
logging.info(f"- KDK already installed ({Path(self.kdk_installed_path).name}), skipping") logging.info(f"KDK already installed ({Path(self.kdk_installed_path).name}), skipping")
self.kdk_already_installed = True self.kdk_already_installed = True
self.success = True self.success = True
return return
logging.info("- Following KDK is recommended:") logging.info("Following KDK is recommended:")
logging.info(f"- KDK Build: {self.kdk_url_build}") logging.info(f"- KDK Build: {self.kdk_url_build}")
logging.info(f"- KDK Version: {self.kdk_url_version}") logging.info(f"- KDK Version: {self.kdk_url_version}")
logging.info(f"- KDK URL: {self.kdk_url}") logging.info(f"- KDK URL: {self.kdk_url}")
self.success = True self.success = True
@@ -256,7 +256,7 @@ class KernelDebugKitObject:
self.error_msg = "" self.error_msg = ""
if self.kdk_already_installed: if self.kdk_already_installed:
logging.info("- No download required, KDK already installed") logging.info("No download required, KDK already installed")
self.success = True self.success = True
return None return None
@@ -265,7 +265,7 @@ class KernelDebugKitObject:
logging.error(self.error_msg) logging.error(self.error_msg)
return None return None
logging.info(f"- Returning DownloadObject for KDK: {Path(self.kdk_url).name}") logging.info(f"Returning DownloadObject for KDK: {Path(self.kdk_url).name}")
self.success = True self.success = True
kdk_download_path = self.constants.kdk_download_path if override_path == "" else Path(override_path) kdk_download_path = self.constants.kdk_download_path if override_path == "" else Path(override_path)
@@ -294,7 +294,7 @@ class KernelDebugKitObject:
plist_path.touch() plist_path.touch()
plistlib.dump(kdk_dict, plist_path.open("wb"), sort_keys=False) plistlib.dump(kdk_dict, plist_path.open("wb"), sort_keys=False)
except Exception as e: except Exception as e:
logging.error(f"- Failed to generate KDK Info.plist: {e}") logging.error(f"Failed to generate KDK Info.plist: {e}")
def _local_kdk_valid(self, kdk_path: Path) -> bool: def _local_kdk_valid(self, kdk_path: Path) -> bool:
@@ -314,14 +314,14 @@ class KernelDebugKitObject:
""" """
if not Path(f"{kdk_path}/System/Library/CoreServices/SystemVersion.plist").exists(): if not Path(f"{kdk_path}/System/Library/CoreServices/SystemVersion.plist").exists():
logging.info(f"- Corrupted KDK found ({kdk_path.name}), removing due to missing SystemVersion.plist") logging.info(f"Corrupted KDK found ({kdk_path.name}), removing due to missing SystemVersion.plist")
self._remove_kdk(kdk_path) self._remove_kdk(kdk_path)
return False return False
# Get build from KDK # Get build from KDK
kdk_plist_data = plistlib.load(Path(f"{kdk_path}/System/Library/CoreServices/SystemVersion.plist").open("rb")) kdk_plist_data = plistlib.load(Path(f"{kdk_path}/System/Library/CoreServices/SystemVersion.plist").open("rb"))
if "ProductBuildVersion" not in kdk_plist_data: if "ProductBuildVersion" not in kdk_plist_data:
logging.info(f"- Corrupted KDK found ({kdk_path.name}), removing due to missing ProductBuildVersion") logging.info(f"Corrupted KDK found ({kdk_path.name}), removing due to missing ProductBuildVersion")
self._remove_kdk(kdk_path) self._remove_kdk(kdk_path)
return False return False
@@ -331,7 +331,7 @@ class KernelDebugKitObject:
result = subprocess.run(["pkgutil", "--files", f"com.apple.pkg.KDK.{kdk_build}"], capture_output=True) result = subprocess.run(["pkgutil", "--files", f"com.apple.pkg.KDK.{kdk_build}"], capture_output=True)
if result.returncode != 0: if result.returncode != 0:
# If pkg receipt is missing, we'll fallback to legacy validation # If pkg receipt is missing, we'll fallback to legacy validation
logging.info(f"- pkg receipt missing for {kdk_path.name}, falling back to legacy validation") logging.info(f"pkg receipt missing for {kdk_path.name}, falling back to legacy validation")
return self._local_kdk_valid_legacy(kdk_path) return self._local_kdk_valid_legacy(kdk_path)
# Go through each line of the pkg receipt and ensure it exists # Go through each line of the pkg receipt and ensure it exists
@@ -339,7 +339,7 @@ class KernelDebugKitObject:
if not line.startswith("System/Library/Extensions"): if not line.startswith("System/Library/Extensions"):
continue continue
if not Path(f"{kdk_path}/{line}").exists(): if not Path(f"{kdk_path}/{line}").exists():
logging.info(f"- Corrupted KDK found ({kdk_path.name}), removing due to missing file: {line}") logging.info(f"Corrupted KDK found ({kdk_path.name}), removing due to missing file: {line}")
self._remove_kdk(kdk_path) self._remove_kdk(kdk_path)
return False return False
@@ -368,7 +368,7 @@ class KernelDebugKitObject:
for kext in KEXT_CATALOG: for kext in KEXT_CATALOG:
if not Path(f"{kdk_path}/System/Library/Extensions/{kext}").exists(): if not Path(f"{kdk_path}/System/Library/Extensions/{kext}").exists():
logging.info(f"- Corrupted KDK found, removing due to missing: {kdk_path}/System/Library/Extensions/{kext}") logging.info(f"Corrupted KDK found, removing due to missing: {kdk_path}/System/Library/Extensions/{kext}")
self._remove_kdk(kdk_path) self._remove_kdk(kdk_path)
return False return False
@@ -427,15 +427,15 @@ class KernelDebugKitObject:
if not kdk_pkg.name.endswith(f"{match}.pkg"): if not kdk_pkg.name.endswith(f"{match}.pkg"):
continue continue
logging.info(f"- Found KDK backup: {kdk_pkg.name}") logging.info(f"Found KDK backup: {kdk_pkg.name}")
if self.passive is False: if self.passive is False:
logging.info("- Attempting KDK restoration") logging.info("Attempting KDK restoration")
if KernelDebugKitUtilities().install_kdk_pkg(kdk_pkg): if KernelDebugKitUtilities().install_kdk_pkg(kdk_pkg):
logging.info("- Successfully restored KDK") logging.info("Successfully restored KDK")
return self._local_kdk_installed(match=match, check_version=check_version) return self._local_kdk_installed(match=match, check_version=check_version)
else: else:
# When in passive mode, we're just checking if a KDK could be restored # When in passive mode, we're just checking if a KDK could be restored
logging.info("- KDK restoration skipped, running in passive mode") logging.info("KDK restoration skipped, running in passive mode")
return kdk_pkg return kdk_pkg
return None return None
@@ -453,22 +453,22 @@ class KernelDebugKitObject:
return return
if os.getuid() != 0: if os.getuid() != 0:
logging.warning("- Cannot remove KDK, not running as root") logging.warning("Cannot remove KDK, not running as root")
return return
if not Path(kdk_path).exists(): if not Path(kdk_path).exists():
logging.warning(f"- KDK does not exist: {kdk_path}") logging.warning(f"KDK does not exist: {kdk_path}")
return return
rm_args = ["rm", "-rf" if Path(kdk_path).is_dir() else "-f", kdk_path] rm_args = ["rm", "-rf" if Path(kdk_path).is_dir() else "-f", kdk_path]
result = utilities.elevated(rm_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = utilities.elevated(rm_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.warning(f"- Failed to remove KDK: {kdk_path}") logging.warning(f"Failed to remove KDK: {kdk_path}")
logging.warning(f"- {result.stdout.decode('utf-8')}") logging.warning(f"{result.stdout.decode('utf-8')}")
return return
logging.info(f"- Successfully removed KDK: {kdk_path}") logging.info(f"Successfully removed KDK: {kdk_path}")
def _remove_unused_kdks(self, exclude_builds: list = None) -> None: def _remove_unused_kdks(self, exclude_builds: list = None) -> None:
@@ -495,7 +495,7 @@ class KernelDebugKitObject:
if not Path(KDK_INSTALL_PATH).exists(): if not Path(KDK_INSTALL_PATH).exists():
return return
logging.info("- Cleaning unused KDKs") logging.info("Cleaning unused KDKs")
for kdk_folder in Path(KDK_INSTALL_PATH).iterdir(): for kdk_folder in Path(KDK_INSTALL_PATH).iterdir():
if kdk_folder.name.endswith(".kdk") or kdk_folder.name.endswith(".pkg"): if kdk_folder.name.endswith(".kdk") or kdk_folder.name.endswith(".pkg"):
should_remove = True should_remove = True
@@ -532,17 +532,17 @@ class KernelDebugKitObject:
# TODO: should we use the checksum from the API? # TODO: should we use the checksum from the API?
result = subprocess.run(["hdiutil", "verify", self.constants.kdk_download_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = subprocess.run(["hdiutil", "verify", self.constants.kdk_download_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Error: Kernel Debug Kit checksum verification failed!") logging.info("Error: Kernel Debug Kit checksum verification failed!")
logging.info(f"- Output: {result.stderr.decode('utf-8')}") logging.info(f"Output: {result.stderr.decode('utf-8')}")
msg = "Kernel Debug Kit checksum verification failed, please try again.\n\nIf this continues to fail, ensure you're downloading on a stable network connection (ie. Ethernet)" msg = "Kernel Debug Kit checksum verification failed, please try again.\n\nIf this continues to fail, ensure you're downloading on a stable network connection (ie. Ethernet)"
logging.info(f"- {msg}") logging.info(f"{msg}")
self.error_msg = msg self.error_msg = msg
return False return False
self._remove_unused_kdks() self._remove_unused_kdks()
self.success = True self.success = True
logging.info("- Kernel Debug Kit checksum verified") logging.info("Kernel Debug Kit checksum verified")
return True return True
@@ -568,17 +568,17 @@ class KernelDebugKitUtilities:
""" """
if os.getuid() != 0: if os.getuid() != 0:
logging.warning("- Cannot install KDK, not running as root") logging.warning("Cannot install KDK, not running as root")
return False return False
logging.info(f"- Installing KDK package: {kdk_path.name}") logging.info(f"Installing KDK package: {kdk_path.name}")
logging.info(f" - This may take a while...") logging.info(f"- This may take a while...")
# TODO: Check whether enough disk space is available # TODO: Check whether enough disk space is available
result = utilities.elevated(["installer", "-pkg", kdk_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = utilities.elevated(["installer", "-pkg", kdk_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Failed to install KDK:") logging.info("Failed to install KDK:")
logging.info(result.stdout.decode('utf-8')) logging.info(result.stdout.decode('utf-8'))
if result.stderr: if result.stderr:
logging.info(result.stderr.decode('utf-8')) logging.info(result.stderr.decode('utf-8'))
@@ -599,21 +599,21 @@ class KernelDebugKitUtilities:
""" """
if os.getuid() != 0: if os.getuid() != 0:
logging.warning("- Cannot install KDK, not running as root") logging.warning("Cannot install KDK, not running as root")
return False return False
logging.info(f"- Extracting downloaded KDK disk image") logging.info(f"Extracting downloaded KDK disk image")
with tempfile.TemporaryDirectory() as mount_point: with tempfile.TemporaryDirectory() as mount_point:
result = subprocess.run(["hdiutil", "attach", kdk_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = subprocess.run(["hdiutil", "attach", kdk_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Failed to mount KDK:") logging.info("Failed to mount KDK:")
logging.info(result.stdout.decode('utf-8')) logging.info(result.stdout.decode('utf-8'))
return False return False
kdk_pkg_path = Path(f"{mount_point}/KernelDebugKit.pkg") kdk_pkg_path = Path(f"{mount_point}/KernelDebugKit.pkg")
if not kdk_pkg_path.exists(): if not kdk_pkg_path.exists():
logging.warning("- Failed to find KDK package in DMG, likely corrupted!!!") logging.warning("Failed to find KDK package in DMG, likely corrupted!!!")
self._unmount_disk_image(mount_point) self._unmount_disk_image(mount_point)
return False return False
@@ -624,7 +624,7 @@ class KernelDebugKitUtilities:
self._create_backup(kdk_pkg_path, Path(f"{kdk_path.parent}/{KDK_INFO_PLIST}")) self._create_backup(kdk_pkg_path, Path(f"{kdk_path.parent}/{KDK_INFO_PLIST}"))
self._unmount_disk_image(mount_point) self._unmount_disk_image(mount_point)
logging.info("- Successfully installed KDK") logging.info("Successfully installed KDK")
return True return True
def _unmount_disk_image(self, mount_point) -> None: def _unmount_disk_image(self, mount_point) -> None:
@@ -647,31 +647,31 @@ class KernelDebugKitUtilities:
""" """
if not kdk_path.exists(): if not kdk_path.exists():
logging.warning("- KDK does not exist, cannot create backup") logging.warning("KDK does not exist, cannot create backup")
return return
if not kdk_info_plist.exists(): if not kdk_info_plist.exists():
logging.warning("- KDK Info.plist does not exist, cannot create backup") logging.warning("KDK Info.plist does not exist, cannot create backup")
return return
kdk_info_dict = plistlib.load(kdk_info_plist.open("rb")) kdk_info_dict = plistlib.load(kdk_info_plist.open("rb"))
if 'version' not in kdk_info_dict or 'build' not in kdk_info_dict: if 'version' not in kdk_info_dict or 'build' not in kdk_info_dict:
logging.warning("- Malformed KDK Info.plist provided, cannot create backup") logging.warning("Malformed KDK Info.plist provided, cannot create backup")
return return
if os.getuid() != 0: if os.getuid() != 0:
logging.warning("- Cannot create KDK backup, not running as root") logging.warning("Cannot create KDK backup, not running as root")
return return
kdk_dst_name = f"KDK_{kdk_info_dict['version']}_{kdk_info_dict['build']}.pkg" kdk_dst_name = f"KDK_{kdk_info_dict['version']}_{kdk_info_dict['build']}.pkg"
kdk_dst_path = Path(f"{KDK_INSTALL_PATH}/{kdk_dst_name}") kdk_dst_path = Path(f"{KDK_INSTALL_PATH}/{kdk_dst_name}")
logging.info(f"- Creating backup: {kdk_dst_name}") logging.info(f"Creating backup: {kdk_dst_name}")
if kdk_dst_path.exists(): if kdk_dst_path.exists():
logging.info("- Backup already exists, skipping") logging.info("Backup already exists, skipping")
return return
result = utilities.elevated(["cp", "-R", kdk_path, kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = utilities.elevated(["cp", "-R", kdk_path, kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Failed to create KDK backup:") logging.info("Failed to create KDK backup:")
logging.info(result.stdout.decode('utf-8')) logging.info(result.stdout.decode('utf-8'))
+60 -14
View File
@@ -1,5 +1,7 @@
import wx
import os import os
import sys import sys
import time
import logging import logging
import threading import threading
import traceback import traceback
@@ -32,22 +34,24 @@ class InitializeLoggingSupport:
""" """
def __init__(self, global_constants: constants.Constants) -> None: def __init__(self, global_constants: constants.Constants) -> None:
self.log_filename: str = "OpenCore-Patcher.log"
self.log_filepath: Path = None
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
self.log_filename: str = f"OpenCore-Patcher-{self.constants.patcher_version}.log"
self.log_filepath: Path = None
self.original_excepthook: sys = sys.excepthook self.original_excepthook: sys = sys.excepthook
self.original_thread_excepthook: threading = threading.excepthook self.original_thread_excepthook: threading = threading.excepthook
self.max_file_size: int = 1024 * 1024 * 10 # 10 MB self.max_file_size: int = 1024 * 1024 # 1 MB
self.file_size_redline: int = 1024 * 1024 * 9 # 9 MB, when to start cleaning log file self.file_size_redline: int = 1024 * 1024 - 1024 * 100 # 900 KB, when to start cleaning log file
self._initialize_logging_path() self._initialize_logging_path()
self._clean_log_file() self._clean_log_file()
self._attempt_initialize_logging_configuration() self._attempt_initialize_logging_configuration()
self._start_logging()
self._implement_custom_traceback_handler() self._implement_custom_traceback_handler()
self._fix_file_permission() self._fix_file_permission()
self._clean_prior_version_logs()
def _initialize_logging_path(self) -> None: def _initialize_logging_path(self) -> None:
@@ -61,9 +65,6 @@ class InitializeLoggingSupport:
# Likely in an installer environment, store in /Users/Shared # Likely in an installer environment, store in /Users/Shared
self.log_filepath = Path("/Users/Shared") / self.log_filename self.log_filepath = Path("/Users/Shared") / self.log_filename
print("- Initializing logging framework...")
print(f" - Log file: {self.log_filepath}")
def _clean_log_file(self) -> None: def _clean_log_file(self) -> None:
""" """
@@ -87,7 +88,33 @@ class InitializeLoggingSupport:
# Rename current log file to backup log file # Rename current log file to backup log file
self.log_filepath.rename(backup_log_filepath) self.log_filepath.rename(backup_log_filepath)
except Exception as e: except Exception as e:
print(f"- Failed to clean log file: {e}") print(f"Failed to clean log file: {e}")
def _clean_prior_version_logs(self) -> None:
"""
Clean logs from old Patcher versions
If file is more than a week old, assume it's unused and delete it
"""
time_threshold = time.time() - 60 * 60 * 24 * 7
for file in self.log_filepath.parent.glob("OpenCore-Patcher*"):
if not file.is_file():
continue
if not file.name.endswith(".log"):
continue
if file.name == self.log_filename:
continue
if file.stat().st_mtime < time_threshold:
try:
file.unlink()
except Exception as e:
print(f"Failed to clean prior version log file: {e}")
def _fix_file_permission(self) -> None: def _fix_file_permission(self) -> None:
@@ -103,9 +130,13 @@ class InitializeLoggingSupport:
result = subprocess.run(["chmod", "777", self.log_filepath], capture_output=True) result = subprocess.run(["chmod", "777", self.log_filepath], capture_output=True)
if result.returncode != 0: if result.returncode != 0:
print(f"- Failed to fix log file permissions") logging.error(f"Failed to fix log file permissions")
if result.stdout:
logging.error("STDOUT:")
logging.error(result.stdout.decode("utf-8"))
if result.stderr: if result.stderr:
print(result.stderr.decode("utf-8")) logging.error("STDERR:")
logging.error(result.stderr.decode("utf-8"))
def _initialize_logging_configuration(self, log_to_file: bool = True) -> None: def _initialize_logging_configuration(self, log_to_file: bool = True) -> None:
@@ -122,7 +153,7 @@ class InitializeLoggingSupport:
logging.basicConfig( logging.basicConfig(
level=logging.NOTSET, level=logging.NOTSET,
format="%(asctime)s - %(filename)s (%(lineno)d): %(message)s", format="[%(asctime)s] [%(filename)-32s] [%(lineno)-4d]: %(message)s",
handlers=[ handlers=[
logging.StreamHandler(stream = sys.stdout), logging.StreamHandler(stream = sys.stdout),
logging.FileHandler(self.log_filepath) if log_to_file is True else logging.NullHandler() logging.FileHandler(self.log_filepath) if log_to_file is True else logging.NullHandler()
@@ -143,11 +174,26 @@ class InitializeLoggingSupport:
try: try:
self._initialize_logging_configuration() self._initialize_logging_configuration()
except Exception as e: except Exception as e:
print(f"- Failed to initialize logging framework: {e}") print(f"Failed to initialize logging framework: {e}")
print("- Retrying without logging to file...") print("Retrying without logging to file...")
self._initialize_logging_configuration(log_to_file=False) self._initialize_logging_configuration(log_to_file=False)
def _start_logging(self):
"""
Start logging, used as easily identifiable start point in logs
"""
str_msg = f"# OpenCore Legacy Patcher ({self.constants.patcher_version}) #"
str_len = len(str_msg)
logging.info('#' * str_len)
logging.info(str_msg)
logging.info('#' * str_len)
logging.info(f"Log file set to: {self.log_filepath}")
def _implement_custom_traceback_handler(self) -> None: def _implement_custom_traceback_handler(self) -> None:
""" """
Reroute traceback to logging module Reroute traceback to logging module
+3 -3
View File
@@ -53,7 +53,7 @@ class InstallerCreation():
bool: True if successful, False otherwise bool: True if successful, False otherwise
""" """
logging.info("- Extracting macOS installer from InstallAssistant.pkg\n This may take some time") logging.info("Extracting macOS installer from InstallAssistant.pkg\n This may take some time")
try: try:
applescript.AppleScript( applescript.AppleScript(
f'''do shell script "installer -pkg {Path(download_path)}/InstallAssistant.pkg -target /"''' f'''do shell script "installer -pkg {Path(download_path)}/InstallAssistant.pkg -target /"'''
@@ -62,11 +62,11 @@ class InstallerCreation():
" without altering line endings", " without altering line endings",
).run() ).run()
except Exception as e: except Exception as e:
logging.info("- Failed to install InstallAssistant") logging.info("Failed to install InstallAssistant")
logging.info(f" Error Code: {e}") logging.info(f" Error Code: {e}")
return False return False
logging.info("- InstallAssistant installed") logging.info("InstallAssistant installed")
return True return True
+2 -5
View File
@@ -32,8 +32,6 @@ class OpenCoreLegacyPatcher:
logging_handler.InitializeLoggingSupport(self.constants) logging_handler.InitializeLoggingSupport(self.constants)
logging.info(f"- Loading OpenCore Legacy Patcher v{self.constants.patcher_version}...")
self._generate_base_data() self._generate_base_data()
if utilities.check_cli_args() is None: if utilities.check_cli_args() is None:
@@ -98,18 +96,17 @@ class OpenCoreLegacyPatcher:
if utilities.check_cli_args() is None: if utilities.check_cli_args() is None:
self.constants.cli_mode = False self.constants.cli_mode = False
logging.info(f"- No arguments present, loading {'GUI' if self.constants.wxpython_variant is True else 'TUI'} mode")
return return
logging.info("- Detected arguments, switching to CLI mode") logging.info("Detected arguments, switching to CLI mode")
self.constants.gui_mode = True # Assumes no user interaction is required self.constants.gui_mode = True # Assumes no user interaction is required
ignore_args = ["--auto_patch", "--gui_patch", "--gui_unpatch", "--update_installed"] ignore_args = ["--auto_patch", "--gui_patch", "--gui_unpatch", "--update_installed"]
if not any(x in sys.argv for x in ignore_args): if not any(x in sys.argv for x in ignore_args):
self.constants.current_path = Path.cwd() self.constants.current_path = Path.cwd()
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"): if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
logging.info("- Rerouting payloads location")
self.constants.payload_path = sys._MEIPASS / Path("payloads") self.constants.payload_path = sys._MEIPASS / Path("payloads")
logging.info("Rerouting payloads location")
ignore_args = ignore_args.pop(0) ignore_args = ignore_args.pop(0)
if not any(x in sys.argv for x in ignore_args): if not any(x in sys.argv for x in ignore_args):
+17 -17
View File
@@ -204,10 +204,10 @@ class DownloadObject:
""" """
self.status = DownloadStatus.DOWNLOADING self.status = DownloadStatus.DOWNLOADING
logging.info(f"- Starting download: {self.filename}") logging.info(f"Starting download: {self.filename}")
if spawn_thread: if spawn_thread:
if self.active_thread: if self.active_thread:
logging.error("- Download already in progress") logging.error("Download already in progress")
return return
self.should_checksum = verify_checksum self.should_checksum = verify_checksum
self.active_thread = threading.Thread(target=self._download, args=(display_progress,)) self.active_thread = threading.Thread(target=self._download, args=(display_progress,))
@@ -267,8 +267,8 @@ class DownloadObject:
else: else:
raise Exception("Content-Length missing from headers") raise Exception("Content-Length missing from headers")
except Exception as e: except Exception as e:
logging.error(f"- Error determining file size {self.url}: {str(e)}") logging.error(f"Error determining file size {self.url}: {str(e)}")
logging.error("- Assuming file size is 0") logging.error("Assuming file size is 0")
self.total_file_size = 0.0 self.total_file_size = 0.0
@@ -295,17 +295,17 @@ class DownloadObject:
try: try:
if Path(path).exists(): if Path(path).exists():
logging.info(f"- Deleting existing file: {path}") logging.info(f"Deleting existing file: {path}")
Path(path).unlink() Path(path).unlink()
return True return True
if not Path(path).parent.exists(): if not Path(path).parent.exists():
logging.info(f"- Creating directory: {Path(path).parent}") logging.info(f"Creating directory: {Path(path).parent}")
Path(path).parent.mkdir(parents=True, exist_ok=True) Path(path).parent.mkdir(parents=True, exist_ok=True)
available_space = utilities.get_free_space(Path(path).parent) available_space = utilities.get_free_space(Path(path).parent)
if self.total_file_size > available_space: if self.total_file_size > available_space:
msg = f"- Not enough free space to download {self.filename}, need {utilities.human_fmt(self.total_file_size)}, have {utilities.human_fmt(available_space)}" msg = f"Not enough free space to download {self.filename}, need {utilities.human_fmt(self.total_file_size)}, have {utilities.human_fmt(available_space)}"
logging.error(msg) logging.error(msg)
raise Exception(msg) raise Exception(msg)
@@ -313,7 +313,7 @@ class DownloadObject:
self.error = True self.error = True
self.error_msg = str(e) self.error_msg = str(e)
self.status = DownloadStatus.ERROR self.status = DownloadStatus.ERROR
logging.error(f"- Error preparing working directory {path}: {self.error_msg}") logging.error(f"Error preparing working directory {path}: {self.error_msg}")
return False return False
return True return True
@@ -353,21 +353,21 @@ class DownloadObject:
if display_progress and i % 100: if display_progress and i % 100:
# Don't use logging here, as we'll be spamming the log file # Don't use logging here, as we'll be spamming the log file
if self.total_file_size == 0.0: if self.total_file_size == 0.0:
print(f"- Downloaded {utilities.human_fmt(self.downloaded_file_size)} of {self.filename}") print(f"Downloaded {utilities.human_fmt(self.downloaded_file_size)} of {self.filename}")
else: else:
print(f"- Downloaded {self.get_percent():.2f}% of {self.filename} ({utilities.human_fmt(self.get_speed())}/s) ({self.get_time_remaining():.2f} seconds remaining)") print(f"Downloaded {self.get_percent():.2f}% of {self.filename} ({utilities.human_fmt(self.get_speed())}/s) ({self.get_time_remaining():.2f} seconds remaining)")
self.download_complete = True self.download_complete = True
logging.info(f"- Download complete: {self.filename}") logging.info(f"Download complete: {self.filename}")
logging.info("- Stats:") logging.info("Stats:")
logging.info(f"- Downloaded size: {utilities.human_fmt(self.downloaded_file_size)}") logging.info(f"- Downloaded size: {utilities.human_fmt(self.downloaded_file_size)}")
logging.info(f"- Time elapsed: {(time.time() - self.start_time):.2f} seconds") logging.info(f"- Time elapsed: {(time.time() - self.start_time):.2f} seconds")
logging.info(f"- Speed: {utilities.human_fmt(self.downloaded_file_size / (time.time() - self.start_time))}/s") logging.info(f"- Speed: {utilities.human_fmt(self.downloaded_file_size / (time.time() - self.start_time))}/s")
logging.info(f"- Location: {self.filepath}") logging.info(f"- Location: {self.filepath}")
except Exception as e: except Exception as e:
self.error = True self.error = True
self.error_msg = str(e) self.error_msg = str(e)
self.status = DownloadStatus.ERROR self.status = DownloadStatus.ERROR
logging.error(f"- Error downloading {self.url}: {self.error_msg}") logging.error(f"Error downloading {self.url}: {self.error_msg}")
self.status = DownloadStatus.COMPLETE self.status = DownloadStatus.COMPLETE
utilities.enable_sleep_after_running() utilities.enable_sleep_after_running()
+7 -7
View File
@@ -28,10 +28,10 @@ class RoutePayloadDiskImage:
""" """
if self.constants.wxpython_variant is True and not self.constants.launcher_script: if self.constants.wxpython_variant is True and not self.constants.launcher_script:
logging.info("- Running in Binary GUI mode, switching to tmp directory") logging.info("Running in Binary GUI mode, switching to tmp directory")
self.temp_dir = tempfile.TemporaryDirectory() self.temp_dir = tempfile.TemporaryDirectory()
logging.info(f"- New payloads location: {self.temp_dir.name}") logging.info(f"New payloads location: {self.temp_dir.name}")
logging.info("- Creating payloads directory") logging.info("Creating payloads directory")
Path(self.temp_dir.name / Path("payloads")).mkdir(parents=True, exist_ok=True) Path(self.temp_dir.name / Path("payloads")).mkdir(parents=True, exist_ok=True)
self._unmount_active_dmgs(unmount_all_active=False) self._unmount_active_dmgs(unmount_all_active=False)
output = subprocess.run( output = subprocess.run(
@@ -45,12 +45,12 @@ class RoutePayloadDiskImage:
stdout=subprocess.PIPE, stderr=subprocess.STDOUT stdout=subprocess.PIPE, stderr=subprocess.STDOUT
) )
if output.returncode == 0: if output.returncode == 0:
logging.info("- Mounted payloads.dmg") logging.info("Mounted payloads.dmg")
self.constants.current_path = Path(self.temp_dir.name) self.constants.current_path = Path(self.temp_dir.name)
self.constants.payload_path = Path(self.temp_dir.name) / Path("payloads") self.constants.payload_path = Path(self.temp_dir.name) / Path("payloads")
atexit.register(self._unmount_active_dmgs, unmount_all_active=False) atexit.register(self._unmount_active_dmgs, unmount_all_active=False)
else: else:
logging.info("- Failed to mount payloads.dmg") logging.info("Failed to mount payloads.dmg")
logging.info(f"Output: {output.stdout.decode()}") logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}") logging.info(f"Return Code: {output.returncode}")
@@ -78,13 +78,13 @@ class RoutePayloadDiskImage:
# Check that only our personal payloads.dmg is unmounted # Check that only our personal payloads.dmg is unmounted
if "shadow-path" in image: if "shadow-path" in image:
if self.temp_dir.name in image["shadow-path"]: if self.temp_dir.name in image["shadow-path"]:
logging.info(f"- Unmounting personal {variant}") logging.info(f"Unmounting personal {variant}")
subprocess.run( subprocess.run(
["hdiutil", "detach", image["system-entities"][0]["dev-entry"], "-force"], ["hdiutil", "detach", image["system-entities"][0]["dev-entry"], "-force"],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT stdout=subprocess.PIPE, stderr=subprocess.STDOUT
) )
else: else:
logging.info(f"- Unmounting {variant} at: {image['system-entities'][0]['dev-entry']}") logging.info(f"Unmounting {variant} at: {image['system-entities'][0]['dev-entry']}")
subprocess.run( subprocess.run(
["hdiutil", "detach", image["system-entities"][0]["dev-entry"], "-force"], ["hdiutil", "detach", image["system-entities"][0]["dev-entry"], "-force"],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT stdout=subprocess.PIPE, stderr=subprocess.STDOUT
+1 -1
View File
@@ -92,7 +92,7 @@ class DetectRootPatch:
non_metal_os = os_data.os_data.catalina non_metal_os = os_data.os_data.catalina
for i, gpu in enumerate(gpus): for i, gpu in enumerate(gpus):
if gpu.class_code and gpu.class_code != 0xFFFFFFFF: if gpu.class_code and gpu.class_code != 0xFFFFFFFF:
logging.info(f"- Found GPU ({i}): {utilities.friendly_hex(gpu.vendor_id)}:{utilities.friendly_hex(gpu.device_id)}") logging.info(f"Found GPU ({i}): {utilities.friendly_hex(gpu.vendor_id)}:{utilities.friendly_hex(gpu.device_id)}")
if gpu.arch in [device_probe.NVIDIA.Archs.Tesla] and self.constants.force_nv_web is False: if gpu.arch in [device_probe.NVIDIA.Archs.Tesla] and self.constants.force_nv_web is False:
if self.constants.detected_os > non_metal_os: if self.constants.detected_os > non_metal_os:
self.nvidia_tesla = True self.nvidia_tesla = True
+3 -3
View File
@@ -40,7 +40,7 @@ class GenerateRootPatchSets:
utilities.cls() utilities.cls()
logging.info("- The following patches will be applied:") logging.info("The following patches will be applied:")
if self.hardware_details["Graphics: Intel Ironlake"] is True: if self.hardware_details["Graphics: Intel Ironlake"] is True:
required_patches.update({"Non-Metal Common": all_hardware_patchset["Graphics"]["Non-Metal Common"]}) required_patches.update({"Non-Metal Common": all_hardware_patchset["Graphics"]["Non-Metal Common"]})
@@ -184,8 +184,8 @@ class GenerateRootPatchSets:
del(required_patches[patch_name]) del(required_patches[patch_name])
else: else:
if required_patches[patch_name]["Display Name"]: if required_patches[patch_name]["Display Name"]:
logging.info(f" - {required_patches[patch_name]['Display Name']}") logging.info(f"- {required_patches[patch_name]['Display Name']}")
else: else:
logging.info(" - No patch sets found for booted model") logging.info("- No patch sets found for booted model")
return required_patches return required_patches
+11 -11
View File
@@ -42,10 +42,10 @@ class SysPatchHelpers:
if self.constants.computer.reported_board_id in self.constants.sandy_board_id_stock: if self.constants.computer.reported_board_id in self.constants.sandy_board_id_stock:
return return
logging.info(f"- Found unsupported Board ID {self.constants.computer.reported_board_id}, performing AppleIntelSNBGraphicsFB bin patching") logging.info(f"Found unsupported Board ID {self.constants.computer.reported_board_id}, performing AppleIntelSNBGraphicsFB bin patching")
board_to_patch = generate_smbios.determine_best_board_id_for_sandy(self.constants.computer.reported_board_id, self.constants.computer.gpus) board_to_patch = generate_smbios.determine_best_board_id_for_sandy(self.constants.computer.reported_board_id, self.constants.computer.gpus)
logging.info(f"- Replacing {board_to_patch} with {self.constants.computer.reported_board_id}") logging.info(f"Replacing {board_to_patch} with {self.constants.computer.reported_board_id}")
board_to_patch_hex = bytes.fromhex(board_to_patch.encode('utf-8').hex()) board_to_patch_hex = bytes.fromhex(board_to_patch.encode('utf-8').hex())
reported_board_hex = bytes.fromhex(self.constants.computer.reported_board_id.encode('utf-8').hex()) reported_board_hex = bytes.fromhex(self.constants.computer.reported_board_id.encode('utf-8').hex())
@@ -54,12 +54,12 @@ class SysPatchHelpers:
# Pad the reported Board ID with zeros to match the length of the board to patch # Pad the reported Board ID with zeros to match the length of the board to patch
reported_board_hex = reported_board_hex + bytes(len(board_to_patch_hex) - len(reported_board_hex)) reported_board_hex = reported_board_hex + bytes(len(board_to_patch_hex) - len(reported_board_hex))
elif len(board_to_patch_hex) < len(reported_board_hex): elif len(board_to_patch_hex) < len(reported_board_hex):
logging.info(f"- Error: Board ID {self.constants.computer.reported_board_id} is longer than {board_to_patch}") logging.info(f"Error: Board ID {self.constants.computer.reported_board_id} is longer than {board_to_patch}")
raise Exception("Host's Board ID is longer than the kext's Board ID, cannot patch!!!") raise Exception("Host's Board ID is longer than the kext's Board ID, cannot patch!!!")
path = source_files_path + "/10.13.6/System/Library/Extensions/AppleIntelSNBGraphicsFB.kext/Contents/MacOS/AppleIntelSNBGraphicsFB" path = source_files_path + "/10.13.6/System/Library/Extensions/AppleIntelSNBGraphicsFB.kext/Contents/MacOS/AppleIntelSNBGraphicsFB"
if not Path(path).exists(): if not Path(path).exists():
logging.info(f"- Error: Could not find {path}") logging.info(f"Error: Could not find {path}")
raise Exception("Failed to find AppleIntelSNBGraphicsFB.kext, cannot patch!!!") raise Exception("Failed to find AppleIntelSNBGraphicsFB.kext, cannot patch!!!")
with open(path, 'rb') as f: with open(path, 'rb') as f:
@@ -128,7 +128,7 @@ class SysPatchHelpers:
if self.constants.detected_os < os_data.os_data.ventura: if self.constants.detected_os < os_data.os_data.ventura:
return return
logging.info("- Disabling WindowServer Caching") logging.info("Disabling WindowServer Caching")
# Invoke via 'bash -c' to resolve pathing # Invoke via 'bash -c' to resolve pathing
utilities.elevated(["bash", "-c", "rm -rf /private/var/folders/*/*/*/WindowServer/com.apple.WindowServer"]) utilities.elevated(["bash", "-c", "rm -rf /private/var/folders/*/*/*/WindowServer/com.apple.WindowServer"])
# Disable writing to WindowServer folder # Disable writing to WindowServer folder
@@ -150,12 +150,12 @@ class SysPatchHelpers:
if self.constants.detected_os < os_data.os_data.ventura: if self.constants.detected_os < os_data.os_data.ventura:
return return
logging.info("- Parsing Notification Centre Widgets") logging.info("Parsing Notification Centre Widgets")
file_path = "~/Library/Containers/com.apple.notificationcenterui/Data/Library/Preferences/com.apple.notificationcenterui.plist" file_path = "~/Library/Containers/com.apple.notificationcenterui/Data/Library/Preferences/com.apple.notificationcenterui.plist"
file_path = Path(file_path).expanduser() file_path = Path(file_path).expanduser()
if not file_path.exists(): if not file_path.exists():
logging.info(" - Defaults file not found, skipping") logging.info("- Defaults file not found, skipping")
return return
did_find = False did_find = False
@@ -178,7 +178,7 @@ class SysPatchHelpers:
continue continue
if not b'com.apple.news' in sub_data[sub_entry][2]: if not b'com.apple.news' in sub_data[sub_entry][2]:
continue continue
logging.info(f" - Found News Widget to remove: {sub_data[sub_entry][2].decode('ascii')}") logging.info(f"- Found News Widget to remove: {sub_data[sub_entry][2].decode('ascii')}")
data["widgets"]["instances"].remove(widget) data["widgets"]["instances"].remove(widget)
did_find = True did_find = True
@@ -210,10 +210,10 @@ class SysPatchHelpers:
if self.constants.detected_os < os_data.os_data.big_sur: if self.constants.detected_os < os_data.os_data.big_sur:
return return
logging.info("- Installing Kernel Collection syncing utility") logging.info("Installing Kernel Collection syncing utility")
result = utilities.elevated([self.constants.rsrrepair_userspace_path, "--install"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = utilities.elevated([self.constants.rsrrepair_userspace_path, "--install"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info(f" - Failed to install RSRRepair: {result.stdout.decode()}") logging.info(f"- Failed to install RSRRepair: {result.stdout.decode()}")
def patch_gpu_compiler_libraries(self, mount_point: Union[str, Path]): def patch_gpu_compiler_libraries(self, mount_point: Union[str, Path]):
@@ -262,7 +262,7 @@ class SysPatchHelpers:
if not file.name.startswith("31001."): if not file.name.startswith("31001."):
continue continue
logging.info(f"- Merging GPUCompiler.framework libraries to match binary") logging.info(f"Merging GPUCompiler.framework libraries to match binary")
src_dir = f"{LIBRARY_DIR}/{file.name}" src_dir = f"{LIBRARY_DIR}/{file.name}"
if not Path(f"{DEST_DIR}/lib").exists(): if not Path(f"{DEST_DIR}/lib").exists():
+1 -1
View File
@@ -116,7 +116,7 @@ class CheckBinaryUpdates:
return None return None
for asset in data_set["assets"]: for asset in data_set["assets"]:
logging.info(f"- Found asset: {asset['name']}") logging.info(f"Found asset: {asset['name']}")
if self._determine_remote_type(asset["name"]) == self._determine_local_build_type(): if self._determine_remote_type(asset["name"]) == self._determine_local_build_type():
available_binaries.update({ available_binaries.update({
asset['name']: { asset['name']: {
+3 -3
View File
@@ -158,7 +158,7 @@ sleep_process = None
def disable_sleep_while_running(): def disable_sleep_while_running():
global sleep_process global sleep_process
logging.info("- Disabling Idle Sleep") logging.info("Disabling Idle Sleep")
if sleep_process is None: if sleep_process is None:
# If sleep_process is active, we'll just keep it running # If sleep_process is active, we'll just keep it running
sleep_process = subprocess.Popen(["caffeinate", "-d", "-i", "-s"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) sleep_process = subprocess.Popen(["caffeinate", "-d", "-i", "-s"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -168,7 +168,7 @@ def disable_sleep_while_running():
def enable_sleep_after_running(): def enable_sleep_after_running():
global sleep_process global sleep_process
if sleep_process: if sleep_process:
logging.info("- Re-enabling Idle Sleep") logging.info("Re-enabling Idle Sleep")
sleep_process.kill() sleep_process.kill()
sleep_process = None sleep_process = None
@@ -516,7 +516,7 @@ def block_os_updaters():
for bad_process in bad_processes: for bad_process in bad_processes:
if bad_process in current_process: if bad_process in current_process:
if pid != "": if pid != "":
logging.info(f"- Killing Process: {pid} - {current_process.split('/')[-1]}") logging.info(f"Killing Process: {pid} - {current_process.split('/')[-1]}")
subprocess.run(["kill", "-9", pid]) subprocess.run(["kill", "-9", pid])
break break
+4 -4
View File
@@ -120,7 +120,7 @@ class PatcherValidation:
logging.info(f"File not found: {source_file}") logging.info(f"File not found: {source_file}")
raise Exception(f"Failed to find {source_file}") raise Exception(f"Failed to find {source_file}")
logging.info(f"- Validating against Darwin {major_kernel}.{minor_kernel}") logging.info(f"Validating against Darwin {major_kernel}.{minor_kernel}")
if not sys_patch_helpers.SysPatchHelpers(self.constants).generate_patchset_plist(patchset, f"OpenCore-Legacy-Patcher-{major_kernel}.{minor_kernel}.plist", None): if not sys_patch_helpers.SysPatchHelpers(self.constants).generate_patchset_plist(patchset, f"OpenCore-Legacy-Patcher-{major_kernel}.{minor_kernel}.plist", None):
raise Exception("Failed to generate patchset plist") raise Exception("Failed to generate patchset plist")
@@ -153,13 +153,13 @@ class PatcherValidation:
) )
if output.returncode != 0: if output.returncode != 0:
logging.info("- Failed to mount Universal-Binaries.dmg") logging.info("Failed to mount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}") logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}") logging.info(f"Return Code: {output.returncode}")
raise Exception("Failed to mount Universal-Binaries.dmg") raise Exception("Failed to mount Universal-Binaries.dmg")
logging.info("- Mounted Universal-Binaries.dmg") logging.info("Mounted Universal-Binaries.dmg")
for supported_os in [os_data.os_data.big_sur, os_data.os_data.monterey, os_data.os_data.ventura]: for supported_os in [os_data.os_data.big_sur, os_data.os_data.monterey, os_data.os_data.ventura]:
@@ -179,7 +179,7 @@ class PatcherValidation:
) )
if output.returncode != 0: if output.returncode != 0:
logging.info("- Failed to unmount Universal-Binaries.dmg") logging.info("Failed to unmount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}") logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}") logging.info(f"Return Code: {output.returncode}")
+2
View File
@@ -2,6 +2,7 @@
import wx import wx
import wx.adv import wx.adv
import logging
from resources import constants from resources import constants
@@ -12,6 +13,7 @@ class AboutFrame(wx.Frame):
if wx.FindWindowByName("About"): if wx.FindWindowByName("About"):
return return
logging.info("Generating About frame")
super(AboutFrame, self).__init__(None, title="About", size=(350, 350), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)) super(AboutFrame, self).__init__(None, title="About", size=(350, 350), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
self.Centre() self.Centre()
+2 -1
View File
@@ -19,6 +19,7 @@ class BuildFrame(wx.Frame):
Uses a Modal Dialog for smoother transition from other frames Uses a Modal Dialog for smoother transition from other frames
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None) -> None: def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None) -> None:
logging.info("Initializing Build Frame")
super(BuildFrame, self).__init__(parent, title=title, size=(350, 200), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)) super(BuildFrame, self).__init__(parent, title=title, size=(350, 200), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
gui_support.GenerateMenubar(self, global_constants).generate() gui_support.GenerateMenubar(self, global_constants).generate()
@@ -121,7 +122,7 @@ class BuildFrame(wx.Frame):
try: try:
build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants) build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants)
except: except:
logging.error("- An internal error occurred while building:\n") logging.error("An internal error occurred while building:\n")
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logger.removeHandler(logger.handlers[2]) logger.removeHandler(logger.handlers[2])
+3
View File
@@ -1,5 +1,6 @@
# Generate UI for downloading files # Generate UI for downloading files
import wx import wx
import logging
from resources import ( from resources import (
constants, constants,
@@ -13,6 +14,7 @@ class DownloadFrame(wx.Frame):
Update provided frame with download stats Update provided frame with download stats
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, download_obj: network_handler.DownloadObject, item_name: str) -> None: def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, download_obj: network_handler.DownloadObject, item_name: str) -> None:
logging.info("Initializing Download Frame")
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
self.title: str = title self.title: str = title
self.parent: wx.Frame = parent self.parent: wx.Frame = parent
@@ -91,6 +93,7 @@ class DownloadFrame(wx.Frame):
Terminate download Terminate download
""" """
if wx.MessageBox("Are you sure you want to cancel the download?", "Cancel Download", wx.YES_NO | wx.ICON_QUESTION | wx.NO_DEFAULT) == wx.YES: if wx.MessageBox("Are you sure you want to cancel the download?", "Cancel Download", wx.YES_NO | wx.ICON_QUESTION | wx.NO_DEFAULT) == wx.YES:
logging.info("User cancelled download")
self.user_cancelled = True self.user_cancelled = True
self.download_obj.stop() self.download_obj.stop()
+2 -2
View File
@@ -52,7 +52,7 @@ class EntryPoint:
entry = gui_sys_patch.SysPatchFrame entry = gui_sys_patch.SysPatchFrame
patches = sys_patch_detect.DetectRootPatch(self.constants.computer.real_model, self.constants).detect_patch_set() patches = sys_patch_detect.DetectRootPatch(self.constants.computer.real_model, self.constants).detect_patch_set()
logging.info(f"- Loading wxPython GUI: {entry.__name__}") logging.info(f"Entry point set: {entry.__name__}")
self.frame: wx.Frame = entry( self.frame: wx.Frame = entry(
None, None,
title=f"{self.constants.patcher_name} ({self.constants.patcher_version})", title=f"{self.constants.patcher_name} ({self.constants.patcher_version})",
@@ -79,7 +79,7 @@ class EntryPoint:
if not self.frame: if not self.frame:
return return
logging.info("- Cleaning up wxPython GUI") logging.info("Cleaning up wxPython GUI")
self.frame.SetTransparent(0) self.frame.SetTransparent(0)
wx.Yield() wx.Yield()
+2 -1
View File
@@ -1,5 +1,6 @@
# Generate UI for help menu # Generate UI for help menu
import wx import wx
import logging
import webbrowser import webbrowser
from resources import constants from resources import constants
@@ -10,7 +11,7 @@ class HelpFrame(wx.Frame):
Append to main menu through a modal dialog Append to main menu through a modal dialog
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None) -> None: def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None) -> None:
logging.info("Initializing Help Frame")
self.dialog = wx.Dialog(parent, title=title, size=(300, 200)) self.dialog = wx.Dialog(parent, title=title, size=(300, 200))
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
+6 -3
View File
@@ -13,6 +13,7 @@ class InstallOCFrame(wx.Frame):
Create a frame for installing OpenCore to disk Create a frame for installing OpenCore to disk
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
logging.info("Initializing Install OpenCore Frame")
super(InstallOCFrame, self).__init__(parent, title=title, size=(300, 120), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)) super(InstallOCFrame, self).__init__(parent, title=title, size=(300, 120), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
gui_support.GenerateMenubar(self, global_constants).generate() gui_support.GenerateMenubar(self, global_constants).generate()
@@ -124,13 +125,14 @@ class InstallOCFrame(wx.Frame):
# disk6s1 -> disk6 # disk6s1 -> disk6
disk_root = self.constants.booted_oc_disk.strip("disk") disk_root = self.constants.booted_oc_disk.strip("disk")
disk_root = "disk" + disk_root.split("s")[0] disk_root = "disk" + disk_root.split("s")[0]
logging.info(f"- Checking if booted disk is present: {disk_root}") logging.info(f"Checking if booted disk is present: {disk_root}")
# Add buttons for each disk # Add buttons for each disk
items = len(self.available_disks) items = len(self.available_disks)
longest_label = max((len(self.available_disks[disk]['disk']) + len(self.available_disks[disk]['name']) + len(str(self.available_disks[disk]['size']))) for disk in self.available_disks) longest_label = max((len(self.available_disks[disk]['disk']) + len(self.available_disks[disk]['name']) + len(str(self.available_disks[disk]['size']))) for disk in self.available_disks)
longest_label = longest_label * 9 longest_label = longest_label * 9
spacer = 0 spacer = 0
logging.info("Available disks:")
for disk in self.available_disks: for disk in self.available_disks:
# Create a button for each disk # Create a button for each disk
logging.info(f"- {self.available_disks[disk]['disk']} - {self.available_disks[disk]['name']} - {self.available_disks[disk]['size']}") logging.info(f"- {self.available_disks[disk]['disk']} - {self.available_disks[disk]['name']} - {self.available_disks[disk]['size']}")
@@ -195,6 +197,7 @@ class InstallOCFrame(wx.Frame):
items = len(partitions) items = len(partitions)
longest_label = max((len(partitions[partition]['partition']) + len(partitions[partition]['name']) + len(str(partitions[partition]['size']))) for partition in partitions) longest_label = max((len(partitions[partition]['partition']) + len(partitions[partition]['name']) + len(str(partitions[partition]['size']))) for partition in partitions)
longest_label = longest_label * 10 longest_label = longest_label * 10
logging.info(f"Available partitions for {disk}:")
for partition in partitions: for partition in partitions:
logging.info(f"- {partitions[partition]['partition']} - {partitions[partition]['name']} - {partitions[partition]['size']}") logging.info(f"- {partitions[partition]['partition']} - {partitions[partition]['name']} - {partitions[partition]['size']}")
disk_button = wx.Button(dialog, label=f"{partitions[partition]['partition']} - {partitions[partition]['name']} - {partitions[partition]['size']}", size=(longest_label,30), pos=(-1, text_label.GetPosition()[1] + text_label.GetSize()[1] + 5)) disk_button = wx.Button(dialog, label=f"{partitions[partition]['partition']} - {partitions[partition]['name']} - {partitions[partition]['size']}", size=(longest_label,30), pos=(-1, text_label.GetPosition()[1] + text_label.GetSize()[1] + 5))
@@ -306,14 +309,14 @@ class InstallOCFrame(wx.Frame):
""" """
Install OpenCore to disk Install OpenCore to disk
""" """
logging.info(f"- Installing OpenCore to {partition}") logging.info(f"Installing OpenCore to {partition}")
logger = logging.getLogger() logger = logging.getLogger()
logger.addHandler(gui_support.ThreadHandler(self.text_box)) logger.addHandler(gui_support.ThreadHandler(self.text_box))
try: try:
self.result = install.tui_disk_installation(self.constants).install_opencore(partition) self.result = install.tui_disk_installation(self.constants).install_opencore(partition)
except: except:
logging.error("- An internal error occurred while installing:\n") logging.error("An internal error occurred while installing:\n")
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logger.removeHandler(logger.handlers[2]) logger.removeHandler(logger.handlers[2])
@@ -28,7 +28,7 @@ class macOSInstallerDownloadFrame(wx.Frame):
Note: Flashing installers is passed to gui_macos_installer_flash.py Note: Flashing installers is passed to gui_macos_installer_flash.py
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
logging.info("Initializing macOS Installer Download Frame")
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
self.title: str = title self.title: str = title
self.parent: wx.Frame = parent self.parent: wx.Frame = parent
+26 -25
View File
@@ -22,6 +22,7 @@ from data import os_data
class macOSInstallerFlashFrame(wx.Frame): class macOSInstallerFlashFrame(wx.Frame):
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
logging.info("Initializing macOS Installer Flash Frame")
super(macOSInstallerFlashFrame, self).__init__(parent, title=title, size=(350, 200), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)) super(macOSInstallerFlashFrame, self).__init__(parent, title=title, size=(350, 200), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
gui_support.GenerateMenubar(self, global_constants).generate() gui_support.GenerateMenubar(self, global_constants).generate()
@@ -354,14 +355,14 @@ class macOSInstallerFlashFrame(wx.Frame):
def _flash_installer(self, disk) -> bool: def _flash_installer(self, disk) -> bool:
utilities.disable_sleep_while_running() utilities.disable_sleep_while_running()
logging.info("- Creating macOS installer") logging.info("Creating macOS installer")
thread = threading.Thread(target=self._auto_package_handler) thread = threading.Thread(target=self._auto_package_handler)
thread.start() thread.start()
# print contents of installer.sh # print contents of installer.sh
with open(self.constants.installer_sh_path, "r") as f: with open(self.constants.installer_sh_path, "r") as f:
logging.info(f"- installer.sh contents:\n{f.read()}") logging.info(f"installer.sh contents:\n{f.read()}")
args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path] args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path]
result = subprocess.run(args, capture_output=True, text=True) result = subprocess.run(args, capture_output=True, text=True)
@@ -369,17 +370,17 @@ class macOSInstallerFlashFrame(wx.Frame):
error = result.stderr if result.stderr else "" error = result.stderr if result.stderr else ""
if "Install media now available at" not in output: if "Install media now available at" not in output:
logging.info("- Failed to create macOS installer") logging.info("Failed to create macOS installer")
popup = wx.MessageDialog(self, f"Failed to create macOS installer\n\nOutput: {output}\n\nError: {error}", "Error", wx.OK | wx.ICON_ERROR) popup = wx.MessageDialog(self, f"Failed to create macOS installer\n\nOutput: {output}\n\nError: {error}", "Error", wx.OK | wx.ICON_ERROR)
popup.ShowModal() popup.ShowModal()
return False return False
logging.info("- Successfully created macOS installer") logging.info("Successfully created macOS installer")
while thread.is_alive(): while thread.is_alive():
# wait for download_thread to finish # wait for download_thread to finish
# though highly unlikely this thread is still alive (flashing an Installer will take a while) # though highly unlikely this thread is still alive (flashing an Installer will take a while)
time.sleep(0.1) time.sleep(0.1)
logging.info("- Installing Root Patcher to drive") logging.info("Installing Root Patcher to drive")
self._install_installer_pkg(disk) self._install_installer_pkg(disk)
utilities.enable_sleep_after_running() utilities.enable_sleep_after_running()
@@ -396,7 +397,7 @@ class macOSInstallerFlashFrame(wx.Frame):
""" """
link = self.constants.installer_pkg_url link = self.constants.installer_pkg_url
if network_handler.NetworkUtilities(link).validate_link() is False: if network_handler.NetworkUtilities(link).validate_link() is False:
logging.info("- Stock Install.pkg is missing on Github, falling back to Nightly") logging.info("Stock Install.pkg is missing on Github, falling back to Nightly")
link = self.constants.installer_pkg_url_nightly link = self.constants.installer_pkg_url_nightly
if link.endswith(".zip"): if link.endswith(".zip"):
@@ -408,7 +409,7 @@ class macOSInstallerFlashFrame(wx.Frame):
autopkg_download.download(spawn_thread=False) autopkg_download.download(spawn_thread=False)
if autopkg_download.download_complete is False: if autopkg_download.download_complete is False:
logging.warning("- Failed to download Install.pkg") logging.warning("Failed to download Install.pkg")
logging.warning(autopkg_download.error_msg) logging.warning(autopkg_download.error_msg)
return return
@@ -434,7 +435,7 @@ class macOSInstallerFlashFrame(wx.Frame):
os_version = plistlib.load(Path(path + "/System/Library/CoreServices/SystemVersion.plist").open("rb")) 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"]) kernel_version = os_data.os_conversion.os_to_kernel(os_version["ProductVersion"])
if int(kernel_version) < os_data.os_data.big_sur: if int(kernel_version) < os_data.os_data.big_sur:
logging.info("- Installer unsupported, requires Big Sur or newer") logging.info("Installer unsupported, requires Big Sur or newer")
return return
subprocess.run(["mkdir", "-p", f"{path}/Library/Packages/"]) subprocess.run(["mkdir", "-p", f"{path}/Library/Packages/"])
@@ -460,29 +461,29 @@ class macOSInstallerFlashFrame(wx.Frame):
if kdk_pkg_path.exists(): if kdk_pkg_path.exists():
kdk_pkg_path.unlink() kdk_pkg_path.unlink()
logging.info("- Initiating KDK download") logging.info("Initiating KDK download")
logging.info(f" - Build: {build}") logging.info(f"- Build: {build}")
logging.info(f" - Version: {version}") logging.info(f"- Version: {version}")
logging.info(f" - Working Directory: {download_dir}") logging.info(f"- Working Directory: {download_dir}")
kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, build, version, ignore_installed=True) kdk_obj = kdk_handler.KernelDebugKitObject(self.constants, build, version, ignore_installed=True)
if kdk_obj.success is False: if kdk_obj.success is False:
logging.info("- Failed to retrieve KDK") logging.info("Failed to retrieve KDK")
logging.info(kdk_obj.error_msg) logging.info(kdk_obj.error_msg)
return return
kdk_download_obj = kdk_obj.retrieve_download(override_path=kdk_dmg_path) kdk_download_obj = kdk_obj.retrieve_download(override_path=kdk_dmg_path)
if kdk_download_obj is None: if kdk_download_obj is None:
logging.info("- Failed to retrieve KDK") logging.info("Failed to retrieve KDK")
logging.info(kdk_obj.error_msg) logging.info(kdk_obj.error_msg)
# Check remaining disk space before downloading # Check remaining disk space before downloading
space = utilities.get_free_space(download_dir) space = utilities.get_free_space(download_dir)
if space < (kdk_obj.kdk_url_expected_size * 2): if space < (kdk_obj.kdk_url_expected_size * 2):
logging.info("- Not enough disk space to download and install KDK") logging.info("Not enough disk space to download and install KDK")
logging.info(f"- Attempting to download locally first") logging.info(f"Attempting to download locally first")
if space < kdk_obj.kdk_url_expected_size: if space < kdk_obj.kdk_url_expected_size:
logging.info("- Not enough disk space to install KDK, skipping") logging.info("Not enough disk space to install KDK, skipping")
return return
# Ideally we'd download the KDK onto the disk to display progress in the UI # 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 # However we'll just download to our temp directory and move it to the target disk
@@ -490,34 +491,34 @@ class macOSInstallerFlashFrame(wx.Frame):
kdk_download_obj.download(spawn_thread=False) kdk_download_obj.download(spawn_thread=False)
if kdk_download_obj.download_complete is False: if kdk_download_obj.download_complete is False:
logging.info("- Failed to download KDK") logging.info("Failed to download KDK")
logging.info(kdk_download_obj.error_msg) logging.info(kdk_download_obj.error_msg)
return return
if not kdk_dmg_path.exists(): if not kdk_dmg_path.exists():
logging.info(f"- KDK missing: {kdk_dmg_path}") logging.info(f"KDK missing: {kdk_dmg_path}")
return return
# Now that we have a KDK, extract it to get the pkg # Now that we have a KDK, extract it to get the pkg
with tempfile.TemporaryDirectory() as mount_point: with tempfile.TemporaryDirectory() as mount_point:
logging.info("- Mounting KDK") logging.info("Mounting KDK")
result = subprocess.run(["hdiutil", "attach", kdk_dmg_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = subprocess.run(["hdiutil", "attach", kdk_dmg_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Failed to mount KDK") logging.info("Failed to mount KDK")
logging.info(result.stdout.decode("utf-8")) logging.info(result.stdout.decode("utf-8"))
return return
logging.info("- Copying KDK") logging.info("Copying KDK")
subprocess.run(["cp", "-r", f"{mount_point}/KernelDebugKit.pkg", kdk_pkg_path]) subprocess.run(["cp", "-r", f"{mount_point}/KernelDebugKit.pkg", kdk_pkg_path])
logging.info("- Unmounting KDK") logging.info("Unmounting KDK")
result = subprocess.run(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = subprocess.run(["hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0: if result.returncode != 0:
logging.info("- Failed to unmount KDK") logging.info("Failed to unmount KDK")
logging.info(result.stdout.decode("utf-8")) logging.info(result.stdout.decode("utf-8"))
return return
logging.info("- Removing KDK Disk Image") logging.info("Removing KDK Disk Image")
kdk_dmg_path.unlink() kdk_dmg_path.unlink()
def _validate_installer_pkg(self, disk: str) -> bool: def _validate_installer_pkg(self, disk: str) -> bool:
+3 -2
View File
@@ -24,6 +24,7 @@ from data import os_data
class MainFrame(wx.Frame): class MainFrame(wx.Frame):
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
logging.info("Initializing Main Menu Frame")
super(MainFrame, self).__init__(parent, title=title, size=(600, 400), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)) super(MainFrame, self).__init__(parent, title=title, size=(600, 400), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
gui_support.GenerateMenubar(self, global_constants).generate() gui_support.GenerateMenubar(self, global_constants).generate()
@@ -213,11 +214,11 @@ class MainFrame(wx.Frame):
pop_up.ShowModal() pop_up.ShowModal()
if pop_up.GetReturnCode() != wx.ID_YES: if pop_up.GetReturnCode() != wx.ID_YES:
print("- Skipping OpenCore and root volume patch update...") print("Skipping OpenCore and root volume patch update...")
return return
print("- Updating OpenCore and root volume patches...") print("Updating OpenCore and root volume patches...")
self.constants.update_stage = gui_support.AutoUpdateStages.CHECKING self.constants.update_stage = gui_support.AutoUpdateStages.CHECKING
self.Hide() self.Hide()
pos = self.GetPosition() pos = self.GetPosition()
+3 -1
View File
@@ -32,6 +32,7 @@ class SettingsFrame(wx.Frame):
Modal-based Settings Frame Modal-based Settings Frame
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
logging.info("Initializing Settings Frame")
self.constants: constants.Constants = global_constants self.constants: constants.Constants = global_constants
self.title: str = title self.title: str = title
self.parent: wx.Frame = parent self.parent: wx.Frame = parent
@@ -1257,11 +1258,12 @@ Hardware Information:
def on_export_constants(self, event: wx.Event) -> None: def on_export_constants(self, event: wx.Event) -> None:
# Throw pop up to get save location # Throw pop up to get save location
with wx.FileDialog(self.parent, "Save Constants File", wildcard="JSON files (*.txt)|*.txt", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog: with wx.FileDialog(self.parent, "Save Constants File", wildcard="JSON files (*.txt)|*.txt", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, defaultFile=f"constants-{self.constants.patcher_version}.txt") as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL: if fileDialog.ShowModal() == wx.ID_CANCEL:
return return
# Save the current contents in the file # Save the current contents in the file
pathname = fileDialog.GetPath() pathname = fileDialog.GetPath()
logging.info(f"Saving constants to {pathname}")
with open(pathname, 'w') as file: with open(pathname, 'w') as file:
file.write(pprint.pformat(vars(self.constants), indent=4)) file.write(pprint.pformat(vars(self.constants), indent=4))
+1 -1
View File
@@ -289,7 +289,7 @@ class RelaunchApplicationAsRoot:
wx.Yield() wx.Yield()
logging.info(f"- Relaunching as root with command: {program_arguments}") logging.info(f"Relaunching as root with command: {program_arguments}")
subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True: while True:
+11 -6
View File
@@ -33,6 +33,7 @@ class SysPatchFrame(wx.Frame):
Uses a Modal Dialog for smoother transition from other frames Uses a Modal Dialog for smoother transition from other frames
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None, patches: dict = {}): def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None, patches: dict = {}):
logging.info("Initializing Root Patching Frame")
self.frame = parent self.frame = parent
self.initiated_with_parent = False self.initiated_with_parent = False
if not self.frame and patches == {}: if not self.frame and patches == {}:
@@ -167,7 +168,7 @@ class SysPatchFrame(wx.Frame):
can_unpatch: bool = patches["Validation: Unpatching Possible"] can_unpatch: bool = 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): if not any(not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True for patch in patches):
logging.info("- No applicable patches available") logging.info("No applicable patches available")
patches = [] patches = []
# Check if OCLP has already applied the same patches # Check if OCLP has already applied the same patches
@@ -198,10 +199,11 @@ class SysPatchFrame(wx.Frame):
anchor.Centre(wx.HORIZONTAL) anchor.Centre(wx.HORIZONTAL)
anchor.Hide() anchor.Hide()
logging.info("Available patches:")
for patch in patches: for patch in patches:
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True): if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
i = i + 20 i = i + 20
logging.info(f"- Adding patch: {patch} - {patches[patch]}") logging.info(f"- {patch}")
patch_label = wx.StaticText(frame, label=f"- {patch}", pos=(anchor.GetPosition()[0], available_label.GetPosition()[1] + i)) patch_label = wx.StaticText(frame, label=f"- {patch}", pos=(anchor.GetPosition()[0], available_label.GetPosition()[1] + i))
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont")) patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
@@ -346,9 +348,10 @@ class SysPatchFrame(wx.Frame):
# Labels # Labels
i = 0 i = 0
logging.info("Available patches:")
for patch in patches: for patch in patches:
if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True): if (not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True):
logging.info(f"- Adding patch: {patch} - {patches[patch]}") logging.info(f"- {patch}")
patch_label = wx.StaticText(dialog, label=f"- {patch}", pos=(anchor.GetPosition()[0], label.GetPosition()[1] + 20 + i)) patch_label = wx.StaticText(dialog, label=f"- {patch}", pos=(anchor.GetPosition()[0], label.GetPosition()[1] + 20 + i))
patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont")) patch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
i = i + 20 i = i + 20
@@ -422,7 +425,7 @@ class SysPatchFrame(wx.Frame):
try: try:
sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_patch() sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_patch()
except: except:
logging.error("- An internal error occurred while running the Root Patcher:\n") logging.error("An internal error occurred while running the Root Patcher:\n")
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logger.removeHandler(logger.handlers[2]) logger.removeHandler(logger.handlers[2])
@@ -454,7 +457,7 @@ class SysPatchFrame(wx.Frame):
try: try:
sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_unpatch() sys_patch.PatchSysVolume(self.constants.computer.real_model, self.constants, patches).start_unpatch()
except: except:
logging.error("- An internal error occurred while running the Root Patcher:\n") logging.error("An internal error occurred while running the Root Patcher:\n")
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logger.removeHandler(logger.handlers[2]) logger.removeHandler(logger.handlers[2])
@@ -525,6 +528,8 @@ class SysPatchFrame(wx.Frame):
Thus we'll need to see if the exact same OCLP build was used already Thus we'll need to see if the exact same OCLP build was used already
""" """
logging.info("Checking if new patches are needed")
if self.constants.commit_info[0] in ["Running from source", "Built from source"]: if self.constants.commit_info[0] in ["Running from source", "Built from source"]:
return True return True
@@ -557,5 +562,5 @@ class SysPatchFrame(wx.Frame):
logging.info(f"- Patch {patch} not installed") logging.info(f"- Patch {patch} not installed")
return True return True
logging.info("- No new patches detected for system") logging.info("No new patches detected for system")
return False return False
+8
View File
@@ -22,6 +22,7 @@ class UpdateFrame(wx.Frame):
Create a frame for updating the patcher Create a frame for updating the patcher
""" """
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: wx.Point, url: str = "", version_label: str = "") -> None: def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: wx.Point, url: str = "", version_label: str = "") -> None:
logging.info("Initializing Update Frame")
if parent: if parent:
self.parent: wx.Frame = parent self.parent: wx.Frame = parent
@@ -55,6 +56,9 @@ class UpdateFrame(wx.Frame):
self.version_label = version_label self.version_label = version_label
self.url = url self.url = url
logging.info(f"Update URL: {url}")
logging.info(f"Update Version: {version_label}")
self.frame: wx.Frame = wx.Frame( self.frame: wx.Frame = wx.Frame(
parent=parent if parent else self, parent=parent if parent else self,
title=self.title, title=self.title,
@@ -180,6 +184,7 @@ class UpdateFrame(wx.Frame):
["ditto", "-xk", str(self.constants.payload_path / "OpenCore-Patcher-GUI.app.zip"), str(self.constants.payload_path)], capture_output=True ["ditto", "-xk", str(self.constants.payload_path / "OpenCore-Patcher-GUI.app.zip"), str(self.constants.payload_path)], capture_output=True
) )
if result.returncode != 0: if result.returncode != 0:
logging.error(f"Failed to extract update. Error: {result.stderr.decode('utf-8')}")
wx.CallAfter(self.progress_bar_animation.stop_pulse) wx.CallAfter(self.progress_bar_animation.stop_pulse)
wx.CallAfter(self.progress_bar.SetValue, 0) wx.CallAfter(self.progress_bar.SetValue, 0)
wx.CallAfter(wx.MessageBox, f"Failed to extract update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR) wx.CallAfter(wx.MessageBox, f"Failed to extract update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR)
@@ -190,6 +195,7 @@ class UpdateFrame(wx.Frame):
break break
if i == 1: if i == 1:
logging.error("Failed to extract update. Error: Update file does not exist")
wx.CallAfter(self.progress_bar_animation.stop_pulse) wx.CallAfter(self.progress_bar_animation.stop_pulse)
wx.CallAfter(self.progress_bar.SetValue, 0) wx.CallAfter(self.progress_bar.SetValue, 0)
wx.CallAfter(wx.MessageBox, "Failed to extract update. Error: Update file does not exist", "Critical Error!", wx.OK | wx.ICON_ERROR) wx.CallAfter(wx.MessageBox, "Failed to extract update. Error: Update file does not exist", "Critical Error!", wx.OK | wx.ICON_ERROR)
@@ -251,8 +257,10 @@ EOF
wx.CallAfter(self.progress_bar_animation.stop_pulse) wx.CallAfter(self.progress_bar_animation.stop_pulse)
wx.CallAfter(self.progress_bar.SetValue, 0) wx.CallAfter(self.progress_bar.SetValue, 0)
if "User cancelled" in result.stderr.decode("utf-8"): if "User cancelled" in result.stderr.decode("utf-8"):
logging.info("User cancelled update")
wx.CallAfter(wx.MessageBox, "User cancelled update", "Update Cancelled", wx.OK | wx.ICON_INFORMATION) wx.CallAfter(wx.MessageBox, "User cancelled update", "Update Cancelled", wx.OK | wx.ICON_INFORMATION)
else: else:
logging.critical(f"Failed to install update. Error: {result.stderr.decode('utf-8')}")
wx.CallAfter(wx.MessageBox, f"Failed to install update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR) wx.CallAfter(wx.MessageBox, f"Failed to install update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR)
wx.CallAfter(sys.exit, 1) wx.CallAfter(sys.exit, 1)