mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-24 12:00:15 +10:00
GUI: Implement update.plist creation on update
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -36,3 +36,4 @@ __pycache__/
|
|||||||
/Universal-Binaries.dmg
|
/Universal-Binaries.dmg
|
||||||
/payloads/KDKInfo.plist
|
/payloads/KDKInfo.plist
|
||||||
/payloads/update.sh
|
/payloads/update.sh
|
||||||
|
/payloads/OpenCore-Patcher.app
|
||||||
|
|||||||
@@ -382,7 +382,6 @@ class DownloadObject:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if self.total_file_size == 0.0:
|
if self.total_file_size == 0.0:
|
||||||
logging.error("- File size is 0, cannot calculate percent")
|
|
||||||
return -1
|
return -1
|
||||||
return self.downloaded_file_size / self.total_file_size * 100
|
return self.downloaded_file_size / self.total_file_size * 100
|
||||||
|
|
||||||
@@ -407,7 +406,6 @@ class DownloadObject:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if self.total_file_size == 0.0:
|
if self.total_file_size == 0.0:
|
||||||
logging.error("- File size is 0, cannot calculate time remaining")
|
|
||||||
return -1
|
return -1
|
||||||
speed = self.get_speed()
|
speed = self.get_speed()
|
||||||
if speed <= 0:
|
if speed <= 0:
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ def seconds_to_readable_time(seconds) -> str:
|
|||||||
time = ""
|
time = ""
|
||||||
|
|
||||||
if seconds == 0:
|
if seconds == 0:
|
||||||
return "Done"
|
return "Almost done"
|
||||||
if seconds < 0:
|
if seconds < 0:
|
||||||
return "Indeterminate"
|
return "Indeterminate"
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class DownloadFrame(wx.Frame):
|
|||||||
|
|
||||||
self.download_obj.download()
|
self.download_obj.download()
|
||||||
while self.download_obj.is_active():
|
while self.download_obj.is_active():
|
||||||
if self.download_obj.total_file_size == -1:
|
if self.download_obj.get_percent() == -1:
|
||||||
amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded"
|
amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded"
|
||||||
else:
|
else:
|
||||||
amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded of {utilities.human_fmt(self.download_obj.total_file_size)} ({self.download_obj.get_percent():.2f}%)"
|
amount_str = f"{utilities.human_fmt(self.download_obj.downloaded_file_size)} downloaded of {utilities.human_fmt(self.download_obj.total_file_size)} ({self.download_obj.get_percent():.2f}%)"
|
||||||
@@ -71,7 +71,6 @@ class DownloadFrame(wx.Frame):
|
|||||||
f"Estimated time remaining: {utilities.seconds_to_readable_time(self.download_obj.get_time_remaining())}"
|
f"Estimated time remaining: {utilities.seconds_to_readable_time(self.download_obj.get_time_remaining())}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
progress_bar.SetValue(int(self.download_obj.get_percent()))
|
progress_bar.SetValue(int(self.download_obj.get_percent()))
|
||||||
wx.GetApp().Yield()
|
wx.GetApp().Yield()
|
||||||
|
|
||||||
|
|||||||
@@ -203,5 +203,5 @@ class MainMenu(wx.Frame):
|
|||||||
global_constants=self.constants,
|
global_constants=self.constants,
|
||||||
screen_location=self.GetPosition(),
|
screen_location=self.GetPosition(),
|
||||||
url=oclp_url,
|
url=oclp_url,
|
||||||
item=oclp_version
|
version_label=oclp_version
|
||||||
)
|
)
|
||||||
@@ -4,8 +4,9 @@ import logging
|
|||||||
import py_sip_xnu
|
import py_sip_xnu
|
||||||
import pprint
|
import pprint
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from resources.wx_gui import gui_support
|
from resources.wx_gui import gui_support, gui_update
|
||||||
|
|
||||||
from resources import constants, global_settings, defaults, generate_smbios
|
from resources import constants, global_settings, defaults, generate_smbios
|
||||||
from data import model_array, sip_data, smbios_data, os_data
|
from data import model_array, sip_data, smbios_data, os_data
|
||||||
@@ -52,6 +53,12 @@ class SettingsFrame(wx.Frame):
|
|||||||
model_choice.SetSelection(model_choice.FindString(selection))
|
model_choice.SetSelection(model_choice.FindString(selection))
|
||||||
sizer.Add(model_choice, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
sizer.Add(model_choice, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
||||||
|
|
||||||
|
if Path("~/.dortania_developer").expanduser().exists():
|
||||||
|
developer_mode_button = wx.Button(frame, label="Install latest nightly build 🧪", pos=(-1, -1), size=(200, 30))
|
||||||
|
developer_mode_button.Bind(wx.EVT_BUTTON, self.on_dev_mode)
|
||||||
|
developer_mode_button.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
||||||
|
sizer.Add(developer_mode_button, 0, wx.ALIGN_CENTER | wx.ALL, 0)
|
||||||
|
else:
|
||||||
model_description = wx.StaticText(frame, label="Overrides Mac Model Patcher will build for.", pos=(-1, -1))
|
model_description = wx.StaticText(frame, label="Overrides Mac Model Patcher will build for.", pos=(-1, -1))
|
||||||
model_description.SetFont(wx.Font(11, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
model_description.SetFont(wx.Font(11, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
||||||
sizer.Add(model_description, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
sizer.Add(model_description, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
||||||
@@ -1133,7 +1140,6 @@ Hardware Information:
|
|||||||
self.constants.metal_build = False
|
self.constants.metal_build = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _get_system_settings(self, variable) -> bool:
|
def _get_system_settings(self, variable) -> bool:
|
||||||
result = subprocess.run(["defaults", "read", "-g", variable], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
result = subprocess.run(["defaults", "read", "-g", variable], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
@@ -1146,3 +1152,14 @@ Hardware Information:
|
|||||||
|
|
||||||
def on_return(self, event):
|
def on_return(self, event):
|
||||||
self.frame_modal.Destroy()
|
self.frame_modal.Destroy()
|
||||||
|
|
||||||
|
|
||||||
|
def on_dev_mode(self, event: wx.Event) -> None:
|
||||||
|
gui_update.UpdateFrame(
|
||||||
|
parent=self.parent,
|
||||||
|
title=self.title,
|
||||||
|
global_constants=self.constants,
|
||||||
|
screen_location=self.parent.GetPosition(),
|
||||||
|
url="https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/main/OpenCore-Patcher.app%20%28GUI%29.zip",
|
||||||
|
version_label="(Nightly)"
|
||||||
|
)
|
||||||
@@ -4,6 +4,7 @@ import subprocess
|
|||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from resources.wx_gui import gui_download
|
from resources.wx_gui import gui_download
|
||||||
@@ -13,7 +14,7 @@ from resources import constants, network_handler, updates
|
|||||||
|
|
||||||
class UpdateFrame(wx.Frame):
|
class UpdateFrame(wx.Frame):
|
||||||
|
|
||||||
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: wx.Point, url: str = "", item: str = "") -> None:
|
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: wx.Point, url: str = "", version_label: str = "") -> None:
|
||||||
if parent:
|
if parent:
|
||||||
self.parent: wx.Frame = parent
|
self.parent: wx.Frame = parent
|
||||||
|
|
||||||
@@ -35,14 +36,17 @@ class UpdateFrame(wx.Frame):
|
|||||||
self.screen_location = self.GetScreenPosition()
|
self.screen_location = self.GetScreenPosition()
|
||||||
|
|
||||||
|
|
||||||
if url == "" or item == "":
|
if url == "" or version_label == "":
|
||||||
dict = updates.CheckBinaryUpdates(self.constants).check_binary_updates()
|
dict = updates.CheckBinaryUpdates(self.constants).check_binary_updates()
|
||||||
if dict:
|
if dict:
|
||||||
for key in dict:
|
for key in dict:
|
||||||
item = dict[key]["Version"]
|
version_label = dict[key]["Version"]
|
||||||
url = dict[key]["Link"]
|
url = dict[key]["Link"]
|
||||||
break
|
break
|
||||||
|
|
||||||
|
self.version_label = version_label
|
||||||
|
self.url = url
|
||||||
|
|
||||||
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,
|
||||||
@@ -51,7 +55,6 @@ class UpdateFrame(wx.Frame):
|
|||||||
style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
|
style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Title: Preparing update
|
# Title: Preparing update
|
||||||
title_label = wx.StaticText(self.frame, label="Preparing download...", pos=(-1,1))
|
title_label = wx.StaticText(self.frame, label="Preparing download...", pos=(-1,1))
|
||||||
title_label.SetFont(wx.Font(19, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
title_label.SetFont(wx.Font(19, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
||||||
@@ -73,7 +76,7 @@ class UpdateFrame(wx.Frame):
|
|||||||
title=self.title,
|
title=self.title,
|
||||||
global_constants=self.constants,
|
global_constants=self.constants,
|
||||||
download_obj=download_obj,
|
download_obj=download_obj,
|
||||||
item_name=f"OpenCore Patcher {item}"
|
item_name=f"OpenCore Patcher {version_label}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if download_obj.download_complete is False:
|
if download_obj.download_complete is False:
|
||||||
@@ -110,7 +113,7 @@ class UpdateFrame(wx.Frame):
|
|||||||
progress_bar.Hide()
|
progress_bar.Hide()
|
||||||
|
|
||||||
# Label: 0.6.6 has been installed to:
|
# Label: 0.6.6 has been installed to:
|
||||||
installed_label = wx.StaticText(self.frame, label=f"{item} has been installed:", pos=(-1, progress_bar.GetPosition().y - 15))
|
installed_label = wx.StaticText(self.frame, label=f"{version_label} has been installed:", pos=(-1, progress_bar.GetPosition().y - 15))
|
||||||
installed_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
installed_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, ".AppleSystemUIFont"))
|
||||||
installed_label.Center(wx.HORIZONTAL)
|
installed_label.Center(wx.HORIZONTAL)
|
||||||
|
|
||||||
@@ -120,12 +123,12 @@ class UpdateFrame(wx.Frame):
|
|||||||
installed_path_label.Center(wx.HORIZONTAL)
|
installed_path_label.Center(wx.HORIZONTAL)
|
||||||
|
|
||||||
# Label: Launching update shortly...
|
# Label: Launching update shortly...
|
||||||
launch_label = wx.StaticText(self.frame, label="Launching update shortly...", pos=(-1, installed_path_label.GetPosition().y + 20))
|
launch_label = wx.StaticText(self.frame, label="Launching update shortly...", pos=(-1, installed_path_label.GetPosition().y + 30))
|
||||||
launch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
launch_label.SetFont(wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
|
||||||
launch_label.Center(wx.HORIZONTAL)
|
launch_label.Center(wx.HORIZONTAL)
|
||||||
|
|
||||||
# Adjust frame size
|
# Adjust frame size
|
||||||
self.frame.SetSize((-1, launch_label.GetPosition().y + 80))
|
self.frame.SetSize((-1, launch_label.GetPosition().y + 60))
|
||||||
|
|
||||||
thread = threading.Thread(target=self._launch_update)
|
thread = threading.Thread(target=self._launch_update)
|
||||||
thread.start()
|
thread.start()
|
||||||
@@ -133,11 +136,11 @@ class UpdateFrame(wx.Frame):
|
|||||||
while thread.is_alive():
|
while thread.is_alive():
|
||||||
wx.Yield()
|
wx.Yield()
|
||||||
|
|
||||||
timer = 3
|
timer = 5
|
||||||
while True:
|
while True:
|
||||||
wx.GetApp().Yield()
|
|
||||||
launch_label.SetLabel(f"Closing old process in {timer} seconds")
|
launch_label.SetLabel(f"Closing old process in {timer} seconds")
|
||||||
launch_label.Center(wx.HORIZONTAL)
|
launch_label.Center(wx.HORIZONTAL)
|
||||||
|
wx.GetApp().Yield()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
timer -= 1
|
timer -= 1
|
||||||
if timer == 0:
|
if timer == 0:
|
||||||
@@ -152,6 +155,12 @@ class UpdateFrame(wx.Frame):
|
|||||||
logging.info("Extracting update")
|
logging.info("Extracting update")
|
||||||
if Path(self.application_path).exists():
|
if Path(self.application_path).exists():
|
||||||
subprocess.run(["rm", "-rf", str(self.application_path)])
|
subprocess.run(["rm", "-rf", str(self.application_path)])
|
||||||
|
|
||||||
|
|
||||||
|
# Some hell spawn at Github decided to double zip our Github Actions artifacts
|
||||||
|
# So we need to unzip it twice
|
||||||
|
loop = 0
|
||||||
|
while True:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["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
|
||||||
)
|
)
|
||||||
@@ -159,11 +168,18 @@ class UpdateFrame(wx.Frame):
|
|||||||
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)
|
||||||
wx.CallAfter(sys.exit, 1)
|
wx.CallAfter(sys.exit, 1)
|
||||||
|
if Path(self.application_path).exists():
|
||||||
|
break
|
||||||
|
loop += 1
|
||||||
|
if loop == 2:
|
||||||
|
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(sys.exit, 1)
|
||||||
|
|
||||||
|
|
||||||
def _install_update(self):
|
def _install_update(self):
|
||||||
# Install update
|
# Install update
|
||||||
logging.info("Installing update")
|
logging.info(f"Installing update: {self.application_path}")
|
||||||
|
|
||||||
# Create bash script to run as root
|
# Create bash script to run as root
|
||||||
script = f"""#!/bin/bash
|
script = f"""#!/bin/bash
|
||||||
@@ -184,6 +200,23 @@ mv "{str(self.application_path)}" "/Library/Application Support/Dortania/OpenCor
|
|||||||
if [ ! -d "/Applications/OpenCore-Patcher.app" ]; then
|
if [ ! -d "/Applications/OpenCore-Patcher.app" ]; then
|
||||||
ln -s "/Library/Application Support/Dortania/OpenCore-Patcher.app" "/Applications/OpenCore-Patcher.app"
|
ln -s "/Library/Application Support/Dortania/OpenCore-Patcher.app" "/Applications/OpenCore-Patcher.app"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Create update.plist with info about update
|
||||||
|
cat << EOF > "/Library/Application Support/Dortania/update.plist"
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>{self.version_label}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>{self.version_label}</string>
|
||||||
|
<key>InstallationDate</key>
|
||||||
|
<date>{datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")}</date>
|
||||||
|
<key>InstallationSource</key>
|
||||||
|
<string>{self.url}</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
"""
|
"""
|
||||||
# Write script to file
|
# Write script to file
|
||||||
with open(self.constants.payload_path / "update.sh", "w") as f:
|
with open(self.constants.payload_path / "update.sh", "w") as f:
|
||||||
@@ -191,10 +224,12 @@ fi
|
|||||||
|
|
||||||
# Execute script
|
# Execute script
|
||||||
args = [self.constants.oclp_helper_path, "/bin/sh", str(self.constants.payload_path / "update.sh")]
|
args = [self.constants.oclp_helper_path, "/bin/sh", str(self.constants.payload_path / "update.sh")]
|
||||||
logging.info(f"Executing: {args}")
|
|
||||||
result = subprocess.run(args, capture_output=True)
|
result = subprocess.run(args, capture_output=True)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
wx.CallAfter(self.progress_bar.SetValue, 0)
|
wx.CallAfter(self.progress_bar.SetValue, 0)
|
||||||
|
if "User cancelled" in result.stderr.decode("utf-8"):
|
||||||
|
wx.CallAfter(wx.MessageBox, "User cancelled update", "Update Cancelled", wx.OK | wx.ICON_INFORMATION)
|
||||||
|
else:
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user