diff --git a/SOURCE.md b/SOURCE.md index 597779254..8bd2a036f 100644 --- a/SOURCE.md +++ b/SOURCE.md @@ -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). diff --git a/opencore_legacy_patcher/support/updates.py b/opencore_legacy_patcher/support/updates.py index 4e5e220e5..bf10de30a 100644 --- a/opencore_legacy_patcher/support/updates.py +++ b/opencore_legacy_patcher/support/updates.py @@ -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 diff --git a/opencore_legacy_patcher/wx_gui/gui_settings.py b/opencore_legacy_patcher/wx_gui/gui_settings.py index 8dfe48a6d..201d1a690 100644 --- a/opencore_legacy_patcher/wx_gui/gui_settings.py +++ b/opencore_legacy_patcher/wx_gui/gui_settings.py @@ -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)" ) diff --git a/opencore_legacy_patcher/wx_gui/gui_update.py b/opencore_legacy_patcher/wx_gui/gui_update.py index d08a49ca0..b96016798 100644 --- a/opencore_legacy_patcher/wx_gui/gui_update.py +++ b/opencore_legacy_patcher/wx_gui/gui_update.py @@ -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" - - - - CFBundleShortVersionString - {self.version_label} - CFBundleVersion - {self.version_label} - InstallationDate - {datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")} - InstallationSource - {self.url} - - -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"])