mirror of
https://github.com/sickcodes/Docker-OSX.git
synced 2025-06-21 17:12:47 +02:00
Jules was unable to complete the task in time. Please review the work done so far and provide feedback for Jules to continue.
This commit is contained in:
parent
f4d5cd9daf
commit
a77d30aab1
@ -1,6 +1,6 @@
|
|||||||
# Skyscope macOS on PC USB Creator Tool
|
# Skyscope macOS on PC USB Creator Tool
|
||||||
|
|
||||||
**Version:** 0.8.0 (Alpha)
|
**Version:** 0.8.1 (Alpha)
|
||||||
**Developer:** Miss Casey Jay Topojani
|
**Developer:** Miss Casey Jay Topojani
|
||||||
**Business:** Skyscope Sentinel Intelligence
|
**Business:** Skyscope Sentinel Intelligence
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ This tool provides a graphical user interface to automate the creation of a boot
|
|||||||
* Creates an EFI System Partition (ESP) and a main HFS+ partition for macOS.
|
* Creates an EFI System Partition (ESP) and a main HFS+ partition for macOS.
|
||||||
* Copies EFI files and writes the macOS system image.
|
* Copies EFI files and writes the macOS system image.
|
||||||
* Warning prompts before destructive operations like USB writing.
|
* Warning prompts before destructive operations like USB writing.
|
||||||
|
* Experimental `config.plist` auto-enhancement based on detected host hardware (currently Linux-only for hardware detection) to potentially improve iGPU, audio, and Ethernet compatibility, and handle NVIDIA GTX 970 specifics. A backup of the original `config.plist` is created.
|
||||||
|
|
||||||
## Current Status & Known Issues/Limitations
|
## Current Status & Known Issues/Limitations
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ This tool provides a graphical user interface to automate the creation of a boot
|
|||||||
* **Intel iGPU Compatibility:** Relies on the generic iGPU support provided by WhateverGreen.kext within the OpenCore configuration from Docker-OSX. This works for many iGPUs but isn't guaranteed for all without specific `config.plist` tuning.
|
* **Intel iGPU Compatibility:** Relies on the generic iGPU support provided by WhateverGreen.kext within the OpenCore configuration from Docker-OSX. This works for many iGPUs but isn't guaranteed for all without specific `config.plist` tuning.
|
||||||
* **Dependency on Docker-OSX:** This tool orchestrates Docker-OSX. Changes or issues in the upstream Docker-OSX project might affect this tool.
|
* **Dependency on Docker-OSX:** This tool orchestrates Docker-OSX. Changes or issues in the upstream Docker-OSX project might affect this tool.
|
||||||
* **Elevated Privileges:** For USB writing on Linux, the application currently requires being run with `sudo`. It does not yet have in-app checks or prompts for this.
|
* **Elevated Privileges:** For USB writing on Linux, the application currently requires being run with `sudo`. It does not yet have in-app checks or prompts for this.
|
||||||
|
* `config.plist` auto-enhancement is experimental. The hardware detection component for this feature is **currently only implemented for Linux hosts**. While the modification logic is called on macOS, it will not apply hardware-specific changes due to lack of macOS hardware detection in `plist_modifier.py`. Modifications are based on common configurations and may not be optimal for all hardware. Always test thoroughly. A backup of the original `config.plist` (as `config.plist.backup`) is created in the source OpenCore image's EFI directory before modification attempts.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ This tool provides a graphical user interface to automate the creation of a boot
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install qemu-utils parted kpartx rsync dosfstools hfsprogs util-linux
|
sudo apt install qemu-utils parted kpartx rsync dosfstools hfsprogs util-linux
|
||||||
```
|
```
|
||||||
* For `apfs-fuse` on Debian/Ubuntu, you may need to search for a PPA or compile it from its source (e.g., from GitHub). Ensure it's in your PATH.
|
* For `apfs-fuse` on Debian/Ubuntu (including Debian 13 Trixie), you will likely need to compile it from its source (e.g., from the `sgan81/apfs-fuse` repository on GitHub). Typical build dependencies include `git g++ cmake libfuse3-dev libicu-dev zlib1g-dev libbz2-dev libssl-dev` (package names may vary slightly, e.g. `libfuse-dev`). Ensure the compiled `apfs-fuse` binary is in your system PATH.
|
||||||
|
|
||||||
## How to Run
|
## How to Run
|
||||||
|
|
||||||
@ -91,6 +93,7 @@ This tool provides a graphical user interface to automate the creation of a boot
|
|||||||
* Click "Refresh List" to scan for USB drives.
|
* Click "Refresh List" to scan for USB drives.
|
||||||
* Select your intended USB drive from the dropdown. **VERIFY CAREFULLY!**
|
* Select your intended USB drive from the dropdown. **VERIFY CAREFULLY!**
|
||||||
* **WARNING:** The next step will erase all data on the selected USB drive.
|
* **WARNING:** The next step will erase all data on the selected USB drive.
|
||||||
|
* Optionally, check the '\[Experimental] Auto-enhance config.plist...' box if you want the tool to attempt to modify the OpenCore configuration based on your Linux host's hardware (this feature is Linux-only for detection). This may improve compatibility but use with caution. A backup (`config.plist.backup`) is created in the source OpenCore image's EFI directory before modification.
|
||||||
* If you are on Linux and have all dependencies, and the images from Step 2 are ready, the "Write Images to USB Drive" button will be enabled.
|
* If you are on Linux and have all dependencies, and the images from Step 2 are ready, the "Write Images to USB Drive" button will be enabled.
|
||||||
* Click it and confirm the warning dialog. The application will then partition the USB and write the images. This will take a significant amount of time.
|
* Click it and confirm the warning dialog. The application will then partition the USB and write the images. This will take a significant amount of time.
|
||||||
|
|
||||||
@ -101,6 +104,8 @@ This tool provides a graphical user interface to automate the creation of a boot
|
|||||||
* **Privilege Handling:** Add checks to see if the application is run with necessary privileges for USB writing and guide the user if not.
|
* **Privilege Handling:** Add checks to see if the application is run with necessary privileges for USB writing and guide the user if not.
|
||||||
* **USB Writing for macOS and Windows:** Implement the `usb_writer_macos.py` and `usb_writer_windows.py` modules.
|
* **USB Writing for macOS and Windows:** Implement the `usb_writer_macos.py` and `usb_writer_windows.py` modules.
|
||||||
* **GUI for Advanced Options:** Potentially allow users to specify custom Docker parameters or OpenCore properties.
|
* **GUI for Advanced Options:** Potentially allow users to specify custom Docker parameters or OpenCore properties.
|
||||||
|
* **Expand hardware detection for `config.plist` enhancement to also support macOS and Windows hosts.**
|
||||||
|
* **Provide more granular user control and detailed feedback for the `config.plist` enhancement feature (e.g., preview changes, select specific patches).**
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
139
linux_hardware_info.py
Normal file
139
linux_hardware_info.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# linux_hardware_info.py
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
|
def _run_command(command: list[str]) -> str:
|
||||||
|
"""Helper to run a command and return its stdout."""
|
||||||
|
try:
|
||||||
|
process = subprocess.run(command, capture_output=True, text=True, check=True)
|
||||||
|
return process.stdout
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: Command '{command[0]}' not found. Is 'pciutils' (for lspci) installed?")
|
||||||
|
return ""
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error executing {' '.join(command)}: {e.stderr}")
|
||||||
|
return ""
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred with command {' '.join(command)}: {e}")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_pci_devices_info() -> list[dict]:
|
||||||
|
"""
|
||||||
|
Gets a list of dictionaries, each containing info about a PCI device,
|
||||||
|
focusing on VGA, Audio, and Ethernet controllers.
|
||||||
|
Output format for relevant devices:
|
||||||
|
{'type': 'VGA', 'vendor_id': '10de', 'device_id': '13c2', 'description': 'NVIDIA GTX 970'}
|
||||||
|
{'type': 'Audio', 'vendor_id': '8086', 'device_id': 'a170', 'description': 'Intel Sunrise Point-H HD Audio'}
|
||||||
|
{'type': 'Ethernet', 'vendor_id': '8086', 'device_id': '15b8', 'description': 'Intel Ethernet Connection I219-V'}
|
||||||
|
"""
|
||||||
|
output = _run_command(["lspci", "-nnk"])
|
||||||
|
if not output:
|
||||||
|
return []
|
||||||
|
|
||||||
|
devices = []
|
||||||
|
# Regex to capture device type (from description), description, and [vendor:device]
|
||||||
|
# Example line: 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1)
|
||||||
|
# Example line: 00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31)
|
||||||
|
# Example line: 00:1f.6 Ethernet controller [0200]: Intel Corporation Ethernet Connection (2) I219-V [8086:15b8] (rev 31)
|
||||||
|
|
||||||
|
# More robust regex:
|
||||||
|
# It captures the class description (like "VGA compatible controller", "Audio device")
|
||||||
|
# and the main device description (like "NVIDIA Corporation GM204 [GeForce GTX 970]")
|
||||||
|
# and the vendor/device IDs like "[10de:13c2]"
|
||||||
|
regex = re.compile(
|
||||||
|
r"^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.\d\s+" # PCI Address (e.g., 01:00.0 )
|
||||||
|
r"(.+?)\s+" # Class Description (e.g., "VGA compatible controller")
|
||||||
|
r"\[[0-9a-fA-F]{4}\]:\s+" # PCI Class Code (e.g., [0300]: )
|
||||||
|
r"(.+?)\s+" # Full Device Description (e.g., "NVIDIA Corporation GM204 [GeForce GTX 970]")
|
||||||
|
r"\[([0-9a-fA-F]{4}):([0-9a-fA-F]{4})\]" # Vendor and Device ID (e.g., [10de:13c2])
|
||||||
|
)
|
||||||
|
|
||||||
|
for line in output.splitlines():
|
||||||
|
match = regex.search(line)
|
||||||
|
if match:
|
||||||
|
class_desc = match.group(1).strip()
|
||||||
|
full_desc = match.group(2).strip()
|
||||||
|
vendor_id = match.group(3).lower()
|
||||||
|
device_id = match.group(4).lower()
|
||||||
|
|
||||||
|
device_type = None
|
||||||
|
if "VGA compatible controller" in class_desc or "3D controller" in class_desc:
|
||||||
|
device_type = "VGA"
|
||||||
|
elif "Audio device" in class_desc:
|
||||||
|
device_type = "Audio"
|
||||||
|
elif "Ethernet controller" in class_desc:
|
||||||
|
device_type = "Ethernet"
|
||||||
|
elif "Network controller" in class_desc: # Could be Wi-Fi
|
||||||
|
device_type = "Network (Wi-Fi?)"
|
||||||
|
|
||||||
|
|
||||||
|
if device_type:
|
||||||
|
# Try to get a cleaner description if possible, removing vendor name if it's at the start
|
||||||
|
# e.g. "Intel Corporation Ethernet Connection (2) I219-V" -> "Ethernet Connection (2) I219-V"
|
||||||
|
# This is a simple attempt.
|
||||||
|
cleaned_desc = full_desc
|
||||||
|
if full_desc.lower().startswith("intel corporation "):
|
||||||
|
cleaned_desc = full_desc[len("intel corporation "):]
|
||||||
|
elif full_desc.lower().startswith("nvidia corporation "):
|
||||||
|
cleaned_desc = full_desc[len("nvidia corporation "):]
|
||||||
|
elif full_desc.lower().startswith("advanced micro devices, inc.") or full_desc.lower().startswith("amd"):
|
||||||
|
# Handle different AMD namings
|
||||||
|
if full_desc.lower().startswith("advanced micro devices, inc."):
|
||||||
|
cleaned_desc = re.sub(r"Advanced Micro Devices, Inc\.\s*\[AMD/ATI\]\s*", "", full_desc, flags=re.IGNORECASE)
|
||||||
|
else: # Starts with AMD
|
||||||
|
cleaned_desc = re.sub(r"AMD\s*\[ATI\]\s*", "", full_desc, flags=re.IGNORECASE)
|
||||||
|
elif full_desc.lower().startswith("realtek semiconductor co., ltd."):
|
||||||
|
cleaned_desc = full_desc[len("realtek semiconductor co., ltd. "):]
|
||||||
|
|
||||||
|
|
||||||
|
devices.append({
|
||||||
|
"type": device_type,
|
||||||
|
"vendor_id": vendor_id,
|
||||||
|
"device_id": device_id,
|
||||||
|
"description": cleaned_desc.strip(),
|
||||||
|
"full_lspci_line": line.strip() # For debugging or more info
|
||||||
|
})
|
||||||
|
return devices
|
||||||
|
|
||||||
|
def get_cpu_info() -> dict:
|
||||||
|
"""
|
||||||
|
Gets CPU information using lscpu.
|
||||||
|
Returns a dictionary with 'Model name', 'Vendor ID', 'CPU family', 'Model', 'Stepping', 'Flags'.
|
||||||
|
"""
|
||||||
|
output = _run_command(["lscpu"])
|
||||||
|
if not output:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
info = {}
|
||||||
|
# Regex to capture key-value pairs from lscpu output
|
||||||
|
# Handles spaces in values for "Model name"
|
||||||
|
regex = re.compile(r"^(CPU family|Model name|Vendor ID|Model|Stepping|Flags):\s+(.*)$")
|
||||||
|
for line in output.splitlines():
|
||||||
|
match = regex.match(line)
|
||||||
|
if match:
|
||||||
|
key = match.group(1).strip()
|
||||||
|
value = match.group(2).strip()
|
||||||
|
info[key] = value
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("--- PCI Devices ---")
|
||||||
|
pci_devs = get_pci_devices_info()
|
||||||
|
if pci_devs:
|
||||||
|
for dev in pci_devs:
|
||||||
|
print(f" Type: {dev['type']}")
|
||||||
|
print(f" Vendor ID: {dev['vendor_id']}")
|
||||||
|
print(f" Device ID: {dev['device_id']}")
|
||||||
|
print(f" Description: {dev['description']}")
|
||||||
|
# print(f" Full Line: {dev['full_lspci_line']}")
|
||||||
|
else:
|
||||||
|
print(" No relevant PCI devices found or lspci not available.")
|
||||||
|
|
||||||
|
print("\n--- CPU Info ---")
|
||||||
|
cpu_info = get_cpu_info()
|
||||||
|
if cpu_info:
|
||||||
|
for key, value in cpu_info.items():
|
||||||
|
print(f" {key}: {value}")
|
||||||
|
else:
|
||||||
|
print(" Could not retrieve CPU info or lscpu not available.")
|
83
main_app.py
83
main_app.py
@ -10,10 +10,10 @@ import json # For parsing PowerShell JSON output
|
|||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QLabel, QComboBox, QPushButton, QTextEdit, QMessageBox, QMenuBar,
|
QLabel, QComboBox, QPushButton, QTextEdit, QMessageBox, QMenuBar,
|
||||||
QFileDialog, QGroupBox, QLineEdit, QProgressBar # Added QProgressBar
|
QFileDialog, QGroupBox, QLineEdit, QProgressBar, QCheckBox # Added QCheckBox
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import QAction
|
from PyQt6.QtGui import QAction
|
||||||
from PyQt6.QtCore import pyqtSignal, pyqtSlot, QObject, QThread, Qt # Added Qt
|
from PyQt6.QtCore import pyqtSignal, pyqtSlot, QObject, QThread, Qt
|
||||||
|
|
||||||
# ... (Worker classes and other imports remain the same) ...
|
# ... (Worker classes and other imports remain the same) ...
|
||||||
from constants import APP_NAME, DEVELOPER_NAME, BUSINESS_NAME, MACOS_VERSIONS, DOCKER_IMAGE_BASE
|
from constants import APP_NAME, DEVELOPER_NAME, BUSINESS_NAME, MACOS_VERSIONS, DOCKER_IMAGE_BASE
|
||||||
@ -96,9 +96,17 @@ class DockerCommandWorker(QObject): # ... ( 그대로 )
|
|||||||
except FileNotFoundError: self.signals.error.emit("Error: Docker command not found.")
|
except FileNotFoundError: self.signals.error.emit("Error: Docker command not found.")
|
||||||
except Exception as e: self.signals.error.emit(f"An error occurred: {str(e)}")
|
except Exception as e: self.signals.error.emit(f"An error occurred: {str(e)}")
|
||||||
|
|
||||||
class USBWriterWorker(QObject): # ... ( 그대로 )
|
class USBWriterWorker(QObject):
|
||||||
signals = WorkerSignals()
|
signals = WorkerSignals()
|
||||||
def __init__(self, device, opencore_path, macos_path): super().__init__(); self.device, self.opencore_path, self.macos_path = device, opencore_path, macos_path; self.writer_instance = None
|
def __init__(self, device, opencore_path, macos_path, enhance_plist: bool, target_macos_version: str): # Added new args
|
||||||
|
super().__init__()
|
||||||
|
self.device = device
|
||||||
|
self.opencore_path = opencore_path
|
||||||
|
self.macos_path = macos_path
|
||||||
|
self.enhance_plist = enhance_plist # Store
|
||||||
|
self.target_macos_version = target_macos_version # Store
|
||||||
|
self.writer_instance = None
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def run(self):
|
def run(self):
|
||||||
current_os = platform.system()
|
current_os = platform.system()
|
||||||
@ -107,11 +115,24 @@ class USBWriterWorker(QObject): # ... ( 그대로 )
|
|||||||
if current_os == "Linux": writer_cls = USBWriterLinux
|
if current_os == "Linux": writer_cls = USBWriterLinux
|
||||||
elif current_os == "Darwin": writer_cls = USBWriterMacOS
|
elif current_os == "Darwin": writer_cls = USBWriterMacOS
|
||||||
elif current_os == "Windows": writer_cls = USBWriterWindows
|
elif current_os == "Windows": writer_cls = USBWriterWindows
|
||||||
if writer_cls is None: self.signals.error.emit(f"{current_os} USB writer module not available or OS not supported."); return
|
|
||||||
self.writer_instance = writer_cls(self.device, self.opencore_path, self.macos_path, lambda msg: self.signals.progress.emit(msg))
|
if writer_cls is None:
|
||||||
if self.writer_instance.format_and_write(): self.signals.finished.emit("USB writing process completed successfully.")
|
self.signals.error.emit(f"{current_os} USB writer module not available or OS not supported."); return
|
||||||
else: self.signals.error.emit("USB writing process failed. Check output for details.")
|
|
||||||
except Exception as e: self.signals.error.emit(f"USB writing preparation error: {str(e)}")
|
# Pass new args to platform writer constructor
|
||||||
|
self.writer_instance = writer_cls(
|
||||||
|
self.device, self.opencore_path, self.macos_path,
|
||||||
|
progress_callback=lambda msg: self.signals.progress.emit(msg), # Ensure progress_callback is named if it's a kwarg in writers
|
||||||
|
enhance_plist_enabled=self.enhance_plist,
|
||||||
|
target_macos_version=self.target_macos_version
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.writer_instance.format_and_write():
|
||||||
|
self.signals.finished.emit("USB writing process completed successfully.")
|
||||||
|
else:
|
||||||
|
self.signals.error.emit("USB writing process failed. Check output for details.")
|
||||||
|
except Exception as e:
|
||||||
|
self.signals.error.emit(f"USB writing preparation error: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
@ -178,6 +199,14 @@ class MainWindow(QMainWindow):
|
|||||||
self.usb_layout.addWidget(self.windows_disk_id_input)
|
self.usb_layout.addWidget(self.windows_disk_id_input)
|
||||||
# Visibility will be toggled in refresh_usb_drives based on OS
|
# Visibility will be toggled in refresh_usb_drives based on OS
|
||||||
|
|
||||||
|
self.enhance_plist_checkbox = QCheckBox("Try to auto-enhance config.plist for this system's hardware (Experimental, Linux Host Only for detection)")
|
||||||
|
self.enhance_plist_checkbox.setChecked(False) # Off by default
|
||||||
|
self.enhance_plist_checkbox.setToolTip(
|
||||||
|
"If checked, attempts to modify the OpenCore config.plist based on detected host hardware (Linux only for detection part).\n"
|
||||||
|
"This might improve compatibility for iGPU, audio, Ethernet. Use with caution."
|
||||||
|
)
|
||||||
|
self.usb_layout.addWidget(self.enhance_plist_checkbox)
|
||||||
|
|
||||||
warning_label = QLabel("WARNING: Selecting a drive and proceeding to write will ERASE ALL DATA on it!")
|
warning_label = QLabel("WARNING: Selecting a drive and proceeding to write will ERASE ALL DATA on it!")
|
||||||
warning_label.setStyleSheet("color: red; font-weight: bold;")
|
warning_label.setStyleSheet("color: red; font-weight: bold;")
|
||||||
self.usb_layout.addWidget(warning_label)
|
self.usb_layout.addWidget(warning_label)
|
||||||
@ -493,14 +522,18 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.warning(self, "Privileges Required", "This operation requires Administrator/root privileges."); return
|
QMessageBox.warning(self, "Privileges Required", "This operation requires Administrator/root privileges."); return
|
||||||
|
|
||||||
current_os = platform.system(); usb_writer_module = None; target_device_id_for_worker = None
|
current_os = platform.system(); usb_writer_module = None; target_device_id_for_worker = None
|
||||||
|
enhance_plist_enabled = self.enhance_plist_checkbox.isChecked() # Get state
|
||||||
|
target_macos_ver = self.version_combo.currentText() # Get macOS version
|
||||||
|
|
||||||
if current_os == "Windows":
|
if current_os == "Windows":
|
||||||
target_device_id_for_worker = self.usb_drive_combo.currentData() # Disk Index from WMI
|
target_device_id_for_worker = self.usb_drive_combo.currentData() # Disk Index from WMI
|
||||||
if not target_device_id_for_worker: # Fallback to manual input if combo is empty or user chose to use it
|
if not target_device_id_for_worker:
|
||||||
target_device_id_for_worker = self.windows_disk_id_input.text().strip()
|
if self.windows_disk_id_input.isVisible():
|
||||||
if not target_device_id_for_worker: QMessageBox.warning(self, "Input Required", "Please select a USB disk or enter its Disk Number."); return
|
target_device_id_for_worker = self.windows_disk_id_input.text().strip()
|
||||||
if not target_device_id_for_worker.isdigit(): QMessageBox.warning(self, "Input Invalid", "Windows Disk Number must be a digit."); return
|
if not target_device_id_for_worker: QMessageBox.warning(self, "Input Required", "Please select a USB disk or enter its Disk Number."); return
|
||||||
# USBWriterWindows expects just the disk number string (e.g., "1")
|
if not target_device_id_for_worker.isdigit(): QMessageBox.warning(self, "Input Invalid", "Windows Disk Number must be a digit."); return
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "USB Error", "No USB disk selected for Windows."); return
|
||||||
usb_writer_module = USBWriterWindows
|
usb_writer_module = USBWriterWindows
|
||||||
else: # Linux/macOS
|
else: # Linux/macOS
|
||||||
target_device_id_for_worker = self.usb_drive_combo.currentData()
|
target_device_id_for_worker = self.usb_drive_combo.currentData()
|
||||||
@ -512,16 +545,26 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.warning(self, "Missing Images", "Ensure both images are extracted."); return
|
QMessageBox.warning(self, "Missing Images", "Ensure both images are extracted."); return
|
||||||
if not target_device_id_for_worker: QMessageBox.warning(self, "No USB Selected/Identified", f"Please select/identify target USB for {current_os}."); return
|
if not target_device_id_for_worker: QMessageBox.warning(self, "No USB Selected/Identified", f"Please select/identify target USB for {current_os}."); return
|
||||||
|
|
||||||
confirm_msg = (f"WARNING: ALL DATA ON TARGET '{target_device_id_for_worker}' WILL BE ERASED PERMANENTLY.
|
confirm_msg = (f"WARNING: ALL DATA ON TARGET '{target_device_id_for_worker}' WILL BE ERASED PERMANENTLY.\n"
|
||||||
Proceed?");
|
f"Enhance config.plist: {'Yes' if enhance_plist_enabled else 'No'}.\nProceed?")
|
||||||
reply = QMessageBox.warning(self, "Confirm Write Operation", confirm_msg, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.Cancel)
|
reply = QMessageBox.warning(self, "Confirm Write Operation", confirm_msg, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.Cancel)
|
||||||
if reply == QMessageBox.StandardButton.Cancel: self.output_area.append("\nUSB write cancelled."); return
|
if reply == QMessageBox.StandardButton.Cancel: self.output_area.append("\nUSB write cancelled."); return
|
||||||
|
|
||||||
self.output_area.append(f"\n--- Starting USB Write for {target_device_id_for_worker} on {current_os} ---")
|
self.output_area.append(f"\n--- Starting USB Write for {target_device_id_for_worker} on {current_os} ---")
|
||||||
self.write_to_usb_button.setEnabled(False); self.refresh_usb_button.setEnabled(False)
|
if enhance_plist_enabled: self.output_area.append("Attempting config.plist enhancement...")
|
||||||
usb_worker = USBWriterWorker(target_device_id_for_worker, self.extracted_opencore_image_path, self.extracted_main_image_path)
|
|
||||||
if not self._start_worker(usb_worker, self.usb_write_finished, self.usb_write_error, "usb_write_worker"):
|
usb_worker = USBWriterWorker(
|
||||||
self.write_to_usb_button.setEnabled(True); self.refresh_usb_button.setEnabled(True)
|
target_device_id_for_worker,
|
||||||
|
self.extracted_opencore_image_path,
|
||||||
|
self.extracted_main_image_path,
|
||||||
|
enhance_plist_enabled,
|
||||||
|
target_macos_ver
|
||||||
|
)
|
||||||
|
self._start_worker(usb_worker,
|
||||||
|
self.usb_write_finished,
|
||||||
|
self.usb_write_error,
|
||||||
|
"usb_write_worker",
|
||||||
|
f"Writing to USB {target_device_id_for_worker}...")
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def usb_write_finished(self, message): # Specific handler
|
def usb_write_finished(self, message): # Specific handler
|
||||||
|
294
plist_modifier.py
Normal file
294
plist_modifier.py
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
# plist_modifier.py
|
||||||
|
import plistlib
|
||||||
|
import platform
|
||||||
|
import shutil # For backup
|
||||||
|
import os # For path operations
|
||||||
|
|
||||||
|
# Attempt to import hardware info, will only work if run in an environment
|
||||||
|
# where linux_hardware_info.py is accessible and on Linux.
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
try:
|
||||||
|
from linux_hardware_info import get_pci_devices_info, get_cpu_info
|
||||||
|
except ImportError:
|
||||||
|
print("Warning: linux_hardware_info.py not found. Plist enhancement will be limited.")
|
||||||
|
get_pci_devices_info = lambda: [] # Dummy function
|
||||||
|
get_cpu_info = lambda: {} # Dummy function
|
||||||
|
else: # For other OS, create dummy functions so the rest of the module can be parsed
|
||||||
|
print(f"Warning: Hardware info gathering not implemented for {platform.system()} in plist_modifier.")
|
||||||
|
get_pci_devices_info = lambda: []
|
||||||
|
get_cpu_info = lambda: {}
|
||||||
|
|
||||||
|
# --- Illustrative Mappings (Proof of Concept) ---
|
||||||
|
# Keys are VENDOR_ID:DEVICE_ID (lowercase)
|
||||||
|
INTEL_IGPU_DEFAULTS = {
|
||||||
|
# Coffee Lake Desktop (UHD 630)
|
||||||
|
"8086:3e9b": {"AAPL,ig-platform-id": b"\x07\x00\x9B\x3E", "device-id": b"\x9B\x3E\x00\x00", "framebuffer-patch-enable": b"\x01\x00\x00\x00"},
|
||||||
|
# Kaby Lake Desktop (HD 630)
|
||||||
|
"8086:5912": {"AAPL,ig-platform-id": b"\x05\x00\x12\x59", "device-id": b"\x12\x59\x00\x00", "framebuffer-patch-enable": b"\x01\x00\x00\x00"},
|
||||||
|
# Skylake Desktop (HD 530)
|
||||||
|
"8086:1912": {"AAPL,ig-platform-id": b"\x00\x00\x12\x19", "device-id": b"\x12\x19\x00\x00", "framebuffer-patch-enable": b"\x01\x00\x00\x00"},
|
||||||
|
}
|
||||||
|
INTEL_IGPU_PCI_PATH = "PciRoot(0x0)/Pci(0x2,0x0)"
|
||||||
|
|
||||||
|
AUDIO_LAYOUTS = {
|
||||||
|
# Intel HDA - common controllers, layout 1 is a frequent default
|
||||||
|
"8086:a170": 1, # Sunrise Point-H HD Audio
|
||||||
|
"8086:a2f0": 1, # Series 200 HD Audio
|
||||||
|
"8086:a348": 3, # Cannon Point-LP HD Audio
|
||||||
|
"8086:f0c8": 3, # Comet Lake HD Audio
|
||||||
|
# Realtek Codecs (often on Intel HDA controller, actual codec detection is harder)
|
||||||
|
# If a Realtek PCI ID is found for audio, one of these layouts might work.
|
||||||
|
# This map is simplified; usually, you detect the codec name (e.g. ALC255, ALC892)
|
||||||
|
"10ec:0255": 3, # ALC255 Example
|
||||||
|
"10ec:0892": 1, # ALC892 Example
|
||||||
|
}
|
||||||
|
AUDIO_PCI_PATH_FALLBACK = "PciRoot(0x0)/Pci(0x1f,0x3)" # Common, but needs verification
|
||||||
|
|
||||||
|
ETHERNET_KEXT_MAP = {
|
||||||
|
"8086:15b8": "IntelMausi.kext", # Intel I219-V
|
||||||
|
"8086:153a": "IntelMausi.kext", # Intel I217-V
|
||||||
|
"8086:10f0": "IntelMausi.kext", # Intel 82579LM
|
||||||
|
"10ec:8168": "RealtekRTL8111.kext", # Realtek RTL8111/8168
|
||||||
|
"10ec:8111": "RealtekRTL8111.kext",
|
||||||
|
"14e4:1686": "AirportBrcmFixup.kext", # Example Broadcom Wi-Fi (though kext name might be BrcmPatchRAM related)
|
||||||
|
# Proper Ethernet kext for Broadcom depends on model e.g. AppleBCM5701Ethernet.kext
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pci_path_for_device(pci_devices, target_vendor_id, target_device_id_prefix):
|
||||||
|
# This is a placeholder. A real implementation would need to parse lspci's bus info (00:1f.3)
|
||||||
|
# and convert that to an OpenCore PciRoot string. For now, uses fallbacks.
|
||||||
|
# Example: lspci output "00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31)"
|
||||||
|
# PciRoot(0x0)/Pci(0x1f,0x3)
|
||||||
|
# For now, this function is not fully implemented and we'll use hardcoded common paths.
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def enhance_config_plist(plist_path: str, target_macos_version_name: str, progress_callback=None) -> bool:
|
||||||
|
"""
|
||||||
|
Loads a config.plist, gathers hardware info (Linux only for now),
|
||||||
|
applies targeted enhancements, and saves it back.
|
||||||
|
Args:
|
||||||
|
plist_path: Path to the config.plist file.
|
||||||
|
target_macos_version_name: e.g., "Sonoma", "High Sierra". Used for version-specific logic.
|
||||||
|
progress_callback: Optional function to report progress.
|
||||||
|
Returns:
|
||||||
|
True if successful, False otherwise.
|
||||||
|
"""
|
||||||
|
def _report(msg):
|
||||||
|
if progress_callback: progress_callback(f"[PlistModifier] {msg}")
|
||||||
|
else: print(f"[PlistModifier] {msg}")
|
||||||
|
|
||||||
|
_report(f"Starting config.plist enhancement for: {plist_path}")
|
||||||
|
_report(f"Target macOS version: {target_macos_version_name}")
|
||||||
|
|
||||||
|
if not os.path.exists(plist_path):
|
||||||
|
_report(f"Error: Plist file not found at {plist_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Create a backup
|
||||||
|
backup_plist_path = plist_path + ".backup"
|
||||||
|
try:
|
||||||
|
shutil.copy2(plist_path, backup_plist_path)
|
||||||
|
_report(f"Created backup of config.plist at: {backup_plist_path}")
|
||||||
|
except Exception as e:
|
||||||
|
_report(f"Error creating backup for {plist_path}: {e}. Proceeding without backup.")
|
||||||
|
# Decide if this should be a fatal error for the modification step
|
||||||
|
# For now, we'll proceed cautiously.
|
||||||
|
|
||||||
|
if platform.system() != "Linux":
|
||||||
|
_report("Hardware detection for plist enhancement currently only supported on Linux. Skipping hardware-specific modifications.")
|
||||||
|
# Still load and save to ensure plist is valid, but no hardware changes.
|
||||||
|
try:
|
||||||
|
with open(plist_path, 'rb') as f: config_data = plistlib.load(f)
|
||||||
|
# No changes made, so just confirm it's okay.
|
||||||
|
# If we wanted to ensure it's valid and resave (pretty print), we could do:
|
||||||
|
# with open(plist_path, 'wb') as f: plistlib.dump(config_data, f, sort_keys=True)
|
||||||
|
_report("Plist not modified on non-Linux host (hardware detection skipped).")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
_report(f"Error processing plist file {plist_path} even without hardware changes: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(plist_path, 'rb') as f:
|
||||||
|
config_data = plistlib.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
_report(f"Error loading plist file {plist_path} for modification: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
pci_devices = get_pci_devices_info()
|
||||||
|
cpu_info = get_cpu_info() # Currently not used in logic below but fetched
|
||||||
|
|
||||||
|
if not pci_devices: # cpu_info might be empty too
|
||||||
|
_report("Could not retrieve PCI hardware information. Skipping most plist enhancements.")
|
||||||
|
# Still try to save (pretty-print/validate) the plist if loaded.
|
||||||
|
try:
|
||||||
|
with open(plist_path, 'wb') as f: plistlib.dump(config_data, f, sort_keys=True)
|
||||||
|
_report("Plist re-saved (no hardware changes applied due to missing PCI info).")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
_report(f"Error re-saving plist file {plist_path}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Ensure sections exist
|
||||||
|
dev_props = config_data.setdefault("DeviceProperties", {}).setdefault("Add", {})
|
||||||
|
kernel_add = config_data.setdefault("Kernel", {}).setdefault("Add", [])
|
||||||
|
nvram_add = config_data.setdefault("NVRAM", {}).setdefault("Add", {})
|
||||||
|
boot_args_uuid = "7C436110-AB2A-4BBB-A880-FE41995C9F82"
|
||||||
|
boot_args_section = nvram_add.setdefault(boot_args_uuid, {})
|
||||||
|
current_boot_args_str = boot_args_section.get("boot-args", "")
|
||||||
|
boot_args = set(current_boot_args_str.split())
|
||||||
|
modified = False # Flag to track if any changes were made
|
||||||
|
|
||||||
|
# 1. Intel iGPU Enhancement
|
||||||
|
intel_igpu_device_id_on_host = None
|
||||||
|
for dev in pci_devices:
|
||||||
|
if dev['type'] == 'VGA' and dev['vendor_id'] == '8086': # Intel iGPU
|
||||||
|
intel_igpu_device_id_on_host = dev['device_id']
|
||||||
|
lookup_key = f"{dev['vendor_id']}:{dev['device_id']}"
|
||||||
|
if lookup_key in INTEL_IGPU_DEFAULTS:
|
||||||
|
_report(f"Found Intel iGPU: {dev['description']}. Applying properties.")
|
||||||
|
igpu_path_properties = dev_props.setdefault(INTEL_IGPU_PCI_PATH, {})
|
||||||
|
for key, value in INTEL_IGPU_DEFAULTS[lookup_key].items():
|
||||||
|
igpu_path_properties[key] = value
|
||||||
|
_report(f" Set {INTEL_IGPU_PCI_PATH} -> {key}")
|
||||||
|
else:
|
||||||
|
_report(f"Found Intel iGPU: {dev['description']} ({lookup_key}) but no default properties defined for it.")
|
||||||
|
break # Assume only one active iGPU for primary display configuration
|
||||||
|
|
||||||
|
# 2. Audio Enhancement (Layout ID)
|
||||||
|
audio_device_path_in_plist = AUDIO_PCI_PATH_FALLBACK # Default, may need to be dynamic
|
||||||
|
for dev in pci_devices:
|
||||||
|
if dev['type'] == 'Audio':
|
||||||
|
lookup_key = f"{dev['vendor_id']}:{dev['device_id']}"
|
||||||
|
if lookup_key in AUDIO_LAYOUTS:
|
||||||
|
layout_id = AUDIO_LAYOUTS[lookup_key]
|
||||||
|
_report(f"Found Audio device: {dev['description']}. Setting layout-id to {layout_id}.")
|
||||||
|
audio_path_properties = dev_props.setdefault(audio_device_path_in_plist, {})
|
||||||
|
new_layout_data = plistlib.Data(layout_id.to_bytes(1, 'little')) # Common layout IDs are small integers
|
||||||
|
if audio_path_properties.get("layout-id") != new_layout_data:
|
||||||
|
audio_path_properties["layout-id"] = new_layout_data
|
||||||
|
_report(f" Set {audio_device_path_in_plist} -> layout-id = {layout_id}")
|
||||||
|
modified = True
|
||||||
|
for kext in kernel_add: # Ensure AppleALC is enabled
|
||||||
|
if isinstance(kext, dict) and kext.get("BundlePath") == "AppleALC.kext":
|
||||||
|
if not kext.get("Enabled", False):
|
||||||
|
kext["Enabled"] = True; _report(" Ensured AppleALC.kext is enabled."); modified = True
|
||||||
|
break
|
||||||
|
break
|
||||||
|
|
||||||
|
# 3. Ethernet Kext Enablement
|
||||||
|
for dev in pci_devices:
|
||||||
|
if dev['type'] == 'Ethernet':
|
||||||
|
lookup_key = f"{dev['vendor_id']}:{dev['device_id']}"
|
||||||
|
if lookup_key in ETHERNET_KEXT_MAP:
|
||||||
|
kext_name = ETHERNET_KEXT_MAP[lookup_key]; _report(f"Found Ethernet device: {dev['description']}. Will ensure {kext_name} is enabled.")
|
||||||
|
kext_found_and_enabled_or_modified = False
|
||||||
|
for kext_entry in kernel_add:
|
||||||
|
if isinstance(kext_entry, dict) and kext_entry.get("BundlePath") == kext_name:
|
||||||
|
if not kext_entry.get("Enabled", False):
|
||||||
|
kext_entry["Enabled"] = True; _report(f" Enabled {kext_name}."); modified = True
|
||||||
|
else:
|
||||||
|
_report(f" {kext_name} already enabled.")
|
||||||
|
kext_found_and_enabled_or_modified = True; break
|
||||||
|
if not kext_found_and_enabled_or_modified: _report(f" Warning: {kext_name} for {dev['description']} not in Kernel->Add.")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 4. NVIDIA GTX 970 Specific Adjustments
|
||||||
|
gtx_970_present = any(dev['vendor_id'] == '10de' and dev['device_id'] == '13c2' for dev in pci_devices)
|
||||||
|
if gtx_970_present:
|
||||||
|
_report("NVIDIA GTX 970 detected.")
|
||||||
|
is_high_sierra_or_older = target_macos_version_name.lower() in ["high sierra"]
|
||||||
|
original_boot_args_len = len(boot_args) # To check if boot_args actually change
|
||||||
|
if is_high_sierra_or_older:
|
||||||
|
boot_args.add('nvda_drv=1'); boot_args.discard('nv_disable=1')
|
||||||
|
_report(" Configured for NVIDIA Web Drivers (High Sierra target).")
|
||||||
|
else:
|
||||||
|
boot_args.discard('nvda_drv=1')
|
||||||
|
if intel_igpu_device_id_on_host:
|
||||||
|
boot_args.add('nv_disable=1'); _report(f" Added nv_disable=1 for {target_macos_version_name} to prioritize iGPU.")
|
||||||
|
else:
|
||||||
|
boot_args.discard('nv_disable=1'); _report(f" GTX 970 likely only GPU for {target_macos_version_name}. `nv_disable=1` not forced.")
|
||||||
|
# Check if boot_args actually changed before setting modified = True
|
||||||
|
if len(boot_args) != original_boot_args_len or ' '.join(sorted(list(boot_args))) != current_boot_args_str : modified = True
|
||||||
|
|
||||||
|
final_boot_args = ' '.join(sorted(list(boot_args)))
|
||||||
|
if final_boot_args != current_boot_args_str: # Check if boot-args actually changed
|
||||||
|
boot_args_section['boot-args'] = final_boot_args
|
||||||
|
_report(f"Updated boot-args to: '{final_boot_args}'")
|
||||||
|
modified = True # Ensure modified is true if boot_args changed
|
||||||
|
|
||||||
|
if not modified:
|
||||||
|
_report("No changes made to config.plist based on detected hardware or existing settings.")
|
||||||
|
return True # Successful in the sense that no changes were needed or applied.
|
||||||
|
|
||||||
|
# Save the modified plist
|
||||||
|
try:
|
||||||
|
with open(plist_path, 'wb') as f:
|
||||||
|
plistlib.dump(config_data, f, sort_keys=True)
|
||||||
|
_report(f"Successfully saved enhanced config.plist to {plist_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
_report(f"Error saving modified plist file {plist_path}: {e}")
|
||||||
|
_report(f"Attempting to restore backup to {plist_path}...")
|
||||||
|
try:
|
||||||
|
shutil.copy2(backup_plist_path, plist_path)
|
||||||
|
_report("Restored backup successfully.")
|
||||||
|
except Exception as backup_error:
|
||||||
|
_report(f"CRITICAL: FAILED TO RESTORE BACKUP. {plist_path} may be corrupt. Backup is at {backup_plist_path}. Error: {backup_error}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# if __name__ == '__main__': (Keep the same test block as before)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("Plist Modifier Standalone Test")
|
||||||
|
dummy_plist_path = "test_config.plist"
|
||||||
|
dummy_data = {
|
||||||
|
"Kernel": {"Add": [
|
||||||
|
{"BundlePath": "Lilu.kext", "Enabled": True, "Arch": "Any", "Comment": "", "ExecutablePath": "Contents/MacOS/Lilu", "MaxKernel": "", "MinKernel": "", "PlistPath": "Contents/Info.plist"},
|
||||||
|
{"BundlePath": "WhateverGreen.kext", "Enabled": True, "Arch": "Any", "Comment": "", "ExecutablePath": "Contents/MacOS/WhateverGreen", "MaxKernel": "", "MinKernel": "", "PlistPath": "Contents/Info.plist"},
|
||||||
|
{"BundlePath": "AppleALC.kext", "Enabled": False, "Arch": "Any", "Comment": "", "ExecutablePath": "Contents/MacOS/AppleALC", "MaxKernel": "", "MinKernel": "", "PlistPath": "Contents/Info.plist"},
|
||||||
|
{"BundlePath": "IntelMausi.kext", "Enabled": False, "Arch": "Any", "Comment": "", "ExecutablePath": "Contents/MacOS/IntelMausi", "MaxKernel": "", "MinKernel": "", "PlistPath": "Contents/Info.plist"},
|
||||||
|
]},
|
||||||
|
"NVRAM": {"Add": {"7C436110-AB2A-4BBB-A880-FE41995C9F82": {"boot-args": "-v"}}}
|
||||||
|
}
|
||||||
|
with open(dummy_plist_path, 'wb') as f:
|
||||||
|
plistlib.dump(dummy_data, f)
|
||||||
|
print(f"Created dummy {dummy_plist_path} for testing.")
|
||||||
|
|
||||||
|
original_get_pci = get_pci_devices_info; original_get_cpu = get_cpu_info # Store originals
|
||||||
|
|
||||||
|
needs_mocking = platform.system() != "Linux"
|
||||||
|
if not needs_mocking:
|
||||||
|
try:
|
||||||
|
get_pci_devices_info()
|
||||||
|
except Exception:
|
||||||
|
print("Hardware info functions seem problematic, forcing mock.")
|
||||||
|
needs_mocking = True
|
||||||
|
|
||||||
|
|
||||||
|
if needs_mocking:
|
||||||
|
print("Mocking hardware info for non-Linux or if module not loaded properly.")
|
||||||
|
|
||||||
|
get_pci_devices_info = lambda: [
|
||||||
|
{'type': 'VGA', 'vendor_id': '8086', 'device_id': '3e9b', 'description': 'Intel UHD Graphics 630 (Desktop Coffee Lake)', 'full_lspci_line':''},
|
||||||
|
{'type': 'Audio', 'vendor_id': '8086', 'device_id': 'a348', 'description': 'Intel Cannon Point-LP HD Audio', 'full_lspci_line':''},
|
||||||
|
{'type': 'Ethernet', 'vendor_id': '8086', 'device_id': '15b8', 'description': 'Intel I219-V Ethernet', 'full_lspci_line':''},
|
||||||
|
]
|
||||||
|
get_cpu_info = lambda: {"Model name": "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz", "Flags": "avx avx2"}
|
||||||
|
|
||||||
|
success = enhance_config_plist(dummy_plist_path, "Sonoma", print)
|
||||||
|
print(f"Plist enhancement {'succeeded' if success else 'failed'}.")
|
||||||
|
if success:
|
||||||
|
with open(dummy_plist_path, 'rb') as f:
|
||||||
|
modified_data = plistlib.load(f)
|
||||||
|
print("\n--- Modified Plist Content (first level keys) ---")
|
||||||
|
for k,v in modified_data.items(): print(f"{k}: {type(v)}")
|
||||||
|
|
||||||
|
if needs_mocking:
|
||||||
|
get_pci_devices_info = original_get_pci; get_cpu_info = original_get_cpu
|
||||||
|
|
||||||
|
if os.path.exists(dummy_plist_path): os.remove(dummy_plist_path)
|
||||||
|
if os.path.exists(dummy_plist_path + ".backup"): os.remove(dummy_plist_path + ".backup")
|
||||||
|
print(f"Cleaned up dummy plist and backup.")
|
@ -5,11 +5,14 @@ import time
|
|||||||
import shutil # For checking command existence
|
import shutil # For checking command existence
|
||||||
|
|
||||||
class USBWriterLinux:
|
class USBWriterLinux:
|
||||||
def __init__(self, device: str, opencore_qcow2_path: str, macos_qcow2_path: str, progress_callback=None):
|
def __init__(self, device: str, opencore_qcow2_path: str, macos_qcow2_path: str,
|
||||||
|
progress_callback=None, enhance_plist_enabled: bool = False, target_macos_version: str = ""): # New args
|
||||||
self.device = device
|
self.device = device
|
||||||
self.opencore_qcow2_path = opencore_qcow2_path
|
self.opencore_qcow2_path = opencore_qcow2_path
|
||||||
self.macos_qcow2_path = macos_qcow2_path
|
self.macos_qcow2_path = macos_qcow2_path
|
||||||
self.progress_callback = progress_callback
|
self.progress_callback = progress_callback
|
||||||
|
self.enhance_plist_enabled = enhance_plist_enabled # Store
|
||||||
|
self.target_macos_version = target_macos_version # Store
|
||||||
|
|
||||||
# Define unique temporary file and mount point names
|
# Define unique temporary file and mount point names
|
||||||
pid = os.getpid() # Make temp names more unique if multiple instances run (though unlikely for this app)
|
pid = os.getpid() # Make temp names more unique if multiple instances run (though unlikely for this app)
|
||||||
@ -180,6 +183,27 @@ class USBWriterLinux:
|
|||||||
|
|
||||||
self._report_progress(f"Mounting {mapped_efi_device} to {self.mount_point_opencore_efi}...")
|
self._report_progress(f"Mounting {mapped_efi_device} to {self.mount_point_opencore_efi}...")
|
||||||
self._run_command(["sudo", "mount", "-o", "ro", mapped_efi_device, self.mount_point_opencore_efi])
|
self._run_command(["sudo", "mount", "-o", "ro", mapped_efi_device, self.mount_point_opencore_efi])
|
||||||
|
|
||||||
|
if self.enhance_plist_enabled:
|
||||||
|
try:
|
||||||
|
from plist_modifier import enhance_config_plist # Import here
|
||||||
|
if enhance_config_plist:
|
||||||
|
config_plist_on_source_efi = os.path.join(self.mount_point_opencore_efi, "EFI", "OC", "config.plist")
|
||||||
|
if os.path.exists(config_plist_on_source_efi):
|
||||||
|
self._report_progress("Attempting to enhance config.plist...")
|
||||||
|
if enhance_config_plist(config_plist_on_source_efi, self.target_macos_version, self._report_progress):
|
||||||
|
self._report_progress("config.plist enhancement successful.")
|
||||||
|
else:
|
||||||
|
self._report_progress("config.plist enhancement failed or had issues. Continuing with original/partially modified plist.")
|
||||||
|
else:
|
||||||
|
self._report_progress(f"Warning: config.plist not found at {config_plist_on_source_efi}. Cannot enhance.")
|
||||||
|
else:
|
||||||
|
self._report_progress("Warning: enhance_config_plist function not available. Skipping enhancement.")
|
||||||
|
except ImportError:
|
||||||
|
self._report_progress("Warning: plist_modifier.py module not found. Skipping config.plist enhancement.")
|
||||||
|
except Exception as e:
|
||||||
|
self._report_progress(f"Error during config.plist enhancement attempt: {e}. Continuing with original plist.")
|
||||||
|
|
||||||
self._report_progress(f"Mounting USB ESP ({esp_partition_dev}) to {self.mount_point_usb_esp}...")
|
self._report_progress(f"Mounting USB ESP ({esp_partition_dev}) to {self.mount_point_usb_esp}...")
|
||||||
self._run_command(["sudo", "mount", esp_partition_dev, self.mount_point_usb_esp])
|
self._run_command(["sudo", "mount", esp_partition_dev, self.mount_point_usb_esp])
|
||||||
|
|
||||||
|
@ -6,11 +6,14 @@ import shutil # For checking command existence
|
|||||||
import plistlib # For parsing diskutil list -plist output
|
import plistlib # For parsing diskutil list -plist output
|
||||||
|
|
||||||
class USBWriterMacOS:
|
class USBWriterMacOS:
|
||||||
def __init__(self, device: str, opencore_qcow2_path: str, macos_qcow2_path: str, progress_callback=None):
|
def __init__(self, device: str, opencore_qcow2_path: str, macos_qcow2_path: str,
|
||||||
|
progress_callback=None, enhance_plist_enabled: bool = False, target_macos_version: str = ""): # New args
|
||||||
self.device = device # Should be like /dev/diskX
|
self.device = device # Should be like /dev/diskX
|
||||||
self.opencore_qcow2_path = opencore_qcow2_path
|
self.opencore_qcow2_path = opencore_qcow2_path
|
||||||
self.macos_qcow2_path = macos_qcow2_path
|
self.macos_qcow2_path = macos_qcow2_path
|
||||||
self.progress_callback = progress_callback
|
self.progress_callback = progress_callback
|
||||||
|
self.enhance_plist_enabled = enhance_plist_enabled # Store
|
||||||
|
self.target_macos_version = target_macos_version # Store
|
||||||
|
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
self.opencore_raw_path = f"opencore_temp_{pid}.raw"
|
self.opencore_raw_path = f"opencore_temp_{pid}.raw"
|
||||||
|
Loading…
Reference in New Issue
Block a user