Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/guided.py2
-rw-r--r--examples/only_hd.py71
-rw-r--r--examples/swiss.py512
3 files changed, 550 insertions, 35 deletions
diff --git a/examples/guided.py b/examples/guided.py
index 1a00a295..16fda4c3 100644
--- a/examples/guided.py
+++ b/examples/guided.py
@@ -36,7 +36,7 @@ def ask_user_questions():
# the system immediately
archinstall.SysCommand('timedatectl set-ntp true')
- global_menu = archinstall.GlobalMenu()
+ global_menu = archinstall.GlobalMenu(data_store=archinstall.arguments)
global_menu.enable('keyboard-layout')
# Set which region to download packages from during the installation
diff --git a/examples/only_hd.py b/examples/only_hd.py
index 835c4292..cc60a3b9 100644
--- a/examples/only_hd.py
+++ b/examples/only_hd.py
@@ -4,41 +4,41 @@ import pathlib
import archinstall
-def ask_harddrives():
- # Ask which harddrives/block-devices we will install to
- # and convert them into archinstall.BlockDevice() objects.
- if archinstall.arguments.get('harddrives', None) is None:
- archinstall.arguments['harddrives'] = archinstall.generic_multi_select(archinstall.all_disks(),
- text="Select one or more harddrives to use and configure (leave blank to skip this step): ",
- allow_empty=True)
-
- if not archinstall.arguments['harddrives']:
- archinstall.log("You decided to skip harddrive selection",fg="red",level=logging.INFO)
- archinstall.log(f"and will use whatever drive-setup is mounted at {archinstall.storage['MOUNT_POINT']} (experimental)",fg="red",level=logging.INFO)
- archinstall.log("WARNING: Archinstall won't check the suitability of this setup",fg="red",level=logging.INFO)
- if input("Do you wish to continue ? [Y/n]").strip().lower() == 'n':
- exit(1)
- else:
- if archinstall.arguments.get('disk_layouts', None) is None:
- archinstall.arguments['disk_layouts'] = archinstall.select_disk_layout(archinstall.arguments['harddrives'], archinstall.arguments.get('advanced', False))
-
+class OnlyHDMenu(archinstall.GlobalMenu):
+ def _setup_selection_menu_options(self):
+ super()._setup_selection_menu_options()
+ options_list = []
+ mandatory_list = []
+ options_list = ['harddrives', 'disk_layouts', '!encryption-password','swap']
+ mandatory_list = ['harddrives']
+ options_list.extend(['install','abort'])
+
+ for entry in self._menu_options:
+ if entry in options_list:
+ # for not lineal executions, only self.option(entry).set_enabled and set_mandatory are necessary
+ if entry in mandatory_list:
+ self.enable(entry,mandatory=True)
+ else:
+ self.enable(entry)
+ else:
+ self.option(entry).set_enabled(False)
+ self._update_install()
+
+ def _missing_configs(self):
+ """ overloaded method """
+ def check(s):
+ return self.option(s).has_selection()
+
# Get disk encryption password (or skip if blank)
if archinstall.arguments.get('!encryption-password', None) is None:
if passwd := archinstall.get_password(prompt=str(_('Enter disk encryption password (leave blank for no encryption): '))):
archinstall.arguments['!encryption-password'] = passwd
- if archinstall.arguments.get('!encryption-password', None):
- # If no partitions was marked as encrypted, but a password was supplied and we have some disks to format..
- # Then we need to identify which partitions to encrypt. This will default to / (root).
- if len(list(archinstall.encrypted_partitions(archinstall.arguments['disk_layouts']))) == 0:
- archinstall.arguments['disk_layouts'] = archinstall.select_encrypted_partitions(archinstall.arguments['disk_layouts'], archinstall.arguments['!encryption-password'])
-
- # Ask which boot-loader to use (will only ask if we're in BIOS (non-efi) mode)
- if not archinstall.arguments.get("bootloader", None):
- archinstall.arguments["bootloader"] = archinstall.ask_for_bootloader(archinstall.arguments.get('advanced', False))
-
- if not archinstall.arguments.get('swap', None):
- archinstall.arguments['swap'] = archinstall.ask_for_swap()
+ _, missing = self.mandatory_overview()
+ if check('harddrives'):
+ if not self.option('harddrives').is_empty() and not check('disk_layouts'):
+ missing += 1
+ return missing
def ask_user_questions():
"""
@@ -46,7 +46,11 @@ def ask_user_questions():
Not until we're satisfied with what we want to install
will we continue with the actual installation steps.
"""
- ask_harddrives()
+ with OnlyHDMenu(data_store=archinstall.arguments) as menu:
+ # We select the execution language separated
+ menu.exec_option('archinstall-language')
+ menu.option('archinstall-language').set_enabled(False)
+ menu.run()
def perform_disk_operations():
"""
@@ -56,7 +60,6 @@ def perform_disk_operations():
if archinstall.arguments.get('harddrives', None):
print(f" ! Formatting {archinstall.arguments['harddrives']} in ", end='')
archinstall.do_countdown()
-
"""
Setup the blockdevice, filesystem (and optionally encryption).
Once that's done, we'll hand over to perform_installation()
@@ -66,9 +69,9 @@ def perform_disk_operations():
mode = archinstall.MBR
for drive in archinstall.arguments.get('harddrives', []):
- if dl_disk := archinstall.arguments.get('disk_layouts', {}).get(drive.path):
+ if archinstall.arguments.get('disk_layouts', {}).get(drive.path):
with archinstall.Filesystem(drive, mode) as fs:
- fs.load_layout(dl_disk)
+ fs.load_layout(archinstall.arguments['disk_layouts'][drive.path])
def perform_installation(mountpoint):
"""
diff --git a/examples/swiss.py b/examples/swiss.py
new file mode 100644
index 00000000..fa2d1fb6
--- /dev/null
+++ b/examples/swiss.py
@@ -0,0 +1,512 @@
+"""
+
+Script swiss (army knife)
+Designed to make different workflows for the installation process. Which is controled by the argument --mode
+mode full guides the full process of installation
+mode only_hd only proceeds to the creation of the disk infraestructure (partition, mount points, encryption)
+mode only_os processes only the installation of Archlinux and software at --mountpoint (or /mnt/archinstall)
+mode minimal (still not implemented)
+mode lineal. Instead of a menu, shows a sequence of selection screens (eq. to the old mode for guided.py)
+
+When using the argument --advanced. an aditional menu for several special parameters needed during installation appears
+
+This script respects the --dry_run argument
+
+"""
+import logging
+import os
+import time
+import pathlib
+
+import archinstall
+
+if archinstall.arguments.get('help'):
+ print("See `man archinstall` for help.")
+ exit(0)
+if os.getuid() != 0:
+ print("Archinstall requires root privileges to run. See --help for more.")
+ exit(1)
+
+"""
+particular routines to SetupMenu
+TODO exec con return parameter
+"""
+def select_activate_NTP():
+ prompt = "Would you like to use automatic time synchronization (NTP) with the default time servers? [Y/n]: "
+ choice = archinstall.Menu(prompt, ['yes', 'no'], default_option='yes').run()
+ if choice == 'yes':
+ return True
+ else:
+ return False
+
+
+def select_mode():
+ return archinstall.generic_select(['full','only_hd','only_os','minimal','lineal'],
+ 'Select one execution mode',
+ default=archinstall.arguments.get('mode','full'))
+
+
+"""
+following functions will be at locale_helpers, so they will have to be called prefixed by archinstall
+"""
+def get_locale_mode_text(mode):
+ if mode == 'LC_ALL':
+ mode_text = "general (LC_ALL)"
+ elif mode == "LC_CTYPE":
+ mode_text = "Character set"
+ elif mode == "LC_NUMERIC":
+ mode_text = "Numeric values"
+ elif mode == "LC_TIME":
+ mode_text = "Time Values"
+ elif mode == "LC_COLLATE":
+ mode_text = "sort order"
+ elif mode == "LC_MESSAGES":
+ mode_text = "text messages"
+ else:
+ mode_text = "Unassigned"
+ return mode_text
+
+def reset_cmd_locale():
+ """ sets the cmd_locale to its saved default """
+ archinstall.storage['CMD_LOCALE'] = archinstall.storage.get('CMD_LOCALE_DEFAULT',{})
+
+def unset_cmd_locale():
+ """ archinstall will use the execution environment default """
+ archinstall.storage['CMD_LOCALE'] = {}
+
+def set_cmd_locale(general :str = None,
+ charset :str = 'C',
+ numbers :str = 'C',
+ time :str = 'C',
+ collate :str = 'C',
+ messages :str = 'C'):
+ """
+ Set the cmd locale.
+ If the parameter general is specified, it takes precedence over the rest (might as well not exist)
+ The rest define some specific settings above the installed default language. If anyone of this parameters is none means the installation default
+ """
+ installed_locales = list_installed_locales()
+ result = {}
+ if general:
+ if general in installed_locales:
+ archinstall.storage['CMD_LOCALE'] = {'LC_ALL':general}
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_ALL')} {general} is not installed. Defaulting to C",fg="yellow",level=logging.WARNING)
+ return
+
+ if numbers:
+ if numbers in installed_locales:
+ result["LC_NUMERIC"] = numbers
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_NUMERIC')} {numbers} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
+ if charset:
+ if charset in installed_locales:
+ result["LC_CTYPE"] = charset
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_CTYPE')} {charset} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
+ if time:
+ if time in installed_locales:
+ result["LC_TIME"] = time
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_TIME')} {time} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
+ if collate:
+ if collate in installed_locales:
+ result["LC_COLLATE"] = collate
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_COLLATE')} {collate} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
+ if messages:
+ if messages in installed_locales:
+ result["LC_MESSAGES"] = messages
+ else:
+ archinstall.log(f"{get_locale_mode_text('LC_MESSAGES')} {messages} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
+ archinstall.storage['CMD_LOCALE'] = result
+
+def list_installed_locales() -> list[str]:
+ lista = []
+ for line in archinstall.SysCommand('locale -a'):
+ lista.append(line.decode('UTF-8').strip())
+ return lista
+
+
+"""
+end of locale helpers
+"""
+
+def select_installed_locale(mode):
+ mode_text = get_locale_mode_text(mode)
+ if mode == 'LC_ALL':
+ texto = "Select the default execution locale \nIf none, you will be prompted for specific settings"
+ else:
+ texto = f"Select the {mode_text} ({mode}) execution locale \nIf none, you will get the installation default"
+ return archinstall.generic_select([None] + list_installed_locales(),
+ texto,
+ allow_empty_input=True,
+ default=archinstall.storage.get('CMD_LOCALE',{}).get(mode,'C'))
+
+
+"""
+ _menus
+"""
+
+class SetupMenu(archinstall.GeneralMenu):
+ def __init__(self,storage_area):
+ super().__init__(data_store=storage_area)
+
+ def _setup_selection_menu_options(self):
+ self.set_option('archinstall-language',
+ archinstall.Selector(
+ _('Select Archinstall language'),
+ lambda: self._select_archinstall_language('English'),
+ default='English',
+ enabled=True))
+ self.set_option('ntp',
+ archinstall.Selector(
+ 'Activate NTP',
+ lambda: select_activate_NTP(),
+ default='Y',
+ enabled=True))
+ self.set_option('mode',
+ archinstall.Selector(
+ 'Excution mode',
+ lambda: select_mode(),
+ default='full',
+ enabled=True))
+ for item in ['LC_ALL','LC_CTYPE','LC_NUMERIC','LC_TIME','LC_MESSAGES','LC_COLLATE']:
+ self.set_option(item,
+ archinstall.Selector(
+ f'{get_locale_mode_text(item)} locale',
+ lambda item=item: select_installed_locale(item), # the parmeter is needed for the lambda in the loop
+ enabled=True,
+ dependencies_not=['LC_ALL'] if item != 'LC_ALL' else []))
+ self.option('LC_ALL').set_enabled(True)
+ self.set_option('continue',
+ archinstall.Selector(
+ 'Continue',
+ exec_func=lambda n,v: True,
+ enabled=True))
+
+ def exit_callback(self):
+ if self._data_store.get('ntp',False):
+ archinstall.log("Hardware time and other post-configuration steps might be required in order for NTP to work. For more information, please check the Arch wiki.", fg="yellow")
+ archinstall.SysCommand('timedatectl set-ntp true')
+ if self._data_store.get('mode',None):
+ archinstall.arguments['mode'] = self._data_store['mode']
+ archinstall.log(f"Archinstall will execute under {archinstall.arguments['mode']} mode")
+ if self._data_store.get('LC_ALL',None):
+ archinstall.storage['CMD_LOCALE'] = {'LC_ALL':self._data_store['LC_ALL']}
+ else:
+ exec_locale = {}
+ for item in ['LC_COLLATE','LC_CTYPE','LC_MESSAGES','LC_NUMERIC','LC_TIME']:
+ if self._data_store.get(item,None):
+ exec_locale[item] = self._data_store[item]
+ archinstall.storage['CMD_LOCALE'] = exec_locale
+ archinstall.log(f"Archinstall will execute with {archinstall.storage.get('CMD_LOCALE',None)} locale")
+
+class MyMenu(archinstall.GlobalMenu):
+ def __init__(self,data_store=archinstall.arguments,mode='full'):
+ self._execution_mode = mode
+ super().__init__(data_store)
+
+ def _setup_selection_menu_options(self):
+ super()._setup_selection_menu_options()
+ options_list = []
+ mandatory_list = []
+ if self._execution_mode in ('full','lineal'):
+ options_list = ['keyboard-layout', 'mirror-region', 'harddrives', 'disk_layouts',
+ '!encryption-password','swap', 'bootloader', 'hostname', '!root-password',
+ '!superusers', '!users', 'profile', 'audio', 'kernels', 'packages','nic',
+ 'timezone', 'ntp']
+ if archinstall.arguments.get('advanced',False):
+ options_list.extend(['sys-language','sys-encoding'])
+ mandatory_list = ['harddrives','bootloader','hostname']
+ elif self._execution_mode == 'only_hd':
+ options_list = ['harddrives', 'disk_layouts', '!encryption-password','swap']
+ mandatory_list = ['harddrives']
+ elif self._execution_mode == 'only_os':
+ options_list = ['keyboard-layout', 'mirror-region','bootloader', 'hostname',
+ '!root-password', '!superusers', '!users', 'profile', 'audio', 'kernels',
+ 'packages', 'nic', 'timezone', 'ntp']
+ mandatory_list = ['hostname']
+ if archinstall.arguments.get('advanced',False):
+ options_list.expand(['sys-language','sys-encoding'])
+ elif self._execution_mode == 'minimal':
+ pass
+ else:
+ archinstall.log(f"self._execution_mode {self._execution_mode} not supported")
+ exit(1)
+ if self._execution_mode != 'lineal':
+ options_list.extend(['install','abort'])
+ if not archinstall.arguments.get('advanced'):
+ options_list.append('archinstall-language')
+
+ for entry in self._menu_options:
+ if entry in options_list:
+ # for not lineal executions, only self.option(entry).set_enabled and set_mandatory are necessary
+ if entry in mandatory_list:
+ self.enable(entry,mandatory=True)
+ else:
+ self.enable(entry)
+ else:
+ self.option(entry).set_enabled(False)
+ self._update_install()
+
+ def post_callback(self,option,value=None):
+ self._update_install(self._execution_mode)
+
+ def _missing_configs(self,mode='full'):
+ def check(s):
+ return self.option(s).has_selection()
+
+ _, missing = self.mandatory_overview()
+ if mode in ('full','only_os') and (not check('!root-password') and not check('!superusers')):
+ missing += 1
+ if mode in ('full', 'only_hd') and check('harddrives'):
+ if not self.option('harddrives').is_empty() and not check('disk_layouts'):
+ missing += 1
+ return missing
+
+ def _install_text(self,mode='full'):
+ missing = self._missing_configs(mode)
+ if missing > 0:
+ return f'Instalation ({missing} config(s) missing)'
+ return 'Install'
+
+ def _update_install(self,mode='full'):
+ text = self._install_text(mode)
+ self.option('install').update_description(text)
+
+
+"""
+Instalation general subroutines
+"""
+
+def get_current_status():
+ # Log various information about hardware before starting the installation. This might assist in troubleshooting
+ archinstall.log(f"Hardware model detected: {archinstall.sys_vendor()} {archinstall.product_name()}; UEFI mode: {archinstall.has_uefi()}", level=logging.DEBUG)
+ archinstall.log(f"Processor model detected: {archinstall.cpu_model()}", level=logging.DEBUG)
+ archinstall.log(f"Memory statistics: {archinstall.mem_available()} available out of {archinstall.mem_total()} total installed", level=logging.DEBUG)
+ archinstall.log(f"Virtualization detected: {archinstall.virtualization()}; is VM: {archinstall.is_vm()}", level=logging.DEBUG)
+ archinstall.log(f"Graphics devices detected: {archinstall.graphics_devices().keys()}", level=logging.DEBUG)
+
+ # For support reasons, we'll log the disk layout pre installation to match against post-installation layout
+ archinstall.log(f"Disk states before installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
+
+def ask_user_questions(mode):
+ """
+ First, we'll ask the user for a bunch of user input.
+ Not until we're satisfied with what we want to install
+ will we continue with the actual installation steps.
+ """
+ if archinstall.arguments.get('advanced',None):
+ # 3.9 syntax. former x = {**y,**z} or x.update(y)
+ set_cmd_locale(charset='es_ES.utf8',collate='es_ES.utf8')
+ setup_area = archinstall.storage.get('CMD_LOCALE',{}) | {}
+ with SetupMenu(setup_area) as setup:
+ if mode == 'lineal':
+ for entry in setup.list_enabled_options():
+ if entry in ('continue','abort'):
+ continue
+ if not setup.option(entry).enabled:
+ continue
+ setup.exec_option(entry)
+ else:
+ setup.run()
+ archinstall.arguments['archinstall-language'] = setup_area.get('archinstall-language')
+ else:
+ archinstall.log("Hardware time and other post-configuration steps might be required in order for NTP to work. For more information, please check the Arch wiki.", fg="yellow")
+ archinstall.SysCommand('timedatectl set-ntp true')
+
+ with MyMenu(data_store=archinstall.arguments,mode=mode) as global_menu:
+
+ if mode == 'lineal':
+ for entry in global_menu.list_enabled_options():
+ if entry in ('install','abort'):
+ continue
+ global_menu.exec_option(entry)
+ archinstall.arguments[entry] = global_menu.option(entry).get_selection()
+ else:
+ global_menu.set_option('install',
+ archinstall.Selector(
+ global_menu._install_text(mode),
+ exec_func=lambda n,v: True if global_menu._missing_configs(mode) == 0 else False,
+ enabled=True))
+
+ global_menu.run()
+
+def perform_filesystem_operations():
+ """
+ Issue a final warning before we continue with something un-revertable.
+ We mention the drive one last time, and count from 5 to 0.
+ """
+
+ if archinstall.arguments.get('harddrives', None):
+ print(f" ! Formatting {archinstall.arguments['harddrives']} in ", end='')
+ archinstall.do_countdown()
+
+ """
+ Setup the blockdevice, filesystem (and optionally encryption).
+ Once that's done, we'll hand over to perform_installation()
+ """
+
+ mode = archinstall.GPT
+ if archinstall.has_uefi() is False:
+ mode = archinstall.MBR
+
+ for drive in archinstall.arguments.get('harddrives', []):
+ if archinstall.arguments.get('disk_layouts', {}).get(drive.path):
+ with archinstall.Filesystem(drive, mode) as fs:
+ fs.load_layout(archinstall.arguments['disk_layouts'][drive.path])
+
+def disk_setup(installation):
+ # Mount all the drives to the desired mountpoint
+ # This *can* be done outside of the installation, but the installer can deal with it.
+ if archinstall.arguments.get('disk_layouts'):
+ installation.mount_ordered_layout(archinstall.arguments['disk_layouts'])
+
+ # Placing /boot check during installation because this will catch both re-use and wipe scenarios.
+ for partition in installation.partitions:
+ if partition.mountpoint == installation.target + '/boot':
+ if partition.size < 0.19: # ~200 MiB in GiB
+ raise archinstall.DiskError(
+ f"The selected /boot partition in use is not large enough to properly install a boot loader. Please resize it to at least 200MiB and re-run the installation.")
+
+def os_setup(installation):
+ # if len(mirrors):
+ # Certain services might be running that affects the system during installation.
+ # Currently, only one such service is "reflector.service" which updates /etc/pacman.d/mirrorlist
+ # We need to wait for it before we continue since we opted in to use a custom mirror/region.
+ installation.log('Waiting for automatic mirror selection (reflector) to complete.', level=logging.INFO)
+ while archinstall.service_state('reflector') not in ('dead', 'failed'):
+ time.sleep(1)
+ # Set mirrors used by pacstrap (outside of installation)
+ if archinstall.arguments.get('mirror-region', None):
+ archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium
+ if installation.minimal_installation():
+ installation.set_locale(archinstall.arguments['sys-language'], archinstall.arguments['sys-encoding'].upper())
+ installation.set_hostname(archinstall.arguments['hostname'])
+ if archinstall.arguments['mirror-region'].get("mirrors", None) is not None:
+ installation.set_mirrors(
+ archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
+ if archinstall.arguments["bootloader"] == "grub-install" and archinstall.has_uefi():
+ installation.add_additional_packages("grub")
+ installation.add_bootloader(archinstall.arguments["bootloader"])
+ if archinstall.arguments['swap']:
+ installation.setup_swap('zram')
+
+ # If user selected to copy the current ISO network configuration
+ # Perform a copy of the config
+ if archinstall.arguments.get('nic', {}) == 'Copy ISO network configuration to installation':
+ installation.copy_iso_network_config(
+ enable_services=True) # Sources the ISO network configuration to the install medium.
+ elif archinstall.arguments.get('nic', {}).get('NetworkManager', False):
+ installation.add_additional_packages("networkmanager")
+ installation.enable_service('NetworkManager.service')
+ # Otherwise, if a interface was selected, configure that interface
+ elif archinstall.arguments.get('nic', {}):
+ installation.configure_nic(**archinstall.arguments.get('nic', {}))
+ installation.enable_service('systemd-networkd')
+ installation.enable_service('systemd-resolved')
+
+ if archinstall.arguments.get('audio', None) is not None:
+ installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}",level=logging.INFO)
+ if archinstall.arguments.get('audio', None) == 'pipewire':
+ archinstall.Application(installation, 'pipewire').install()
+ elif archinstall.arguments.get('audio', None) == 'pulseaudio':
+ print('Installing pulseaudio ...')
+ installation.add_additional_packages("pulseaudio")
+ else:
+ installation.log("No audio server will be installed.", level=logging.INFO)
+
+ if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '':
+ installation.add_additional_packages(archinstall.arguments.get('packages', None))
+
+ if archinstall.arguments.get('profile', None):
+ installation.install_profile(archinstall.arguments.get('profile', None))
+
+ for user, user_info in archinstall.arguments.get('!users', {}).items():
+ installation.user_create(user, user_info["!password"], sudo=False)
+
+ for superuser, user_info in archinstall.arguments.get('!superusers', {}).items():
+ installation.user_create(superuser, user_info["!password"], sudo=True)
+
+ if timezone := archinstall.arguments.get('timezone', None):
+ installation.set_timezone(timezone)
+
+ if archinstall.arguments.get('ntp', False):
+ installation.activate_time_syncronization()
+
+ if archinstall.accessibility_tools_in_use():
+ installation.enable_espeakup()
+
+ if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
+ installation.user_set_pw('root', root_pw)
+
+ # This step must be after profile installs to allow profiles to install language pre-requisits.
+ # After which, this step will set the language both for console and x11 if x11 was installed for instance.
+ installation.set_keyboard_language(archinstall.arguments['keyboard-layout'])
+
+ if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_post_install():
+ with archinstall.arguments['profile'].load_instructions(
+ namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported:
+ if not imported._post_install():
+ archinstall.log(' * Profile\'s post configuration requirements was not fulfilled.', fg='red')
+ exit(1)
+
+ # If the user provided a list of services to be enabled, pass the list to the enable_service function.
+ # Note that while it's called enable_service, it can actually take a list of services and iterate it.
+ if archinstall.arguments.get('services', None):
+ installation.enable_service(*archinstall.arguments['services'])
+
+ # If the user provided custom commands to be run post-installation, execute them now.
+ if archinstall.arguments.get('custom-commands', None):
+ archinstall.run_custom_user_commands(archinstall.arguments['custom-commands'], installation)
+
+
+def perform_installation(mountpoint, mode):
+ """
+ Performs the installation steps on a block device.
+ Only requirement is that the block devices are
+ formatted and setup prior to entering this function.
+ """
+ with archinstall.Installer(mountpoint, kernels=archinstall.arguments.get('kernels', ['linux'])) as installation:
+ if mode in ('full','only_hd'):
+ disk_setup(installation)
+ if mode == 'only_hd':
+ target = pathlib.Path(f"{mountpoint}/etc/fstab")
+ if not target.parent.exists():
+ target.parent.mkdir(parents=True)
+
+ if mode in ('full','only_os'):
+ os_setup(installation)
+ installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow")
+ if not archinstall.arguments.get('silent'):
+ prompt = 'Would you like to chroot into the newly created installation and perform post-installation configuration?'
+ choice = archinstall.Menu(prompt, ['yes', 'no'], default_option='yes').run()
+ if choice == 'yes':
+ try:
+ installation.drop_to_shell()
+ except:
+ pass
+
+ # For support reasons, we'll log the disk layout post installation (crash or no crash)
+ archinstall.log(f"Disk states after installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
+
+
+if not archinstall.check_mirror_reachable():
+ log_file = os.path.join(archinstall.storage.get('LOG_PATH', None), archinstall.storage.get('LOG_FILE', None))
+ archinstall.log(f"Arch Linux mirrors are not reachable. Please check your internet connection and the log file '{log_file}'.", level=logging.INFO, fg="red")
+ exit(1)
+
+mode = archinstall.arguments.get('mode', 'full').lower()
+if not archinstall.arguments.get('silent'):
+ ask_user_questions(mode)
+
+archinstall.output_configs(archinstall.arguments,show=False if archinstall.arguments.get('silent') else True)
+if archinstall.arguments.get('dry_run'):
+ exit(0)
+if not archinstall.arguments.get('silent'):
+ input('Press Enter to continue.')
+
+if mode in ('full','only_hd'):
+ perform_filesystem_operations()
+perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'), mode)