mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-24 03:50:14 +10:00
gui.py: Resolve Root Volume Support
This commit is contained in:
321
gui/gui_main.py
321
gui/gui_main.py
@@ -7,8 +7,10 @@ import sys
|
||||
import webbrowser
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
import wx.adv
|
||||
|
||||
from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect
|
||||
from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run
|
||||
from data import model_array, os_data, smbios_data
|
||||
from gui import menu_redirect
|
||||
|
||||
@@ -21,6 +23,7 @@ class wx_python_gui:
|
||||
|
||||
# Backup stdout for usage with wxPython
|
||||
self.stock_stdout = sys.stdout
|
||||
self.stock_stderr = sys.stderr
|
||||
|
||||
# Define Window Size
|
||||
self.WINDOW_WIDTH_MAIN = 350
|
||||
@@ -56,9 +59,94 @@ class wx_python_gui:
|
||||
self.frame.DestroyChildren()
|
||||
self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN)
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
|
||||
def print_test(self, text):
|
||||
print(text)
|
||||
def relaunch_as_root(self, event=None):
|
||||
|
||||
# Add Dialog Box asking if it's ok to relaunch as root
|
||||
# If yes, relaunch as root
|
||||
# If no, do nothing
|
||||
|
||||
# Create Dialog Box
|
||||
self.dialog = wx.MessageDialog(
|
||||
self.frame,
|
||||
"OpenCore Legacy Patcher needs to relaunch as admin to continue. You will be prompted to enter your password.",
|
||||
"Relaunch as root?",
|
||||
wx.YES_NO | wx.ICON_QUESTION
|
||||
)
|
||||
|
||||
# Show Dialog Box
|
||||
if self.dialog.ShowModal() == wx.ID_YES:
|
||||
print("Relaunching as root")
|
||||
if self.constants.launcher_script is None:
|
||||
args_string = f"{self.constants.launcher_binary}"""
|
||||
else:
|
||||
args_string = f"{self.constants.launcher_binary} {self.constants.launcher_script}"
|
||||
|
||||
args = [
|
||||
"osascript",
|
||||
"-e",
|
||||
f'''do shell script "{args_string}"'''
|
||||
' with prompt "OpenCore Legacy Patcher needs administrator privileges to mount your EFI."'
|
||||
" with administrator privileges"
|
||||
" without altering line endings",
|
||||
]
|
||||
|
||||
self.frame.DestroyChildren()
|
||||
self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN)
|
||||
|
||||
# Header
|
||||
self.header = wx.StaticText(self.frame, label="Relaunching as root")
|
||||
self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
|
||||
self.header.Centre(wx.HORIZONTAL)
|
||||
|
||||
# Add count down label
|
||||
self.countdown_label = wx.StaticText(self.frame, label="Closing old process in 15 seconds")
|
||||
self.countdown_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
# Set below header
|
||||
self.countdown_label.SetPosition(
|
||||
(
|
||||
self.header.GetPosition().x + 3,
|
||||
self.header.GetPosition().y + self.header.GetSize().height + 3
|
||||
)
|
||||
)
|
||||
self.countdown_label.Centre(wx.HORIZONTAL)
|
||||
# Label: You can close this window if app finished relaunching
|
||||
self.countdown_label2 = wx.StaticText(self.frame, label="You can close this window if app finished relaunching")
|
||||
self.countdown_label2.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
# Set below countdown label
|
||||
self.countdown_label2.SetPosition(
|
||||
(
|
||||
self.countdown_label.GetPosition().x,
|
||||
self.countdown_label.GetPosition().y + self.countdown_label.GetSize().height + 3
|
||||
)
|
||||
)
|
||||
self.countdown_label2.Centre(wx.HORIZONTAL)
|
||||
|
||||
# Set frame right below countdown label
|
||||
self.frame.SetSize(
|
||||
(
|
||||
-1,
|
||||
self.countdown_label2.GetPosition().y + self.countdown_label2.GetSize().height + 40
|
||||
)
|
||||
)
|
||||
|
||||
wx.GetApp().Yield()
|
||||
subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
timer_val = 15
|
||||
while True:
|
||||
wx.GetApp().Yield()
|
||||
self.countdown_label.SetLabel(f"Closing old process in {timer_val} seconds")
|
||||
time.sleep(1)
|
||||
timer_val -= 1
|
||||
if timer_val == 0:
|
||||
break
|
||||
# Close Current Application
|
||||
self.frame.Close()
|
||||
|
||||
def not_yet_implemented_menu(self, event=None):
|
||||
self.frame.DestroyChildren()
|
||||
@@ -263,6 +351,8 @@ class wx_python_gui:
|
||||
# Reset Data in the event of re-run
|
||||
self.reset_window()
|
||||
|
||||
# Set header text
|
||||
self.frame.SetTitle(f"OpenCore Legacy Patcher v{self.constants.patcher_version}")
|
||||
# Header
|
||||
self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}")
|
||||
self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
|
||||
@@ -499,6 +589,7 @@ class wx_python_gui:
|
||||
self.stdout_text.Centre(wx.HORIZONTAL)
|
||||
self.stdout_text.SetValue("")
|
||||
sys.stdout=menu_redirect.RedirectText(self.stdout_text)
|
||||
sys.stderr=menu_redirect.RedirectText(self.stdout_text)
|
||||
|
||||
# Return to Main Menu
|
||||
self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu")
|
||||
@@ -519,6 +610,7 @@ class wx_python_gui:
|
||||
|
||||
# Reset stdout
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
|
||||
def install_menu(self, event=None):
|
||||
self.frame.DestroyChildren()
|
||||
@@ -666,6 +758,7 @@ class wx_python_gui:
|
||||
self.stdout_text.Centre(wx.HORIZONTAL)
|
||||
self.stdout_text.SetValue("")
|
||||
sys.stdout=menu_redirect.RedirectText(self.stdout_text)
|
||||
sys.stderr=menu_redirect.RedirectText(self.stdout_text)
|
||||
|
||||
# Update frame height to right below
|
||||
self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40)
|
||||
@@ -700,7 +793,7 @@ class wx_python_gui:
|
||||
self.frame.DestroyChildren()
|
||||
|
||||
# Header
|
||||
self.header = wx.StaticText(self.frame, label="Post-Install Menu")
|
||||
self.header = wx.StaticText(self.frame, label=f"Post-Install Menu")
|
||||
self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
|
||||
self.header.Centre(wx.HORIZONTAL)
|
||||
|
||||
@@ -755,7 +848,12 @@ class wx_python_gui:
|
||||
self.patch_label.GetPosition().y + self.patch_label.GetSize().height + 10
|
||||
)
|
||||
)
|
||||
self.start_root_patching.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu)
|
||||
uid = os.geteuid()
|
||||
print(f"Effective UID: {uid}")
|
||||
if uid == 0:
|
||||
self.start_root_patching.Bind(wx.EVT_BUTTON, self.root_patch_start)
|
||||
else:
|
||||
self.start_root_patching.Bind(wx.EVT_BUTTON, self.relaunch_as_root)
|
||||
self.start_root_patching.Centre(wx.HORIZONTAL)
|
||||
if not patches:
|
||||
self.start_root_patching.Disable()
|
||||
@@ -768,7 +866,10 @@ class wx_python_gui:
|
||||
self.start_root_patching.GetPosition().y + self.start_root_patching.GetSize().height + 3
|
||||
)
|
||||
)
|
||||
if uid == 0:
|
||||
self.revert_root_patches.Bind(wx.EVT_BUTTON, self.root_patch_revert)
|
||||
else:
|
||||
self.revert_root_patches.Bind(wx.EVT_BUTTON, self.relaunch_as_root)
|
||||
self.revert_root_patches.Centre(wx.HORIZONTAL)
|
||||
if self.constants.detected_os < os_data.os_data.big_sur:
|
||||
self.revert_root_patches.Disable()
|
||||
@@ -808,7 +909,7 @@ class wx_python_gui:
|
||||
)
|
||||
self.subheader.Centre(wx.HORIZONTAL)
|
||||
|
||||
self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing")
|
||||
self.developer_note = wx.StaticText(self.frame, label="Starting shortly")
|
||||
self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.developer_note.SetPosition(
|
||||
wx.Point(
|
||||
@@ -830,7 +931,7 @@ class wx_python_gui:
|
||||
self.text_box.SetSize(
|
||||
wx.Size(
|
||||
self.frame.GetSize().width - 10,
|
||||
self.frame.GetSize().height - self.text_box.GetPosition().y + 40
|
||||
self.frame.GetSize().height + self.text_box.GetPosition().y + 80
|
||||
)
|
||||
)
|
||||
self.text_box.Centre(wx.HORIZONTAL)
|
||||
@@ -850,27 +951,16 @@ class wx_python_gui:
|
||||
self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40)
|
||||
|
||||
wx.GetApp().Yield()
|
||||
if self.constants.launcher_script is None:
|
||||
self.text_box.AppendText("- Starting OCLP-CLI via Binary\n")
|
||||
args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--patch_sys_vol"]
|
||||
else:
|
||||
self.text_box.AppendText("- Starting OCLP-CLI via Python\n")
|
||||
args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--patch_sys_vol"]
|
||||
process = subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
|
||||
sys.stdout = menu_redirect.RedirectText(self.text_box)
|
||||
sys.stderr = menu_redirect.RedirectText(self.text_box)
|
||||
wx.GetApp().Yield()
|
||||
while True:
|
||||
line = process.stdout.readline()
|
||||
self.frame.Show()
|
||||
sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_patch()
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
|
||||
wx.GetApp().Yield()
|
||||
if line.strip() == "":
|
||||
pass
|
||||
else:
|
||||
self.text_box.AppendText(line)
|
||||
if not line: break
|
||||
process.wait()
|
||||
|
||||
def root_patch_revert(self, event=None):
|
||||
self.frame.DestroyChildren()
|
||||
@@ -896,7 +986,7 @@ class wx_python_gui:
|
||||
)
|
||||
self.subheader.Centre(wx.HORIZONTAL)
|
||||
|
||||
self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing")
|
||||
self.developer_note = wx.StaticText(self.frame, label="Starting shortly")
|
||||
self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.developer_note.SetPosition(
|
||||
wx.Point(
|
||||
@@ -918,7 +1008,7 @@ class wx_python_gui:
|
||||
self.text_box.SetSize(
|
||||
wx.Size(
|
||||
self.frame.GetSize().width - 10,
|
||||
self.frame.GetSize().height - self.text_box.GetPosition().y + 40
|
||||
self.frame.GetSize().height + self.text_box.GetPosition().y + 80
|
||||
)
|
||||
)
|
||||
self.text_box.Centre(wx.HORIZONTAL)
|
||||
@@ -938,31 +1028,14 @@ class wx_python_gui:
|
||||
self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40)
|
||||
|
||||
# Start reverting root patches
|
||||
# Grab binary path, launch second instance as CLI
|
||||
# This is the cleanest way to implement admin root patching without either seperating OCLP or including duplicate code
|
||||
sys.stdout = menu_redirect.RedirectText(self.text_box)
|
||||
sys.stderr = menu_redirect.RedirectText(self.text_box)
|
||||
wx.GetApp().Yield()
|
||||
if self.constants.launcher_script is None:
|
||||
self.text_box.AppendText("- Starting OCLP-CLI via Binary\n")
|
||||
args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--unpatch_sys_vol"]
|
||||
else:
|
||||
self.text_box.AppendText("- Starting OCLP-CLI via Python\n")
|
||||
args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--unpatch_sys_vol"]
|
||||
process = subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
wx.GetApp().Yield()
|
||||
while True:
|
||||
line = process.stdout.readline()
|
||||
wx.GetApp().Yield()
|
||||
if line.strip() == "":
|
||||
pass
|
||||
else:
|
||||
self.text_box.AppendText(line)
|
||||
if not line: break
|
||||
sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_unpatch()
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
|
||||
process.wait()
|
||||
wx.GetApp().Yield()
|
||||
|
||||
def create_macos_menu(self, event=None):
|
||||
# Define Menu
|
||||
@@ -1162,8 +1235,10 @@ class wx_python_gui:
|
||||
|
||||
# Update Label:
|
||||
sys.stdout=menu_redirect.RedirectLabelAll(self.download_label)
|
||||
sys.stderr=menu_redirect.RedirectLabelAll(self.download_label)
|
||||
installer.install_macOS_installer(self.constants.payload_path)
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
# Update Label:
|
||||
self.download_label.SetLabel(f"Finished Installing {installer_name}")
|
||||
self.download_label.Centre(wx.HORIZONTAL)
|
||||
@@ -1383,34 +1458,14 @@ class wx_python_gui:
|
||||
print("- Starting creation script as admin")
|
||||
wx.GetApp().Yield()
|
||||
time.sleep(1)
|
||||
sys.stdout=menu_redirect.RedirectText(self.stdout_text)
|
||||
cim_start = subprocess.Popen(
|
||||
[self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
|
||||
wx.GetApp().Yield()
|
||||
while True:
|
||||
line = cim_start.stdout.readline()
|
||||
wx.GetApp().Yield()
|
||||
if line.strip() == "":
|
||||
pass
|
||||
else:
|
||||
self.stdout_text.AppendText(line)
|
||||
if not line: break
|
||||
|
||||
cim_start.wait()
|
||||
|
||||
if cim_start.returncode == 0:
|
||||
print("Installer created successfully!")
|
||||
else:
|
||||
print("Installer creation failed")
|
||||
print(f"Return Code {cim_start.returncode}")
|
||||
sys.stdout = self.stock_stdout
|
||||
args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path]
|
||||
sys.stdout = menu_redirect.RedirectText(self.stdout_text)
|
||||
sys.stderr = menu_redirect.RedirectText(self.stdout_text)
|
||||
run.Run()._stream_output(comm=args)
|
||||
else:
|
||||
print("- Failed to create installer script")
|
||||
sys.stdout = self.stock_stdout
|
||||
sys.stderr = self.stock_stderr
|
||||
|
||||
|
||||
def settings_menu(self, event=None):
|
||||
@@ -1430,7 +1485,7 @@ class wx_python_gui:
|
||||
|
||||
self.frame.DestroyChildren()
|
||||
self.frame.SetSize(self.WINDOW_SETTINGS_WIDTH, self.WINDOW_SETTINGS_HEIGHT)
|
||||
self.frame.SetLabel("Settings")
|
||||
self.frame.SetTitle("Settings")
|
||||
|
||||
# Header
|
||||
self.header = wx.StaticText(self.frame, label="Settings")
|
||||
@@ -1769,12 +1824,20 @@ class wx_python_gui:
|
||||
self.apple_alc_checkbox.GetPosition().x,
|
||||
self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height))
|
||||
|
||||
# Button: Developer Debug Info
|
||||
self.debug_button = wx.Button(self.frame, label="Developer Debug Info")
|
||||
self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu)
|
||||
self.debug_button.SetPosition(wx.Point(
|
||||
self.set_writeflash_checkbox.GetPosition().x,
|
||||
self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height))
|
||||
self.debug_button.Center(wx.HORIZONTAL)
|
||||
|
||||
# Button: return to main menu
|
||||
self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu")
|
||||
self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu)
|
||||
self.return_to_main_menu_button.SetPosition(wx.Point(
|
||||
self.set_writeflash_checkbox.GetPosition().x,
|
||||
self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 10))
|
||||
self.debug_button.GetPosition().x,
|
||||
self.debug_button.GetPosition().y + self.debug_button.GetSize().height + 10))
|
||||
self.return_to_main_menu_button.Center(wx.HORIZONTAL)
|
||||
|
||||
# set frame size below return to main menu button
|
||||
@@ -1973,3 +2036,103 @@ class wx_python_gui:
|
||||
selection = self.smbios_model_dropdown.GetStringSelection()
|
||||
print(f"SMBIOS Spoof Model: {selection}")
|
||||
self.constants.override_smbios = selection
|
||||
|
||||
def additional_info_menu(self, event=None):
|
||||
# Define Menu:
|
||||
|
||||
# Header: Additional Info
|
||||
# Label: Model Dump
|
||||
# Textbox: Model Dump
|
||||
# Label: Real User ID
|
||||
# Label: Effective User ID
|
||||
# Label: Launcher Binary
|
||||
# Textbox: Launcher Binary
|
||||
# Label: Launcher Script
|
||||
# Textbox: Launcher Script
|
||||
|
||||
self.frame.DestroyChildren()
|
||||
|
||||
# Header: Additional Info
|
||||
self.additional_info_header = wx.StaticText(self.frame, label="Developer Debug Info", pos=wx.Point(10, 10))
|
||||
self.additional_info_header.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
|
||||
self.additional_info_header.Center(wx.HORIZONTAL)
|
||||
|
||||
# Label: Real User ID
|
||||
self.real_user_id_label = wx.StaticText(self.frame, label=f"Current UID: {os.getuid()} - ({os.geteuid()})")
|
||||
self.real_user_id_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.real_user_id_label.SetPosition(
|
||||
wx.Point(self.additional_info_header.GetPosition().x, self.additional_info_header.GetPosition().y + self.additional_info_header.GetSize().height + 10)
|
||||
)
|
||||
self.real_user_id_label.Center(wx.HORIZONTAL)
|
||||
|
||||
# Label: Model Dump
|
||||
self.model_dump_label = wx.StaticText(self.frame, label="Model Dump")
|
||||
self.model_dump_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.model_dump_label.SetPosition(
|
||||
wx.Point(self.real_user_id_label.GetPosition().x, self.real_user_id_label.GetPosition().y + self.real_user_id_label.GetSize().height + 10)
|
||||
)
|
||||
self.model_dump_label.Center(wx.HORIZONTAL)
|
||||
|
||||
# Textbox: Model Dump
|
||||
self.model_dump_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.model_dump_label.GetPosition().x, self.model_dump_label.GetPosition().y + self.model_dump_label.GetSize().height + 10))
|
||||
self.model_dump_textbox.SetValue(str(self.constants.computer))
|
||||
self.model_dump_textbox.SetPosition(
|
||||
wx.Point(self.model_dump_label.GetPosition().x, self.model_dump_label.GetPosition().y + self.model_dump_label.GetSize().height + 10)
|
||||
)
|
||||
self.model_dump_textbox.SetSize(
|
||||
wx.Size(
|
||||
self.frame.GetSize().width - 5,
|
||||
self.model_dump_textbox.GetSize().height + self.model_dump_textbox.GetSize().height
|
||||
)
|
||||
)
|
||||
self.model_dump_textbox.Center(wx.HORIZONTAL)
|
||||
self.model_dump_textbox.SetEditable(False)
|
||||
|
||||
|
||||
|
||||
# Label: Launcher Binary
|
||||
self.launcher_binary_label = wx.StaticText(self.frame, label="Launcher Binary")
|
||||
self.launcher_binary_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.launcher_binary_label.SetPosition(
|
||||
wx.Point(self.model_dump_textbox.GetPosition().x, self.model_dump_textbox.GetPosition().y + self.model_dump_textbox.GetSize().height + 10)
|
||||
)
|
||||
self.launcher_binary_label.Center(wx.HORIZONTAL)
|
||||
|
||||
# Textbox: Launcher Binary
|
||||
self.launcher_binary_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.launcher_binary_label.GetPosition().x, self.launcher_binary_label.GetPosition().y + self.launcher_binary_label.GetSize().height + 10))
|
||||
self.launcher_binary_textbox.SetValue(self.constants.launcher_binary)
|
||||
self.launcher_binary_textbox.SetPosition(
|
||||
wx.Point(self.launcher_binary_label.GetPosition().x, self.launcher_binary_label.GetPosition().y + self.launcher_binary_label.GetSize().height + 10)
|
||||
)
|
||||
self.launcher_binary_textbox.SetSize(wx.Size(self.frame.GetSize().width - 5, 50))
|
||||
self.launcher_binary_textbox.Center(wx.HORIZONTAL)
|
||||
self.launcher_binary_textbox.SetEditable(False)
|
||||
|
||||
# Label: Launcher Script
|
||||
self.launcher_script_label = wx.StaticText(self.frame, label="Launcher Script")
|
||||
self.launcher_script_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
|
||||
self.launcher_script_label.SetPosition(
|
||||
wx.Point(self.launcher_binary_textbox.GetPosition().x, self.launcher_binary_textbox.GetPosition().y + self.launcher_binary_textbox.GetSize().height + 10)
|
||||
)
|
||||
self.launcher_script_label.Center(wx.HORIZONTAL)
|
||||
|
||||
# Textbox: Launcher Script
|
||||
self.launcher_script_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.launcher_script_label.GetPosition().x, self.launcher_script_label.GetPosition().y + self.launcher_script_label.GetSize().height + 10))
|
||||
self.launcher_script_textbox.SetValue(str(self.constants.launcher_script))
|
||||
self.launcher_script_textbox.SetPosition(
|
||||
wx.Point(self.launcher_script_label.GetPosition().x, self.launcher_script_label.GetPosition().y + self.launcher_script_label.GetSize().height + 10)
|
||||
)
|
||||
self.launcher_script_textbox.SetSize(wx.Size(self.frame.GetSize().width - 5, 60))
|
||||
self.launcher_script_textbox.Center(wx.HORIZONTAL)
|
||||
self.launcher_script_textbox.SetEditable(False)
|
||||
|
||||
# Return to Main Menu Button
|
||||
self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu")
|
||||
self.return_to_main_menu_button.SetPosition(
|
||||
wx.Point(self.launcher_script_textbox.GetPosition().x, self.launcher_script_textbox.GetPosition().y + self.launcher_script_textbox.GetSize().height + 10)
|
||||
)
|
||||
self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu)
|
||||
self.return_to_main_menu_button.Center(wx.HORIZONTAL)
|
||||
|
||||
# Set frame below return to main menu button
|
||||
self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40))
|
||||
@@ -1,4 +1,5 @@
|
||||
import wx
|
||||
import time
|
||||
|
||||
class RedirectText(object):
|
||||
def __init__(self,aWxTextCtrl):
|
||||
@@ -7,6 +8,7 @@ class RedirectText(object):
|
||||
def write(self,string):
|
||||
self.out.WriteText(string)
|
||||
wx.GetApp().Yield()
|
||||
time.sleep(0.01)
|
||||
|
||||
def fileno(self):
|
||||
return 1
|
||||
@@ -23,6 +25,7 @@ class RedirectLabel(object):
|
||||
self.out.SetLabel(string)
|
||||
self.out.Centre(wx.HORIZONTAL)
|
||||
wx.GetApp().Yield()
|
||||
time.sleep(0.01)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
@@ -35,3 +38,4 @@ class RedirectLabelAll(object):
|
||||
self.out.SetLabel(string)
|
||||
self.out.Centre(wx.HORIZONTAL)
|
||||
wx.GetApp().Yield()
|
||||
time.sleep(0.01)
|
||||
155
resources/run.py
Normal file
155
resources/run.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# Module for running processes with real time output
|
||||
# Written by CorpNewt
|
||||
# Source: https://github.com/corpnewt/pymodules/blob/884c3de15b6a2570afde52fe8a14a3e946ffb18a/run.py
|
||||
|
||||
import sys, subprocess, time, threading, shlex
|
||||
try:
|
||||
from Queue import Queue, Empty
|
||||
except:
|
||||
from queue import Queue, Empty
|
||||
|
||||
ON_POSIX = 'posix' in sys.builtin_module_names
|
||||
|
||||
class Run:
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
def _read_output(self, pipe, q):
|
||||
try:
|
||||
for line in iter(lambda: pipe.read(1), b''):
|
||||
q.put(line)
|
||||
except ValueError:
|
||||
pass
|
||||
pipe.close()
|
||||
|
||||
def _create_thread(self, output):
|
||||
# Creates a new queue and thread object to watch based on the output pipe sent
|
||||
q = Queue()
|
||||
t = threading.Thread(target=self._read_output, args=(output, q))
|
||||
t.daemon = True
|
||||
return (q,t)
|
||||
|
||||
def _stream_output(self, comm, shell = False):
|
||||
output = error = ""
|
||||
p = None
|
||||
try:
|
||||
if shell and type(comm) is list:
|
||||
comm = " ".join(shlex.quote(x) for x in comm)
|
||||
if not shell and type(comm) is str:
|
||||
comm = shlex.split(comm)
|
||||
p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True, close_fds=ON_POSIX)
|
||||
# Setup the stdout thread/queue
|
||||
q,t = self._create_thread(p.stdout)
|
||||
qe,te = self._create_thread(p.stderr)
|
||||
# Start both threads
|
||||
t.start()
|
||||
te.start()
|
||||
|
||||
while True:
|
||||
c = z = ""
|
||||
try: c = q.get_nowait()
|
||||
except Empty: pass
|
||||
else:
|
||||
sys.stdout.write(c)
|
||||
output += c
|
||||
sys.stdout.flush()
|
||||
try: z = qe.get_nowait()
|
||||
except Empty: pass
|
||||
else:
|
||||
sys.stderr.write(z)
|
||||
error += z
|
||||
sys.stderr.flush()
|
||||
if not c==z=="": continue # Keep going until empty
|
||||
# No output - see if still running
|
||||
p.poll()
|
||||
if p.returncode != None:
|
||||
# Subprocess ended
|
||||
break
|
||||
# No output, but subprocess still running - stall for 20ms
|
||||
time.sleep(0.02)
|
||||
|
||||
o, e = p.communicate()
|
||||
return (output+o, error+e, p.returncode)
|
||||
except:
|
||||
if p:
|
||||
try: o, e = p.communicate()
|
||||
except: o = e = ""
|
||||
return (output+o, error+e, p.returncode)
|
||||
return ("", "Command not found!", 1)
|
||||
|
||||
def _decode(self, value, encoding="utf-8", errors="ignore"):
|
||||
# Helper method to only decode if bytes type
|
||||
if sys.version_info >= (3,0) and isinstance(value, bytes):
|
||||
return value.decode(encoding,errors)
|
||||
return value
|
||||
|
||||
def _run_command(self, comm, shell = False):
|
||||
c = None
|
||||
try:
|
||||
if shell and type(comm) is list:
|
||||
comm = " ".join(shlex.quote(x) for x in comm)
|
||||
if not shell and type(comm) is str:
|
||||
comm = shlex.split(comm)
|
||||
p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
c = p.communicate()
|
||||
except:
|
||||
if c == None:
|
||||
return ("", "Command not found!", 1)
|
||||
return (self._decode(c[0]), self._decode(c[1]), p.returncode)
|
||||
|
||||
def run(self, command_list, leave_on_fail = False):
|
||||
# Command list should be an array of dicts
|
||||
if type(command_list) is dict:
|
||||
# We only have one command
|
||||
command_list = [command_list]
|
||||
output_list = []
|
||||
for comm in command_list:
|
||||
args = comm.get("args", [])
|
||||
shell = comm.get("shell", False)
|
||||
stream = comm.get("stream", False)
|
||||
sudo = comm.get("sudo", False)
|
||||
stdout = comm.get("stdout", False)
|
||||
stderr = comm.get("stderr", False)
|
||||
mess = comm.get("message", None)
|
||||
show = comm.get("show", False)
|
||||
|
||||
if not mess == None:
|
||||
print(mess)
|
||||
|
||||
if not len(args):
|
||||
# nothing to process
|
||||
continue
|
||||
if sudo:
|
||||
# Check if we have sudo
|
||||
out = self._run_command(["which", "sudo"])
|
||||
if "sudo" in out[0]:
|
||||
# Can sudo
|
||||
if type(args) is list:
|
||||
args.insert(0, out[0].replace("\n", "")) # add to start of list
|
||||
elif type(args) is str:
|
||||
args = out[0].replace("\n", "") + " " + args # add to start of string
|
||||
|
||||
if show:
|
||||
print(" ".join(args))
|
||||
|
||||
if stream:
|
||||
# Stream it!
|
||||
out = self._stream_output(args, shell)
|
||||
else:
|
||||
# Just run and gather output
|
||||
out = self._run_command(args, shell)
|
||||
if stdout and len(out[0]):
|
||||
print(out[0])
|
||||
if stderr and len(out[1]):
|
||||
print(out[1])
|
||||
# Append output
|
||||
output_list.append(out)
|
||||
# Check for errors
|
||||
if leave_on_fail and out[2] != 0:
|
||||
# Got an error - leave
|
||||
break
|
||||
if len(output_list) == 1:
|
||||
# We only ran one command - just return that output
|
||||
return output_list[0]
|
||||
return output_list
|
||||
@@ -83,9 +83,12 @@ class PatchSysVolume:
|
||||
self.unpatch_root_vol()
|
||||
return True
|
||||
else:
|
||||
print(f"User ID: {os.getuid()} - {os.geteuid()}")
|
||||
if self.constants.detected_os > os_data.os_data.catalina:
|
||||
print("- Mounting APFS Snapshot as writable")
|
||||
utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE).stdout.decode().strip().encode()
|
||||
result = utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode == 0:
|
||||
print(f"- Mounted APFS Snapshot as writable at: {self.mount_location}")
|
||||
if Path(self.mount_extensions).exists():
|
||||
print("- Successfully mounted the Root Volume")
|
||||
if patch is True:
|
||||
@@ -272,7 +275,7 @@ class PatchSysVolume:
|
||||
print(bless.stdout.decode())
|
||||
if "Can't use last-sealed-snapshot or create-snapshot on non system volume" in bless.stdout.decode():
|
||||
print("- This is an APFS bug with Monterey! Perform a clean installation to ensure your APFS volume is built correctly")
|
||||
sys.exit(1)
|
||||
return
|
||||
else:
|
||||
self.unmount_drive()
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user