updates.py: Add support for PKG updates

This commit is contained in:
Mykola Grymalyuk
2024-05-27 11:29:04 -06:00
parent acbeef070f
commit b0def277ea
4 changed files with 36 additions and 111 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
OpenCore Legacy Patcher at its core is a Python-based GUI/CLI-based application. In turn, to run the project from source, you simply need to invoke the OpenCore-Patcher-GUI.command file via Python.
For developers wishing to validate mainline changes, you may use this link: [GUI (Graphical Based App)](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/main/OpenCore-Patcher.app%20%28GUI%29.zip)
For developers wishing to validate mainline changes, you may use this link: [GUI (Graphical Based App)](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/main/OpenCore-Patcher.pkg.zip)
* **Warning**: Nightly builds (untagged builds built from the latest commit) are actively developed OpenCore Legacy Patcher builds. These builds have not been tested, are not guaranteed to work, and are not guaranteed to be safe. Do not use nightlies without a good reason to do so, and do not use them on your main machine. Additionally, these binaries should not be used without first consulting the [CHANGELOG](./CHANGELOG.md).
+1 -29
View File
@@ -78,33 +78,6 @@ class CheckBinaryUpdates:
return first_version > second_version
def _determine_local_build_type(self) -> str:
"""
Check if the local build is a GUI or TUI build
Returns:
str: "GUI" or "TUI"
"""
return "GUI" if self.constants.wxpython_variant else "TUI"
def _determine_remote_type(self, remote_name: str) -> str:
"""
Check if the remote build is a GUI or TUI build
Parameters:
remote_name (str): Name of the remote build
Returns:
str: "GUI" or "TUI"
"""
if "TUI" in remote_name:
return "TUI"
elif "GUI" in remote_name:
return "GUI"
else:
return "Unknown"
def check_binary_updates(self) -> Optional[dict]:
"""
@@ -143,12 +116,11 @@ class CheckBinaryUpdates:
for asset in data_set["assets"]:
logging.info(f"Found asset: {asset['name']}")
if self._determine_remote_type(asset["name"]) == self._determine_local_build_type():
if asset["name"] == "OpenCore-Patcher.pkg":
self.latest_details = {
"Name": asset["name"],
"Version": latest_remote_version,
"Link": asset["browser_download_url"],
"Type": self._determine_remote_type(asset["name"]),
"Github Link": f"https://github.com/dortania/OpenCore-Legacy-Patcher/releases/{latest_remote_version}",
}
return self.latest_details
@@ -1303,7 +1303,7 @@ Hardware Information:
title=self.title,
global_constants=self.constants,
screen_location=self.parent.GetPosition(),
url=f"https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/{branch}/OpenCore-Patcher.app%20%28GUI%29.zip",
url=f"https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/{branch}/OpenCore-Patcher.pkg.zip",
version_label="(Nightly)"
)
+33 -80
View File
@@ -43,7 +43,7 @@ class UpdateFrame(wx.Frame):
self.title: str = title
self.constants: constants.Constants = global_constants
self.application_path = self.constants.payload_path / "OpenCore-Patcher.app"
self.pkg_download_path = self.constants.payload_path / "OpenCore-Patcher.pkg"
self.screen_location: wx.Point = screen_location
if parent:
self.parent.Centre()
@@ -98,7 +98,8 @@ class UpdateFrame(wx.Frame):
download_obj = None
def _fetch_update() -> None:
nonlocal download_obj
download_obj = network_handler.DownloadObject(url, self.constants.payload_path / "OpenCore-Patcher-GUI.app.zip")
file_name = "OpenCore-Patcher.pkg.zip" if url.endswith(".zip") else "OpenCore-Patcher.pkg"
download_obj = network_handler.DownloadObject(url, self.constants.payload_path / file_name)
thread = threading.Thread(target=_fetch_update)
thread.start()
@@ -189,90 +190,37 @@ class UpdateFrame(wx.Frame):
def _extract_update(self) -> None:
"""
Extracts the update
Logic:
- Distributed through GitHub Actions: Requires extraction
- Distributed through GitHub Releases: No extraction required
"""
logging.info("Extracting update")
if Path(self.application_path).exists():
subprocess.run(["/bin/rm", "-rf", str(self.application_path)])
# GitHub Release
if not self.url.endswith(".zip"):
return
# Some hell spawn at Github decided to double zip our Github Actions artifacts
# So we need to unzip it twice
for i in range(2):
result = subprocess.run(
["/usr/bin/ditto", "-xk", str(self.constants.payload_path / "OpenCore-Patcher-GUI.app.zip"), str(self.constants.payload_path)], capture_output=True
)
if result.returncode != 0:
logging.error(f"Failed to extract update.")
subprocess_wrapper.log(result)
wx.CallAfter(self.progress_bar_animation.stop_pulse)
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(sys.exit, 1)
break
logging.info("Extracting nightly update")
if Path(self.pkg_download_path).exists():
subprocess.run(["/bin/rm", "-rf", str(self.pkg_download_path)])
if Path(self.application_path).exists():
break
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.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)
break
result = subprocess.run(
["/usr/bin/ditto", "-xk", str(self.constants.payload_path / "OpenCore-Patcher.pkg.zip"), str(self.constants.payload_path)], capture_output=True
)
if result.returncode != 0:
logging.error(f"Failed to extract update.")
subprocess_wrapper.log(result)
wx.CallAfter(self.progress_bar_animation.stop_pulse)
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(sys.exit, 1)
def _install_update(self) -> None:
"""
Installs update to '/Library/Application Support/Dortania/OpenCore-Patcher.app'
Install PKG
"""
logging.info(f"Installing update: {self.application_path}")
# Create bash script to run as root
script = f"""#!/bin/bash
# Check if '/Library/Application Support/Dortania' exists
if [ ! -d "/Library/Application Support/Dortania" ]; then
mkdir -p "/Library/Application Support/Dortania"
fi
# Check if 'OpenCore-Patcher.app' exists
if [ -d "/Library/Application Support/Dortania/OpenCore-Patcher.app" ]; then
rm -rf "/Library/Application Support/Dortania/OpenCore-Patcher.app"
fi
if [ -d "/Applications/OpenCore-Patcher.app" ]; then
rm -rf "/Applications/OpenCore-Patcher.app"
fi
# Move '/tmp/OpenCore-Patcher.app' to '/Library/Application Support/Dortania'
mv "{str(self.application_path)}" "/Library/Application Support/Dortania/OpenCore-Patcher.app"
# Check if '/Applications/OpenCore-Patcher.app' exists
ln -s "/Library/Application Support/Dortania/OpenCore-Patcher.app" "/Applications/OpenCore-Patcher.app"
# 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
with open(self.constants.payload_path / "update.sh", "w") as f:
f.write(script)
# Execute script
args = [self.constants.oclp_helper_path, "/bin/sh", str(self.constants.payload_path / "update.sh")]
result = subprocess.run(args, capture_output=True)
logging.info(f"Installing update: {self.pkg_download_path}")
result = subprocess_wrapper.run_as_root(["/usr/sbin/installer", "-pkg", str(self.pkg_download_path), "-target", "/"], capture_output=True)
if result.returncode != 0:
wx.CallAfter(self.progress_bar_animation.stop_pulse)
wx.CallAfter(self.progress_bar.SetValue, 0)
@@ -282,7 +230,12 @@ EOF
else:
logging.critical("Failed to install update.")
subprocess_wrapper.log(result)
wx.CallAfter(wx.MessageBox, f"Failed to install update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR)
# If it fails, fall back to opening the PKG
logging.error("Failed to install update, attempting to open PKG")
subprocess.run(["/usr/bin/open", str(self.pkg_download_path)])
wx.CallAfter(wx.MessageBox, f"Failed to install update. Please try installing the OpenCore-Patcher.pkg manually or download from GitHub", "Critical Error!", wx.OK | wx.ICON_ERROR)
wx.CallAfter(sys.exit, 1)
@@ -291,4 +244,4 @@ EOF
Launches newly installed update
"""
logging.info("Launching update: '/Library/Application Support/Dortania/OpenCore-Patcher.app'")
subprocess.Popen(["/Library/Application Support/Dortania/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher", "--update_installed"])
subprocess.run(["/usr/bin/open", "/Library/Application Support/Dortania/OpenCore-Patcher.app", "--args", "--update_installed"])