mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-06-18 21:30:00 +10:00
Merge pull request #990 from dortania/onedir-gui
Implement faster app load times in GUI
This commit is contained in:
@@ -17,10 +17,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: python3 create_offline_build.py
|
- run: python3 create_offline_build.py
|
||||||
|
- run: hdiutil create ./payloads.dmg -megabytes 32000 -format UDZO -ov -volname "payloads" -fs HFS+ -srcfolder ./payloads -passphrase password -encryption
|
||||||
- run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec
|
- run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec
|
||||||
- run: python3 ./payloads/binary.py $branch $commiturl $commitdate
|
- run: python3 ./payloads/binary.py $branch $commiturl $commitdate
|
||||||
- run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"'
|
- run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"'
|
||||||
- run: cd dist; zip -r ../OpenCore-Patcher-wxPython.app.zip OpenCore-Patcher.app
|
- run: cd dist; ditto -c -k --sequesterRsrc --keepParent OpenCore-Patcher.app ../OpenCore-Patcher-wxPython.app.zip
|
||||||
- run: ./../sign-wxpython.sh
|
- run: ./../sign-wxpython.sh
|
||||||
- run: packagesbuild ./payloads/InstallPackage/AutoPkg-Assets-Setup.pkgproj
|
- run: packagesbuild ./payloads/InstallPackage/AutoPkg-Assets-Setup.pkgproj
|
||||||
- run: mv ./OpenCore-Patcher-wxPython.app.zip ./OpenCore-Patcher-GUI.app.zip
|
- run: mv ./OpenCore-Patcher-wxPython.app.zip ./OpenCore-Patcher-GUI.app.zip
|
||||||
|
|||||||
@@ -29,3 +29,4 @@ __pycache__/
|
|||||||
/payloads/Universal-Binaries
|
/payloads/Universal-Binaries
|
||||||
/payloads/OpenCore-Legacy-Patcher
|
/payloads/OpenCore-Legacy-Patcher
|
||||||
/payloads/InstallAssistant.pkg.integrityDataV1
|
/payloads/InstallAssistant.pkg.integrityDataV1
|
||||||
|
/payloads.dmg
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
- Fix Bluetooth support in 12.4 Release
|
- Fix Bluetooth support in 12.4 Release
|
||||||
- Applicable for BCM2046 and BCM2070 chipsets
|
- Applicable for BCM2046 and BCM2070 chipsets
|
||||||
- Fix backported to 0.4.5 release
|
- Fix backported to 0.4.5 release
|
||||||
|
- GUI Enhancements:
|
||||||
|
- Greatly improve GUI load times (300-800% on average)
|
||||||
|
|
||||||
## 0.4.5
|
## 0.4.5
|
||||||
- Fix AutoPatcher.pkg download on releases
|
- Fix AutoPatcher.pkg download on releases
|
||||||
|
|||||||
+20
-16
@@ -7,9 +7,9 @@ block_cipher = None
|
|||||||
|
|
||||||
|
|
||||||
a = Analysis(['OpenCore-Patcher-GUI.command'],
|
a = Analysis(['OpenCore-Patcher-GUI.command'],
|
||||||
pathex=['resources', 'data', 'gui'],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=[],
|
||||||
datas=[('payloads', 'payloads')],
|
datas=[('payloads.dmg', '.')],
|
||||||
hiddenimports=[],
|
hiddenimports=[],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
@@ -24,33 +24,37 @@ pyz = PYZ(a.pure, a.zipped_data,
|
|||||||
|
|
||||||
exe = EXE(pyz,
|
exe = EXE(pyz,
|
||||||
a.scripts,
|
a.scripts,
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
[],
|
[],
|
||||||
|
exclude_binaries=True,
|
||||||
name='OpenCore-Patcher',
|
name='OpenCore-Patcher',
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
upx=True,
|
upx=True,
|
||||||
upx_exclude=[],
|
|
||||||
runtime_tmpdir=None,
|
|
||||||
console=False,
|
console=False,
|
||||||
disable_windowed_traceback=False,
|
disable_windowed_traceback=False,
|
||||||
target_arch=None,
|
target_arch=None,
|
||||||
codesign_identity=None,
|
codesign_identity=None,
|
||||||
entitlements_file=None )
|
entitlements_file=None )
|
||||||
app = BUNDLE(exe,
|
coll = COLLECT(exe,
|
||||||
|
a.binaries,
|
||||||
|
a.zipfiles,
|
||||||
|
a.datas,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
name='OpenCore-Patcher')
|
||||||
|
app = BUNDLE(coll,
|
||||||
name='OpenCore-Patcher.app',
|
name='OpenCore-Patcher.app',
|
||||||
icon="payloads/OC-Patcher.icns",
|
icon="payloads/OC-Patcher.icns",
|
||||||
bundle_identifier="com.dortania.opencore-legacy-patcher-wxpython",
|
bundle_identifier="com.dortania.opencore-legacy-patcher-wxpython",
|
||||||
info_plist={
|
info_plist={
|
||||||
"CFBundleShortVersionString": constants.Constants().patcher_version,
|
"CFBundleShortVersionString": constants.Constants().patcher_version,
|
||||||
"NSHumanReadableCopyright": constants.Constants().copyright_date,
|
"NSHumanReadableCopyright": constants.Constants().copyright_date,
|
||||||
"LSMinimumSystemVersion": "10.10.0",
|
"LSMinimumSystemVersion": "10.10.0",
|
||||||
"NSRequiresAquaSystemAppearance": False,
|
"NSRequiresAquaSystemAppearance": False,
|
||||||
"NSHighResolutionCapable": True,
|
"NSHighResolutionCapable": True,
|
||||||
"Build Date": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
"Build Date": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||||
"BuildMachineOSBuild": subprocess.run("sw_vers -buildVersion".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode().strip(),
|
"BuildMachineOSBuild": subprocess.run("sw_vers -buildVersion".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode().strip(),
|
||||||
"NSPrincipalClass": "NSApplication",
|
"NSPrincipalClass": "NSApplication",
|
||||||
})
|
})
|
||||||
|
|||||||
+27
-4
@@ -103,8 +103,9 @@ class wx_python_gui:
|
|||||||
|
|
||||||
def use_non_metal_alternative(self):
|
def use_non_metal_alternative(self):
|
||||||
if self.constants.detected_os >= os_data.os_data.monterey:
|
if self.constants.detected_os >= os_data.os_data.monterey:
|
||||||
if self.constants.host_is_non_metal is True:
|
if Path("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLightOld.dylib").exists():
|
||||||
return True
|
if self.constants.host_is_non_metal is True:
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def pulse_alternative(self, progress_bar):
|
def pulse_alternative(self, progress_bar):
|
||||||
@@ -563,6 +564,10 @@ class wx_python_gui:
|
|||||||
|
|
||||||
def build_start(self, event=None):
|
def build_start(self, event=None):
|
||||||
self.build_opencore.Disable()
|
self.build_opencore.Disable()
|
||||||
|
|
||||||
|
while self.constants.unpack_thread.is_alive():
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants).build_opencore()
|
build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants).build_opencore()
|
||||||
# Once finished, change build_opencore button to "Install OpenCore"
|
# Once finished, change build_opencore button to "Install OpenCore"
|
||||||
self.build_opencore.SetLabel("🔩 Install OpenCore")
|
self.build_opencore.SetLabel("🔩 Install OpenCore")
|
||||||
@@ -1004,7 +1009,23 @@ class wx_python_gui:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.developer_note.Centre(wx.HORIZONTAL)
|
self.developer_note.Centre(wx.HORIZONTAL)
|
||||||
self.frame.SetSize(-1, self.developer_note.GetPosition().y + self.developer_note.GetSize().height + 80)
|
|
||||||
|
self.progress_bar = wx.Gauge(self.frame, range=100, size=(200, 10))
|
||||||
|
self.progress_bar.SetPosition(
|
||||||
|
wx.Point(
|
||||||
|
self.developer_note.GetPosition().x,
|
||||||
|
self.developer_note.GetPosition().y + self.developer_note.GetSize().height + 10
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.progress_bar.SetValue(0)
|
||||||
|
self.progress_bar.Centre(wx.HORIZONTAL)
|
||||||
|
self.progress_bar.Pulse()
|
||||||
|
|
||||||
|
self.frame.SetSize(-1, self.progress_bar.GetPosition().y + self.progress_bar.GetSize().height + 60)
|
||||||
|
self.frame.Show()
|
||||||
|
while self.constants.unpack_thread.is_alive():
|
||||||
|
self.pulse_alternative(self.progress_bar)
|
||||||
|
wx.GetApp().Yield()
|
||||||
|
|
||||||
# Download resources
|
# Download resources
|
||||||
sys.stdout=menu_redirect.RedirectLabel(self.developer_note)
|
sys.stdout=menu_redirect.RedirectLabel(self.developer_note)
|
||||||
@@ -1148,6 +1169,8 @@ class wx_python_gui:
|
|||||||
sys.stdout = menu_redirect.RedirectText(self.text_box, True)
|
sys.stdout = menu_redirect.RedirectText(self.text_box, True)
|
||||||
sys.stderr = menu_redirect.RedirectText(self.text_box, True)
|
sys.stderr = menu_redirect.RedirectText(self.text_box, True)
|
||||||
wx.GetApp().Yield()
|
wx.GetApp().Yield()
|
||||||
|
while self.constants.unpack_thread.is_alive():
|
||||||
|
time.sleep(0.1)
|
||||||
try:
|
try:
|
||||||
sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, self.patches).start_unpatch()
|
sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants, self.patches).start_unpatch()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1265,7 +1288,7 @@ class wx_python_gui:
|
|||||||
thread_ia = threading.Thread(target=ia)
|
thread_ia = threading.Thread(target=ia)
|
||||||
thread_ia.start()
|
thread_ia.start()
|
||||||
|
|
||||||
while thread_ia.is_alive():
|
while thread_ia.is_alive() or self.constants.unpack_thread.is_alive():
|
||||||
self.pulse_alternative(self.progress_bar)
|
self.pulse_alternative(self.progress_bar)
|
||||||
wx.GetApp().Yield()
|
wx.GetApp().Yield()
|
||||||
available_installers = self.available_installers
|
available_installers = self.available_installers
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ class Constants:
|
|||||||
self.launcher_script = None # Determine launch file (if run via Python)
|
self.launcher_script = None # Determine launch file (if run via Python)
|
||||||
self.ignore_updates = False # Ignore OCLP updates
|
self.ignore_updates = False # Ignore OCLP updates
|
||||||
self.wxpython_variant = False # Determine if using wxPython variant
|
self.wxpython_variant = False # Determine if using wxPython variant
|
||||||
|
self.unpack_thread = None # Determine if unpack thread finished
|
||||||
|
self.cli_mode = False # Determine if running in CLI mode
|
||||||
|
|
||||||
## Hardware
|
## Hardware
|
||||||
self.computer: device_probe.Computer = None # type: ignore
|
self.computer: device_probe.Computer = None # type: ignore
|
||||||
|
|||||||
+12
-1
@@ -5,8 +5,10 @@ from __future__ import print_function
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
from resources import build, cli_menu, constants, utilities, device_probe, os_probe, defaults, arguments, install, tui_helpers
|
from resources import build, cli_menu, constants, utilities, device_probe, os_probe, defaults, arguments, install, tui_helpers, reroute_payloads
|
||||||
from data import model_array
|
from data import model_array
|
||||||
|
|
||||||
class OpenCoreLegacyPatcher:
|
class OpenCoreLegacyPatcher:
|
||||||
@@ -40,20 +42,29 @@ class OpenCoreLegacyPatcher:
|
|||||||
launcher_script = launcher_script.replace("/resources/main.py", "/OpenCore-Patcher-GUI.command")
|
launcher_script = launcher_script.replace("/resources/main.py", "/OpenCore-Patcher-GUI.command")
|
||||||
self.constants.launcher_binary = launcher_binary
|
self.constants.launcher_binary = launcher_binary
|
||||||
self.constants.launcher_script = launcher_script
|
self.constants.launcher_script = launcher_script
|
||||||
|
self.constants.unpack_thread = threading.Thread(target=reroute_payloads.reroute_payloads(self.constants).setup_tmp_disk_image)
|
||||||
|
self.constants.unpack_thread.start()
|
||||||
|
|
||||||
defaults.generate_defaults.probe(self.computer.real_model, True, self.constants)
|
defaults.generate_defaults.probe(self.computer.real_model, True, self.constants)
|
||||||
|
|
||||||
if utilities.check_cli_args() is not None:
|
if utilities.check_cli_args() is not None:
|
||||||
print("- Detected arguments, switching to CLI mode")
|
print("- 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"]
|
ignore_args = ["--auto_patch", "--gui_patch", "--gui_unpatch"]
|
||||||
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()
|
||||||
|
self.constants.cli_mode = True
|
||||||
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
||||||
print("- Rerouting payloads location")
|
print("- Rerouting payloads location")
|
||||||
self.constants.payload_path = sys._MEIPASS / Path("payloads")
|
self.constants.payload_path = sys._MEIPASS / Path("payloads")
|
||||||
|
print("- Waiting for payloads to unpack...")
|
||||||
|
while self.constants.unpack_thread.is_alive():
|
||||||
|
time.sleep(0.1)
|
||||||
arguments.arguments().parse_arguments(self.constants)
|
arguments.arguments().parse_arguments(self.constants)
|
||||||
else:
|
else:
|
||||||
print(f"- No arguments present, loading {'GUI' if self.constants.wxpython_variant is True else 'TUI'} mode")
|
print(f"- No arguments present, loading {'GUI' if self.constants.wxpython_variant is True else 'TUI'} mode")
|
||||||
|
|
||||||
|
|
||||||
def main_menu(self):
|
def main_menu(self):
|
||||||
response = None
|
response = None
|
||||||
while not (response and response == -1):
|
while not (response and response == -1):
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Reoute binaries to tmp directory, and mount a disk image of the payloads
|
||||||
|
# Implements a shadowfile to avoid direct writes to the dmg
|
||||||
|
# Copyright (C) 2022, Mykola Grymalyuk
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import plistlib
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
class reroute_payloads:
|
||||||
|
def __init__(self, constants):
|
||||||
|
self.constants = constants
|
||||||
|
|
||||||
|
def setup_tmp_disk_image(self):
|
||||||
|
# Create a temp directory to mount the payloads.dmg
|
||||||
|
# Then reroute r/w to this new temp directory
|
||||||
|
# Currently only applicable for GUI variant
|
||||||
|
if self.constants.launcher_binary and self.constants.wxpython_variant is True and not self.constants.launcher_script:
|
||||||
|
print("- Running in Binary GUI mode, switching to tmp directory")
|
||||||
|
self.temp_dir = tempfile.TemporaryDirectory()
|
||||||
|
print(f"- New payloads location: {self.temp_dir.name}")
|
||||||
|
print("- Creating payloads directory")
|
||||||
|
Path(self.temp_dir.name / Path("payloads")).mkdir(parents=True, exist_ok=True)
|
||||||
|
self.unmount_active_dmgs()
|
||||||
|
output = subprocess.run(
|
||||||
|
[
|
||||||
|
"hdiutil", "attach", "-noverify", f"{self.constants.payload_path}.dmg",
|
||||||
|
"-mountpoint", Path(self.temp_dir.name / Path("payloads")),
|
||||||
|
"-nobrowse", "-shadow", Path(self.temp_dir.name / Path("payloads_overlay")),
|
||||||
|
"-passphrase", "password"
|
||||||
|
],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
|
if output.returncode == 0:
|
||||||
|
print("- Mounted payloads.dmg")
|
||||||
|
self.constants.current_path = Path(self.temp_dir.name)
|
||||||
|
self.constants.payload_path = Path(self.temp_dir.name) / Path("payloads")
|
||||||
|
atexit.register(self.unmount_active_dmgs)
|
||||||
|
else:
|
||||||
|
print("- Failed to mount payloads.dmg")
|
||||||
|
print(f"Output: {output.stdout.decode()}")
|
||||||
|
print(f"Return Code: {output.returncode}")
|
||||||
|
print("- Exiting...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def unmount_active_dmgs(self):
|
||||||
|
# Find all DMGs that are mounted, and forcefully unmount them
|
||||||
|
# If our disk image was previously mounted, we need to unmount it to use again
|
||||||
|
# This can happen if we crash during a previous scession, however 'atexit' class should hopefully avoid this
|
||||||
|
dmg_info = subprocess.run(["hdiutil", "info", "-plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
dmg_info = plistlib.loads(dmg_info.stdout)
|
||||||
|
|
||||||
|
for image in dmg_info["images"]:
|
||||||
|
if image["image-path"].endswith("payloads.dmg"):
|
||||||
|
print(f"- Unmounting payloads.dmg")
|
||||||
|
subprocess.run(
|
||||||
|
["hdiutil", "detach", image["system-entities"][0]["dev-entry"], "-force"],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
@@ -309,7 +309,7 @@ class PatchSysVolume:
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
def download_files(self):
|
def download_files(self):
|
||||||
if self.constants.gui_mode is False or "Library/InstallerSandboxes/" in str(self.constants.payload_path):
|
if self.constants.cli_mode is True:
|
||||||
download_result, link = sys_patch_download.grab_patcher_support_pkg(self.constants).download_files()
|
download_result, link = sys_patch_download.grab_patcher_support_pkg(self.constants).download_files()
|
||||||
else:
|
else:
|
||||||
download_result = True
|
download_result = True
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ class grab_patcher_support_pkg:
|
|||||||
shutil.rmtree(self.constants.payload_local_binaries_root_path)
|
shutil.rmtree(self.constants.payload_local_binaries_root_path)
|
||||||
|
|
||||||
download_result = None
|
download_result = None
|
||||||
local_zip = Path(self.constants.payload_path) / f"Universal-Binaries.zip"
|
if Path(self.constants.payload_local_binaries_root_path_zip).exists():
|
||||||
if Path(local_zip).exists():
|
|
||||||
print(f"- Found local Universal-Binaries.zip, skipping download")
|
print(f"- Found local Universal-Binaries.zip, skipping download")
|
||||||
download_result = True
|
download_result = True
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user