mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-06-21 06:30:52 +10:00
Restructure into package format
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
"""
|
||||
install.py: Installation of OpenCore files to ESP
|
||||
"""
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
import subprocess
|
||||
import applescript
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from .. import constants
|
||||
|
||||
from ..datasets import os_data
|
||||
from ..utilities import utilities
|
||||
|
||||
|
||||
class tui_disk_installation:
|
||||
def __init__(self, versions):
|
||||
self.constants: constants.Constants = versions
|
||||
|
||||
def list_disks(self):
|
||||
all_disks = {}
|
||||
# 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
|
||||
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"], "partitions": {}}
|
||||
for partition in disk["Partitions"]:
|
||||
partition_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", partition["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
all_disks[disk["DeviceIdentifier"]]["partitions"][partition["DeviceIdentifier"]] = {
|
||||
"fs": partition_info.get("FilesystemType", partition_info["Content"]),
|
||||
"type": partition_info["Content"],
|
||||
"name": partition_info.get("VolumeName", ""),
|
||||
"size": partition_info["TotalSize"],
|
||||
}
|
||||
except KeyError:
|
||||
# Avoid crashing with CDs installed
|
||||
continue
|
||||
|
||||
supported_disks = {}
|
||||
for disk in all_disks:
|
||||
if not any(all_disks[disk]["partitions"][partition]["fs"] in ("msdos", "EFI") for partition in all_disks[disk]["partitions"]):
|
||||
continue
|
||||
supported_disks.update({
|
||||
disk: {
|
||||
"disk": disk,
|
||||
"name": all_disks[disk]["name"],
|
||||
"size": utilities.human_fmt(all_disks[disk]['size']),
|
||||
"partitions": all_disks[disk]["partitions"]
|
||||
}
|
||||
})
|
||||
return supported_disks
|
||||
|
||||
def list_partitions(self, disk_response, supported_disks):
|
||||
# Takes disk UUID as well as diskutil dataset generated by list_disks
|
||||
# Returns list of FAT32 partitions
|
||||
disk_identifier = disk_response
|
||||
selected_disk = supported_disks[disk_identifier]
|
||||
|
||||
supported_partitions = {}
|
||||
|
||||
for partition in selected_disk["partitions"]:
|
||||
if selected_disk["partitions"][partition]["fs"] not in ("msdos", "EFI"):
|
||||
continue
|
||||
supported_partitions.update({
|
||||
partition: {
|
||||
"partition": partition,
|
||||
"name": selected_disk["partitions"][partition]["name"],
|
||||
"size": utilities.human_fmt(selected_disk["partitions"][partition]["size"])
|
||||
}
|
||||
})
|
||||
return supported_partitions
|
||||
|
||||
|
||||
def _determine_sd_card(self, media_name: str):
|
||||
# Array filled with common SD Card names
|
||||
# Note most USB-based SD Card readers generally report as "Storage Device"
|
||||
# Thus no reliable way to detect further without parsing IOService output (kUSBProductString)
|
||||
if any(x in media_name for x in ("SD Card", "SD/MMC", "SDXC Reader", "SD Reader", "Card Reader")):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def install_opencore(self, full_disk_identifier: str):
|
||||
# TODO: Apple Script fails in Yosemite(?) and older
|
||||
logging.info(f"Mounting partition: {full_disk_identifier}")
|
||||
if self.constants.detected_os >= os_data.os_data.el_capitan and not self.constants.recovery_status:
|
||||
try:
|
||||
applescript.AppleScript(f'''do shell script "diskutil mount {full_disk_identifier}" with prompt "OpenCore Legacy Patcher needs administrator privileges to mount this volume." with administrator privileges without altering line endings''').run()
|
||||
except applescript.ScriptError as e:
|
||||
if "User canceled" in str(e):
|
||||
logging.info("Mount cancelled by user")
|
||||
return
|
||||
logging.info(f"An error occurred: {e}")
|
||||
if utilities.check_boot_mode() == "safe_boot":
|
||||
logging.info("\nSafe Mode detected. FAT32 is unsupported by macOS in this mode.")
|
||||
logging.info("Please disable Safe Mode and try again.")
|
||||
return
|
||||
else:
|
||||
result = subprocess.run(["/usr/sbin/diskutil", "mount", full_disk_identifier], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode != 0:
|
||||
logging.info("Mount failed")
|
||||
logging.info(result.stderr.decode())
|
||||
return
|
||||
|
||||
partition_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", full_disk_identifier], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
parent_disk = partition_info["ParentWholeDisk"]
|
||||
drive_host_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", parent_disk], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
sd_type = drive_host_info["MediaName"]
|
||||
try:
|
||||
ssd_type = drive_host_info["SolidState"]
|
||||
except KeyError:
|
||||
ssd_type = False
|
||||
mount_path = Path(partition_info["MountPoint"])
|
||||
disk_type = partition_info["BusProtocol"]
|
||||
|
||||
if not mount_path.exists():
|
||||
logging.info("EFI failed to mount!")
|
||||
return False
|
||||
|
||||
if (mount_path / Path("EFI/OC")).exists():
|
||||
logging.info("Removing preexisting EFI/OC folder")
|
||||
subprocess.run(["/bin/rm", "-rf", mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if (mount_path / Path("System")).exists():
|
||||
logging.info("Removing preexisting System folder")
|
||||
subprocess.run(["/bin/rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if (mount_path / Path("boot.efi")).exists():
|
||||
logging.info("Removing preexisting boot.efi")
|
||||
subprocess.run(["/bin/rm", mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
logging.info("Copying OpenCore onto EFI partition")
|
||||
subprocess.run(["/bin/mkdir", "-p", mount_path / Path("EFI")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
subprocess.run(["/bin/cp", "-r", self.constants.opencore_release_folder / Path("EFI/OC"), mount_path / Path("EFI/OC")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
subprocess.run(["/bin/cp", "-r", self.constants.opencore_release_folder / Path("System"), mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if Path(self.constants.opencore_release_folder / Path("boot.efi")).exists():
|
||||
subprocess.run(["/bin/cp", self.constants.opencore_release_folder / Path("boot.efi"), mount_path / Path("boot.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if self.constants.boot_efi is True:
|
||||
logging.info("Converting Bootstrap to BOOTx64.efi")
|
||||
if (mount_path / Path("EFI/BOOT")).exists():
|
||||
subprocess.run(["/bin/rm", "-rf", mount_path / Path("EFI/BOOT")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
Path(mount_path / Path("EFI/BOOT")).mkdir()
|
||||
subprocess.run(["/bin/mv", mount_path / Path("System/Library/CoreServices/boot.efi"), mount_path / Path("EFI/BOOT/BOOTx64.efi")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
subprocess.run(["/bin/rm", "-rf", mount_path / Path("System")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if self._determine_sd_card(sd_type) is True:
|
||||
logging.info("Adding SD Card icon")
|
||||
subprocess.run(["/bin/cp", self.constants.icon_path_sd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
elif ssd_type is True:
|
||||
logging.info("Adding SSD icon")
|
||||
subprocess.run(["/bin/cp", self.constants.icon_path_ssd, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
elif disk_type == "USB":
|
||||
logging.info("Adding External USB Drive icon")
|
||||
subprocess.run(["/bin/cp", self.constants.icon_path_external, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
else:
|
||||
logging.info("Adding Internal Drive icon")
|
||||
subprocess.run(["/bin/cp", self.constants.icon_path_internal, mount_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
logging.info("Cleaning install location")
|
||||
if not self.constants.recovery_status:
|
||||
logging.info("Unmounting EFI partition")
|
||||
subprocess.run(["/usr/sbin/diskutil", "umount", mount_path], stdout=subprocess.PIPE).stdout.decode().strip().encode()
|
||||
|
||||
logging.info("OpenCore transfer complete")
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user