11#!/usr/bin/python3
22# SPDX-License-Identifier: MIT
3- import os , os .path , shlex , subprocess , sys , time , termios
3+ import os , os .path , shlex , subprocess , sys , time , termios , json
44from dataclasses import dataclass
55
6- import system , osenum , stub , diskutil
6+ import system , osenum , stub , diskutil , osinstall , firmware
77from util import *
88
9- STUB_SIZE = align_up (2500 * 1000 * 1000 )
9+ STUB_SIZE = align_up (2500 * 1000 * 1000 , 1024 * 1024 )
1010
1111@dataclass
1212class IPSW :
@@ -48,6 +48,9 @@ class IPSW:
4848]
4949
5050class InstallerMain :
51+ def __init__ (self ):
52+ self .data = json .load (open ("installer_data.json" ))
53+
5154 def choice (self , prompt , options , default = None ):
5255 is_array = False
5356 if isinstance (options , list ):
@@ -93,48 +96,67 @@ def check_cur_os(self):
9396 def action_install_into_container (self , avail_parts ):
9497 self .check_cur_os ()
9598
99+ template = self .choose_os ()
100+
96101 containers = {str (i ): p .desc for i ,p in enumerate (self .parts ) if p in avail_parts }
97102
98103 print ()
99104 print ("Choose a container to install into:" )
100105 idx = self .choice ("Target container" , containers )
101106 self .part = self .parts [int (idx )]
102107
103- print (f"Installing stub macOS into { self .part .name } ({ self .part .label } )" )
104-
105108 ipsw = self .choose_ipsw ()
106- self .ins = stub .Installer (self .sysinfo , self .dutil , self .osinfo , ipsw )
109+ self .ins = stub .StubInstaller (self .sysinfo , self .dutil , self .osinfo , ipsw )
110+ self .osins = osinstall .OSInstaller (self .dutil , self .data , template )
111+ self .osins .load_package ()
107112
108- self .ins .prepare_volume (self .part )
109- self .ins .check_volume ()
110- self .ins .install_files (self .cur_os )
111- self .step2 ()
113+ self .do_install ()
112114
113115 def action_install_into_free (self , avail_free ):
114116 self .check_cur_os ()
115117
118+ template = self .choose_os ()
119+
120+ self .osins = osinstall .OSInstaller (self .dutil , self .data , template )
121+ self .osins .load_package ()
122+
116123 frees = {str (i ): p .desc for i ,p in enumerate (self .parts ) if p in avail_free }
117124
118125 print ()
119126 print ("Choose a free area to install into:" )
120127 idx = self .choice ("Target area" , frees )
121128 free_part = self .parts [int (idx )]
122129
123- label = input ("Enter a name for your OS (Linux): " ) or "Linux"
130+ label = input (f"Enter a name for your OS ({ self .osins .name } ): " ) or self .osins .name
131+ self .osins .name = label
124132 print ()
125133
126134 ipsw = self .choose_ipsw ()
127- self .ins = stub .Installer (self .sysinfo , self .dutil , self .osinfo , ipsw )
135+ self .ins = stub .StubInstaller (self .sysinfo , self .dutil , self .osinfo , ipsw )
128136
129137 print (f"Creating new stub macOS named { label } " )
130- self .part = self .dutil .addPartition (free_part .name , "apfs" , label , "2.5G" )
138+ self .part = self .dutil .addPartition (free_part .name , "apfs" , label , STUB_SIZE )
131139
132- print ()
140+ self .do_install ()
141+
142+ def do_install (self ):
133143 print (f"Installing stub macOS into { self .part .name } ({ self .part .label } )" )
134144
135145 self .ins .prepare_volume (self .part )
136146 self .ins .check_volume ()
137147 self .ins .install_files (self .cur_os )
148+
149+ self .osins .partition_disk (self .part .name )
150+
151+ pkg = None
152+ if self .osins .needs_firmware :
153+ pkg = firmware .FWPackage ("firmware.tar" )
154+ self .ins .collect_firmware (pkg )
155+ pkg .close ()
156+ self .osins .firmware_package = pkg
157+
158+ self .osins .install (self .ins .boot_obj_path )
159+
138160 self .step2 ()
139161
140162 def choose_ipsw (self ):
@@ -162,6 +184,11 @@ def choose_ipsw(self):
162184
163185 return ipsw
164186
187+ def choose_os (self ):
188+ print ("Choose an OS to install:" )
189+ idx = self .choice ("OS" , [i ["name" ] for i in self .data ["os_list" ]])
190+ return self .data ["os_list" ][idx ]
191+
165192 def set_reduced_security (self ):
166193 print ( "We are about to prepare your new stub OS for booting in" )
167194 print ( "Reduced Security mode. Please enter your macOS credentials" )
@@ -197,7 +224,6 @@ def step2(self):
197224 self .step2_indirect ()
198225 else :
199226 assert False # should never happen, we don't give users the option
200- self .step2_old_macos ()
201227
202228 def step2_1tr_direct (self ):
203229 self .startup_disk_recovery ()
@@ -213,6 +239,11 @@ def flush_input(self):
213239 pass
214240
215241 def step2_indirect (self ):
242+ # Hide the new volume until step2 is done
243+ os .rename (self .ins .systemversion_path ,
244+ self .ins .systemversion_path .replace ("SystemVersion.plist" ,
245+ "SystemVersion-disabled.plist" ))
246+
216247 print ( "The system will now shut down." )
217248 print ( "To complete the installation, perform the following steps:" )
218249 print ()
@@ -222,46 +253,18 @@ def step2_indirect(self):
222253 print ( " and that you press and hold down the button once, not multiple times." )
223254 print ( " This is required to put the machine into the right mode." )
224255 print ( "3. Release it once 'Entering startup options' is displayed." )
225- print ( "4. Choose Options ." )
256+ print (f "4. Choose { self . part . label } ." )
226257 print ( "5. You will briefly see a 'macOS Recovery' dialog." )
227258 print ( " * If you are asked to 'Select a volume to recover'," )
228259 print ( " then choose your normal macOS volume and click Next." )
229- print ( "6. Click on the Utilities menu and select Terminal." )
230- print ( "7. Type the following command and follow the prompts:" )
231- print ()
232- print (f"/Volumes/{ shlex .quote (self .part .label )} /step2.sh" )
260+ print ( "6. Once the 'Asahi Linux installer' screen appears, follow the prompts." )
233261 print ()
234262 time .sleep (2 )
235263 self .flush_input ()
236264 print ( "Press enter to shut down the system." )
237265 input ()
238266 os .system ("shutdown -h now" )
239267
240- def step2_old_macos (self ):
241- print ( "To complete the installation, perform the following steps:" )
242- print ()
243- print ( "1. Go to System Settings -> Startup Disk." )
244- print (f"2. Choose '{ self .part .label } ' and authenticate yourself." )
245- print ( " * The system will reboot into the Boot Recovery Assistant." )
246- print ( "3. Authenticate yourself again." )
247- print ( " * The system will go into a reboot loop." )
248- print ( "4. Press and hold down the power button to shut the system down." )
249- print ( " * If you end up in the Startup Options screen, choose Shut Down." )
250- print ( " Do not skip ahead to step 5. It won't work." )
251- print ( " * If you end up in Recovery mode, select Shut Down from the Apple menu." )
252- print ( " Do not skip ahead to step 6. It won't work." )
253- print ( "5. Press and hold down the power button to power on the system." )
254- print ( " * It is important that the system be fully powered off before this step," )
255- print ( " and that you press and hold down the button once, not multiple times." )
256- print ( " This is required to put the machine into the right mode." )
257- print ( "6. Release it once 'Entering startup options' is displayed." )
258- print ( "7. Choose Options." )
259- print ( "8. Click on the Utilities menu and select Terminal." )
260- print ( "9. Type the following command and follow the prompts:" )
261- print ()
262- print (f"/Volumes/{ shlex .quote (self .part .label )} /step2.sh" )
263- print ()
264-
265268 def startup_disk (self , recovery = False , volume_blessed = False , reboot = False ):
266269 print (f"When the Startup Disk screen appears, choose '{ self .part .label } ', then click Restart." )
267270 if not volume_blessed :
@@ -415,13 +418,13 @@ def main(self):
415418 actions = {}
416419
417420 if parts_free :
418- actions ["f" ] = "Install Asahi Linux into free space"
421+ actions ["f" ] = "Install an OS into free space"
419422 if parts_empty_apfs :
420- actions ["a" ] = "Install a macOS stub and m1n1 into an existing APFS container"
423+ actions ["a" ] = "Install an OS into an existing APFS container"
421424 if parts_system and False :
422- actions ["r" ] = "Resize an existing OS and install Asahi Linux "
425+ actions ["r" ] = "Resize an existing OS and install a new OS "
423426 if self .sysinfo .boot_mode == "one true recoveryOS" :
424- actions ["m" ] = "Install m1n1 into an existing OS container "
427+ actions ["m" ] = "Upgrade bootloader of an existing OS"
425428
426429 if not actions :
427430 print ("No actions available on this system." )
0 commit comments