diff --git a/Build-Binary.command b/Build-Binary.command index 1da9a6a71..65e913da6 100755 --- a/Build-Binary.command +++ b/Build-Binary.command @@ -123,6 +123,9 @@ class create_binary: if file.name in delete_files: print(f" - Deleting {file.name}") file.unlink() + elif (Path(file) / Path("Contents/Resources/createinstallmedia")).exists(): + print(f" - Deleting {file}") + subprocess.run(["rm", "-rf", file]) def download_resources(self): patcher_support_pkg_version = constants.Constants().patcher_support_pkg_version diff --git a/gui/gui_main.py b/gui/gui_main.py index 1dbc373e6..d42ce245c 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -31,6 +31,7 @@ class wx_python_gui: self.finished_cim_process = False self.target_disk = "" self.pulse_forward = False + self.prepare_result = False self.non_metal_required = self.use_non_metal_alternative() self.hyperlink_colour = (25, 179, 231) @@ -1832,9 +1833,8 @@ class wx_python_gui: 20 ) self.progress_bar.Centre(wx.HORIZONTAL) - self.progress_bar.SetValue(0) - self.progress_label = wx.StaticText(self.frame, label="Bytes Written: 0") + self.progress_label = wx.StaticText(self.frame, label="Preparing files, beginning shortly...") self.progress_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.progress_label.SetPosition( wx.Point( @@ -1863,7 +1863,18 @@ class wx_python_gui: print("- Creating installer.sh script") print(f"- Disk: {disk}") print(f"- Installer: {installer_path}") - if installer.generate_installer_creation_script(self.constants.installer_sh_path, installer_path, disk): + + self.prepare_script_thread = threading.Thread(target=self.prepare_script, args=(installer_path,disk)) + self.prepare_script_thread.start() + self.progress_bar.Pulse() + + while self.prepare_script_thread.is_alive(): + self.pulse_alternative(self.progress_bar) + wx.GetApp().Yield() + + if self.prepare_result is True: + self.progress_label.SetLabel("Bytes Written: 0") + self.progress_label.Centre(wx.HORIZONTAL) print("- Sucessfully generated creation script") print("- Starting creation script as admin") wx.GetApp().Yield() @@ -1875,6 +1886,7 @@ class wx_python_gui: self.download_thread = threading.Thread(target=self.download_and_unzip_pkg) self.download_thread.start() default_output = float(utilities.monitor_disk_output(disk)) + self.progress_bar.SetValue(0) while True: time.sleep(0.1) output = float(utilities.monitor_disk_output(disk)) @@ -1918,8 +1930,15 @@ class wx_python_gui: self.build_install_menu() else: print("- Failed to create installer script") + self.progress_label.SetLabel("Failed to copy files to tmp directory") + self.progress_label.Centre(wx.HORIZONTAL) + popup_message = wx.MessageDialog(self.frame, "Failed to prepare the base files for installer creation.\n\nPlease ensure you have 20GB~ free on-disk before starting to ensure the installer has enough room to work.", "Error", wx.OK) + popup_message.ShowModal() self.return_to_main_menu.Enable() + def prepare_script(self, installer_path, disk): + self.prepare_result = installer.generate_installer_creation_script(self.constants.payload_path, installer_path, disk) + def start_script(self): utilities.disable_sleep_while_running() args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path] diff --git a/resources/installer.py b/resources/installer.py index e13b3c7e4..0217087cc 100644 --- a/resources/installer.py +++ b/resources/installer.py @@ -3,6 +3,7 @@ from pathlib import Path import plistlib import subprocess import requests +import tempfile from resources import utilities, tui_helpers def list_local_macOS_installers(): @@ -331,8 +332,10 @@ def list_disk_to_format(): }) return list_disks +# Create global tmp directory +tmp_dir = tempfile.TemporaryDirectory() -def generate_installer_creation_script(script_location, installer_path, disk): +def generate_installer_creation_script(tmp_location, installer_path, disk): # Creates installer.sh to be piped to OCLP-Helper and run as admin # Goals: # - Format provided disk as HFS+ GPT @@ -341,6 +344,29 @@ def generate_installer_creation_script(script_location, installer_path, disk): # OCLP-Helper once to avoid nagging the user about permissions additional_args = "" + script_location = Path(tmp_location) / Path("Installer.sh") + + # Due to a bug in createinstallmedia, running from '/Applications' may sometimes error: + # 'Failed to extract AssetData/boot/Firmware/Manifests/InstallerBoot/*' + # This affects native Macs as well even when manually invoking createinstallmedia + + # To resolve, we'll copy into our temp directory and run from there + + # Create a new tmp directory + # Our current one is a disk image, thus CoW will not work + global tmp_dir + ia_tmp = tmp_dir.name + + print(f"Creating temporary directory at {ia_tmp}") + # Delete all files in tmp_dir + for file in Path(ia_tmp).glob("*"): + subprocess.run(["rm", "-rf", str(file)]) + + # Copy installer to tmp (use CoW to avoid extra disk writes) + subprocess.run(["cp", "-cR", installer_path, ia_tmp]) + + # Adjust installer_path to point to the copied installer + installer_path = Path(ia_tmp) / Path(Path(installer_path).name) createinstallmedia_path = str(Path(installer_path) / Path("Contents/Resources/createinstallmedia")) plist_path = str(Path(installer_path) / Path("Contents/Info.plist"))