Skip to content
This repository has been archived by the owner on Jul 17, 2024. It is now read-only.

Commit

Permalink
dortania#922, not sure if it works completely
Browse files Browse the repository at this point in the history
  • Loading branch information
CleverLemming1337 committed Jul 12, 2024
1 parent 18157fe commit 4496851
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 39 deletions.
4 changes: 4 additions & 0 deletions opencore_legacy_patcher/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ def link_rate_driver_path(self):
def installer_sh_path(self):
return self.payload_path / Path("Installer.sh")

@property
def installer_partition_sh_path(self):
return self.payload_path / Path("Installer_partition.sh")

# Kexts
@property
def payload_kexts_path(self):
Expand Down
101 changes: 72 additions & 29 deletions opencore_legacy_patcher/support/macos_installer_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def generate_installer_creation_script(self, tmp_location: str, installer_path:
return False


def list_disk_to_format(self) -> dict:
def list_disk_to_format(self, show_all: bool = False) -> dict:
"""
List applicable disks for macOS installer creation
Only lists disks that are:
Expand All @@ -184,39 +184,82 @@ def list_disk_to_format(self) -> dict:
all_disks: dict = {}
list_disks: dict = {}

# TODO: AllDisksAndPartitions is not supported in Snow Leopard and older
try:
# High Sierra and newer
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist", "physical"], stdout=subprocess.PIPE).stdout.decode().strip().encode())
except ValueError:
# Sierra and older
if show_all:
# TODO: AllDisksAndPartitions is not supported in Snow Leopard and older
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist"], stdout=subprocess.PIPE).stdout.decode().strip().encode())


for disk in disks["AllDisksAndPartitions"]:
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
try:
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info["MediaName"], "size": disk_info["TotalSize"], "removable": disk_info["Internal"], "partitions": {}}
except KeyError:
# Avoid crashing with CDs installed
continue


for disk in disks['AllDisksAndPartitions']:
disk_id = disk['DeviceIdentifier']

# Strip internal disks (avoid user formatting their SSD/HDD)
# Ensure user doesn't format their boot drive
if not any(all_disks[disk_id]['removable'] is False for partition in all_disks[disk_id]):
continue

for disk in disks["AllDisksAndPartitions"]:
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
# If disk is an APFS container, use APFSVolumes, else Partitions
parts = disk["Partitions"] if "APFSVolumes" not in disk.keys() else disk['APFSVolumes']

for part in parts:
# Strip disks that are under 14GB (15,032,385,536 bytes)
# createinstallmedia isn't great at detecting if a disk has enough space
if not part['Size'] > 15_032_385_536:
continue

try:

list_disks.update({
part['DeviceIdentifier']: {
"identifier": part['DeviceIdentifier'],
"name": part['VolumeName'],
"size": part['Size'],
}
})
except KeyError:
# This error occurs at `part['VolumeName']` and means that the disk is an APFS container
continue
else:
try:
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info["MediaName"], "size": disk_info["TotalSize"], "removable": disk_info["Internal"], "partitions": {}}
except KeyError:
# Avoid crashing with CDs installed
continue
# High Sierra and newer
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist", "physical"], stdout=subprocess.PIPE).stdout.decode().strip().encode())
except ValueError:
# Sierra and older
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist"], stdout=subprocess.PIPE).stdout.decode().strip().encode())

for disk in all_disks:
# Strip disks that are under 14GB (15,032,385,536 bytes)
# createinstallmedia isn't great at detecting if a disk has enough space
if not any(all_disks[disk]['size'] > 15032385536 for partition in all_disks[disk]):
continue
# Strip internal disks as well (avoid user formatting their SSD/HDD)
# Ensure user doesn't format their boot drive
if not any(all_disks[disk]['removable'] is False for partition in all_disks[disk]):
continue
for disk in disks["AllDisksAndPartitions"]:
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
try:
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info["MediaName"], "size": disk_info["TotalSize"], "removable": disk_info["Internal"], "partitions": {}}
except KeyError:
# Avoid crashing with CDs installed
continue

list_disks.update({
disk: {
"identifier": all_disks[disk]["identifier"],
"name": all_disks[disk]["name"],
"size": all_disks[disk]["size"],
}
})
for disk in all_disks:
# Strip disks that are under 14GB (15,032,385,536 bytes)
# createinstallmedia isn't great at detecting if a disk has enough space
if not any(all_disks[disk]['size'] > 15032385536 for partition in all_disks[disk]):
continue
# Strip internal disks as well (avoid user formatting their SSD/HDD)
# Ensure user doesn't format their boot drive
if not any(all_disks[disk]['removable'] is False for partition in all_disks[disk]):
continue

list_disks.update({
disk: {
"identifier": all_disks[disk]["identifier"],
"name": all_disks[disk]["name"],
"size": all_disks[disk]["size"],
}
})

return list_disks

Expand Down
31 changes: 21 additions & 10 deletions opencore_legacy_patcher/wx_gui/gui_macos_installer_flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def fetch_installers():
self.frame_modal = frame_modal


def on_select(self, installer: dict) -> None:
def on_select(self, installer: dict, show_all: bool = False) -> None:
logging.info(f"Selected installer: {installer['Short Name']} ({installer['Version']} ({installer['Build']}))")
self.frame_modal.Destroy()

Expand All @@ -165,7 +165,8 @@ def on_select(self, installer: dict) -> None:

# Fetch local disks
def _fetch_disks():
self.available_disks = macos_installer_handler.InstallerCreation().list_disk_to_format()
print(f"Fetching disks with show_all = {show_all}")
self.available_disks = macos_installer_handler.InstallerCreation().list_disk_to_format(show_all)

# Need to clean up output on pre-Sierra
# Disk images are mixed in with regular disks (ex. payloads.dmg)
Expand Down Expand Up @@ -201,7 +202,7 @@ def _fetch_disks():
for disk in self.available_disks:
logging.info(f" - {disk}: {self.available_disks[disk]['name']} - {utilities.human_fmt(self.available_disks[disk]['size'])}")
disk_button = wx.Button(self.frame_modal, label=f"{disk}: {self.available_disks[disk]['name']} - {utilities.human_fmt(self.available_disks[disk]['size'])}", pos=(-1, warning_label.GetPosition()[1] + warning_label.GetSize()[1] + spacer), size=(300, 30))
disk_button.Bind(wx.EVT_BUTTON, lambda event, temp=disk: self.on_select_disk(self.available_disks[temp], installer))
disk_button.Bind(wx.EVT_BUTTON, lambda event, temp=disk: self.on_select_disk(self.available_disks[temp], installer, show_all))
disk_button.Centre(wx.HORIZONTAL)
if entries == 1:
disk_button.SetDefault()
Expand All @@ -221,15 +222,22 @@ def _fetch_disks():
cancel_button.Bind(wx.EVT_BUTTON, self.on_return_to_main_menu)
cancel_button.Centre(wx.HORIZONTAL)

# Show all disks
show_all_checkbox = wx.CheckBox(self.frame_modal, label="Show all disks (Beta)", pos=(-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] - 10), size=(150, 30))
show_all_checkbox.Centre(wx.HORIZONTAL)
if show_all is True:
show_all_checkbox.SetValue(True)
show_all_checkbox.Bind(wx.EVT_CHECKBOX, lambda event, temp=installer: self.on_select(temp, show_all_checkbox.GetValue()))

# Set size of frame
self.frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40))
self.frame_modal.SetSize((-1, show_all_checkbox.GetPosition()[1] + show_all_checkbox.GetSize()[1] + 40))

progress_bar_animation.stop_pulse()

self.frame_modal.ShowWindowModal()


def on_select_disk(self, disk: dict, installer: dict) -> None:
def on_select_disk(self, disk: dict, installer: dict, is_partition: bool = False) -> None:
answer = wx.MessageBox(f"Are you sure you want to erase '{disk['name']}'?\nAll data will be lost, this cannot be undone.", "Confirmation", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
if answer != wx.YES:
return
Expand Down Expand Up @@ -293,19 +301,22 @@ def on_select_disk(self, disk: dict, installer: dict) -> None:

# /dev/diskX -> diskX
root_disk = disk['identifier'][5:]
initial_bytes_written = float(utilities.monitor_disk_output(root_disk))

# TODO: get value for single partition
initial_bytes_written = float(utilities.monitor_disk_output(root_disk)) if not is_partition else 0 # Workaround. iostat does not support single volumes
self.result = False
def _flash():
logging.info(f"Flashing {installer['Path']} to {root_disk}")
self.result = self._flash_installer(root_disk)
self.result = self._flash_installer(root_disk, is_partition)

thread = threading.Thread(target=_flash)
thread.start()

# Wait for installer to be created
while thread.is_alive():
try:
total_bytes_written = float(utilities.monitor_disk_output(root_disk))
# TODO: get value for single partition
total_bytes_written = float(utilities.monitor_disk_output(root_disk)) if not is_partition else 0 # Workaround. iostat does not support single volumes
except:
total_bytes_written = initial_bytes_written
bytes_written = total_bytes_written - initial_bytes_written
Expand Down Expand Up @@ -374,7 +385,7 @@ def prepare_script(self, installer_path: str, disk: str, constants: constants.Co
return self.prepare_result


def _flash_installer(self, disk) -> bool:
def _flash_installer(self, disk, is_partition: bool = False) -> bool:
utilities.disable_sleep_while_running()
logging.info("Creating macOS installer")

Expand All @@ -385,7 +396,7 @@ def _flash_installer(self, disk) -> bool:
with open(self.constants.installer_sh_path, "r") as f:
logging.info(f"installer.sh contents:\n{f.read()}")

args = ["/bin/sh", self.constants.installer_sh_path]
args = ["/bin/sh", self.constants.installer_partition_sh_path if is_partition else self.constants.installer_sh_path]
result = subprocess_wrapper.run_as_root(args, capture_output=True, text=True)
output = result.stdout
error = result.stderr if result.stderr else ""
Expand Down
6 changes: 6 additions & 0 deletions payloads/Installer_partition.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
erase_disk='diskutil eraseVolume HFS+ OCLP-Installer disk6s1'
if $erase_disk; then
"/var/folders/9z/wfwv_7q13gs9wq0q1r7l8l040000gq/T/tmp43d907_y/Install macOS Sonoma.app/Contents/Resources/createinstallmedia" --volume /Volumes/OCLP-Installer --nointeraction
fi

0 comments on commit 4496851

Please sign in to comment.