mirror of
https://github.com/sickcodes/Docker-OSX.git
synced 2025-06-21 17:12:47 +02:00
This commit introduces several major enhancements: 1. **Experimental `config.plist` Auto-Enhancement (Linux Host for Detection):** * `linux_hardware_info.py`: Added audio codec detection. * `plist_modifier.py`: * Uses detected audio codecs for more accurate `layout-id` selection. * Expanded mappings for Intel Alder Lake iGPUs, more audio devices, and Ethernet kexts. * Refined NVIDIA GTX 970 `boot-args` logic based on target macOS version and iGPU presence. * Creates a `.backup` of `config.plist` before modification and attempts restore on save failure. * Integrated into `main_app.py` with a user-selectable experimental checkbox. 2. **Reworked `README.md`:** * Completely rewritten for "Skyscope" branding and project vision. * Details all current features, including platform-specific USB writing (manual Windows dd step). * Comprehensive prerequisites, including `apfs-fuse` build dependencies for Debian. * Updated usage guide and future enhancement plans. Version set to 0.8.2. 3. **UI/UX Enhancements for Task Progress:** * Added a QTimer-driven text-based spinner to the status bar for active operations. * Centralized UI state management (`_set_ui_busy`, `update_all_button_states`) for consistent feedback and control enabling/disabling. * Refactored completion/error handling into generic slots. 4. **Improved Windows USB Writing Guidance:** * `usb_writer_windows.py` now uses `diskpart` to fetch and display the macOS partition number and byte offset, providing more specific details for your manual `dd` operation. 5. **Debian 13 "Trixie" Compatibility:** * Reviewed dependencies and updated `README.md` with specific notes for `hfsprogs` and `apfs-fuse` installation on Debian-based systems. This set of changes makes the application more intelligent in its OpenCore configuration attempts, improves your feedback during operations, and provides much more comprehensive documentation, while also advancing the capabilities of the platform-specific USB writers.
177 lines
7.3 KiB
Python
177 lines
7.3 KiB
Python
# linux_hardware_info.py
|
|
import subprocess
|
|
import re
|
|
import os # For listing /proc/asound
|
|
import glob # For wildcard matching in /proc/asound
|
|
|
|
def _run_command(command: list[str], check_stderr_for_error=False) -> tuple[str, str, int]:
|
|
"""
|
|
Helper to run a command and return its stdout, stderr, and return code.
|
|
Args:
|
|
check_stderr_for_error: If True, treat any output on stderr as an error condition for return code.
|
|
Returns:
|
|
(stdout, stderr, return_code)
|
|
"""
|
|
try:
|
|
process = subprocess.run(command, capture_output=True, text=True, check=False) # check=False to handle errors manually
|
|
|
|
# Some tools (like lspci without -k if no driver) might return 0 but print to stderr.
|
|
# However, for most tools here, a non-zero return code is the primary error indicator.
|
|
# If check_stderr_for_error is True and stderr has content, consider it an error for simplicity here.
|
|
# effective_return_code = process.returncode
|
|
# if check_stderr_for_error and process.stderr and process.returncode == 0:
|
|
# effective_return_code = 1 # Treat as error
|
|
|
|
return process.stdout, process.stderr, process.returncode
|
|
except FileNotFoundError:
|
|
print(f"Error: Command '{command[0]}' not found.")
|
|
return "", f"Command not found: {command[0]}", 127 # Standard exit code for command not found
|
|
except Exception as e:
|
|
print(f"An unexpected error occurred with command {' '.join(command)}: {e}")
|
|
return "", str(e), 1
|
|
|
|
|
|
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 using lspci.
|
|
"""
|
|
stdout, stderr, return_code = _run_command(["lspci", "-nnk"])
|
|
if return_code != 0 or not stdout:
|
|
print(f"lspci command failed or produced no output. stderr: {stderr}")
|
|
return []
|
|
|
|
devices = []
|
|
regex = re.compile(
|
|
r"^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.\d\s+"
|
|
r"(.+?)\s+"
|
|
r"\[([0-9a-fA-F]{4})\]:\s+" # Class Code in hex, like 0300 for VGA
|
|
r"(.+?)\s+"
|
|
r"\[([0-9a-fA-F]{4}):([0-9a-fA-F]{4})\]" # Vendor and Device ID
|
|
)
|
|
|
|
for line in stdout.splitlines():
|
|
match = regex.search(line)
|
|
if match:
|
|
class_desc = match.group(1).strip()
|
|
# class_code = match.group(2).strip() # Not directly used yet but captured
|
|
full_desc = match.group(3).strip()
|
|
vendor_id = match.group(4).lower()
|
|
device_id = match.group(5).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:
|
|
device_type = "Network (Wi-Fi?)"
|
|
|
|
if device_type:
|
|
cleaned_desc = full_desc
|
|
# Simple cleanup attempts (can be expanded)
|
|
vendors_to_strip = ["Intel Corporation", "NVIDIA Corporation", "Advanced Micro Devices, Inc. [AMD/ATI]", "AMD [ATI]", "Realtek Semiconductor Co., Ltd."]
|
|
for v_strip in vendors_to_strip:
|
|
if cleaned_desc.startswith(v_strip):
|
|
cleaned_desc = cleaned_desc[len(v_strip):].strip()
|
|
break
|
|
# Remove revision if present at end, e.g. (rev 31)
|
|
cleaned_desc = re.sub(r'\s*\(rev [0-9a-fA-F]{2}\)$', '', cleaned_desc)
|
|
|
|
|
|
devices.append({
|
|
"type": device_type,
|
|
"vendor_id": vendor_id,
|
|
"device_id": device_id,
|
|
"description": cleaned_desc.strip() if cleaned_desc else full_desc, # Fallback to full_desc
|
|
"full_lspci_line": line.strip()
|
|
})
|
|
return devices
|
|
|
|
def get_cpu_info() -> dict:
|
|
"""
|
|
Gets CPU information using lscpu.
|
|
"""
|
|
stdout, stderr, return_code = _run_command(["lscpu"])
|
|
if return_code != 0 or not stdout:
|
|
print(f"lscpu command failed or produced no output. stderr: {stderr}")
|
|
return {}
|
|
|
|
info = {}
|
|
regex = re.compile(r"^(CPU family|Model name|Vendor ID|Model|Stepping|Flags|Architecture):\s+(.*)$")
|
|
for line in stdout.splitlines():
|
|
match = regex.match(line)
|
|
if match:
|
|
key = match.group(1).strip()
|
|
value = match.group(2).strip()
|
|
info[key] = value
|
|
return info
|
|
|
|
def get_audio_codecs() -> list[str]:
|
|
"""
|
|
Detects audio codec names by parsing /proc/asound/card*/codec#*.
|
|
Returns a list of unique codec name strings.
|
|
E.g., ["Realtek ALC897", "Intel Kaby Lake HDMI"]
|
|
"""
|
|
codec_files = glob.glob("/proc/asound/card*/codec#*")
|
|
if not codec_files:
|
|
# Fallback for systems where codec#* might not exist, try card*/id
|
|
codec_files = glob.glob("/proc/asound/card*/id")
|
|
|
|
codecs = set() # Use a set to store unique codec names
|
|
|
|
for codec_file_path in codec_files:
|
|
try:
|
|
with open(codec_file_path, 'r') as f:
|
|
content = f.read()
|
|
# For codec#* files
|
|
codec_match = re.search(r"Codec:\s*(.*)", content)
|
|
if codec_match:
|
|
codecs.add(codec_match.group(1).strip())
|
|
|
|
# For card*/id files (often just the card name, but sometimes hints at codec)
|
|
# This is a weaker source but a fallback.
|
|
if "/id" in codec_file_path and not codec_match: # Only if no "Codec:" line found
|
|
# The content of /id is usually the card name, e.g. "HDA Intel PCH"
|
|
# This might not be the specific codec chip but can be a hint.
|
|
# For now, let's only add if it seems like a specific codec name.
|
|
# This part needs more refinement if used as a primary source.
|
|
# For now, we prioritize "Codec: " lines.
|
|
if "ALC" in content or "CS" in content or "AD" in content: # Common codec prefixes
|
|
codecs.add(content.strip())
|
|
|
|
|
|
except Exception as e:
|
|
print(f"Error reading or parsing codec file {codec_file_path}: {e}")
|
|
|
|
if not codecs and not codec_files: # If no files found at all
|
|
print("No /proc/asound/card*/codec#* or /proc/asound/card*/id files found. Cannot detect audio codecs this way.")
|
|
|
|
return sorted(list(codecs))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
print("--- 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.")
|
|
|
|
print("\n--- PCI Devices ---")
|
|
pci_devs = get_pci_devices_info()
|
|
if pci_devs:
|
|
for dev in pci_devs:
|
|
print(f" Type: {dev['type']}, Vendor: {dev['vendor_id']}, Device: {dev['device_id']}, Desc: {dev['description']}")
|
|
else: print(" No relevant PCI devices found or lspci not available.")
|
|
|
|
print("\n--- Audio Codecs ---")
|
|
audio_codecs = get_audio_codecs()
|
|
if audio_codecs:
|
|
for codec in audio_codecs:
|
|
print(f" Detected Codec: {codec}")
|
|
else:
|
|
print(" No specific audio codecs detected via /proc/asound.")
|