def _prep_function(*args, **kwargs) -> bool: """ Magic function called by the importing installer before continuing any further. It also avoids executing any other code in this stage. So it's a safe way to ask the user for more input before any other installer steps start. """ choice = Menu(str(_('Select your desired desktop environment')), __supported__).run() if choice.type_ != MenuSelectionType.Selection: return False if choice.value: # Temporarily store the selected desktop profile # in a session-safe location, since this module will get reloaded # the next time it gets executed. if not archinstall.storage.get('_desktop_profile', None): archinstall.storage['_desktop_profile'] = choice.value if not archinstall.arguments.get('desktop-environment', None): archinstall.arguments['desktop-environment'] = choice.value profile = archinstall.Profile(None, choice.value) # Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered. with profile.load_instructions( namespace=f"{choice.value}.py") as imported: if hasattr(imported, '_prep_function'): return imported._prep_function() else: log(f"Deprecated (??): {choice.value} profile has no _prep_function() anymore" ) exit(1) return False
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 = Menu(prompt, Menu.yes_no(), default_option=Menu.yes()).run() if choice == Menu.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)
def perform_installation(mountpoint): """ 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=None) as 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.storage.get('disk_layouts'): installation.mount_ordered_layout( archinstall.storage['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.25: # in GB 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 256MB and re-run the installation." ) # to generate a fstab directory holder. Avoids an error on exit and at the same time checks the procedure target = pathlib.Path(f"{mountpoint}/etc/fstab") if not target.parent.exists(): target.parent.mkdir(parents=True) # 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)
def _select_profile(self): profile = archinstall.select_profile() # Check the potentially selected profiles preparations to get early checks if some additional questions are needed. if profile and profile.has_prep_function(): namespace = f'{profile.namespace}.py' with profile.load_instructions(namespace=namespace) as imported: if not imported._prep_function(): archinstall.log(' * Profile\'s preparation requirements was not fulfilled.', fg='red') exit(1) return profile
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','additional-repositories','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', 'additional-repositories', '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(['save_config','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_text()
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_installation_steps(): print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) print() input('Press Enter to continue.') """ 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('harddrive', None): print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') archinstall.do_countdown() """ Setup the blockdevice, filesystem (and optionally encryption). Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: # Wipe the entire drive if the disk flag `keep_partitions`is False. if archinstall.arguments['harddrive'].keep_partitions is False: fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs')) # Check if encryption is desired and mark the root partition as encrypted. if archinstall.arguments.get('!encryption-password', None): root_partition = fs.find_partition('/') root_partition.encrypted = True # After the disk is ready, iterate the partitions and check # which ones are safe to format, and format those. for partition in archinstall.arguments['harddrive']: if partition.safe_to_format(): # Partition might be marked as encrypted due to the filesystem type crypt_LUKS # But we might have omitted the encryption password question to skip encryption. # In which case partition.encrypted will be true, but passwd will be false. if partition.encrypted and (passwd := archinstall.arguments.get('!encryption-password', None)): partition.encrypt(password=passwd) else: partition.format() else: archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) fs.find_partition('/boot').format('vfat') if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. # archinstall.luks2() encrypts the partition when entering the with context manager, and # unlocks the drive so that it can be used as a normal block-device within archinstall. with archinstall.luks2(fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: unlocked_device.format(fs.find_partition('/').filesystem) unlocked_device.mount('/mnt') else: fs.find_partition('/').format(fs.find_partition('/').filesystem) fs.find_partition('/').mount('/mnt') fs.find_partition('/boot').mount('/mnt/boot')
def write_config_files(): print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=logging.DEBUG) user_configuration = json.dumps( { **archinstall.arguments, 'version': archinstall.__version__ }, indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_configuration, level=logging.INFO) if archinstall.storage.get('disk_layouts'): user_disk_layout = json.dumps(archinstall.storage['disk_layouts'], indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_disk_layout, level=logging.INFO) print() save_user_configurations() if archinstall.arguments.get('dry-run'): exit(0)
def install_on(mountpoint): # We kick off the installer by telling it where the with archinstall.Installer(mountpoint) as installation: # Strap in the base system, add a boot loader and configure # some other minor details as specified by this profile and user. if installation.minimal_installation(): installation.set_hostname('minimal-arch') installation.add_bootloader() # Optionally enable networking: if archinstall.arguments.get('network', None): installation.copy_ISO_network_config(enable_services=True) installation.add_additional_packages(['nano', 'wget', 'git']) installation.install_profile('minimal') installation.user_create('devel', 'devel') installation.user_set_pw('root', 'airoot') # Once this is done, we output some useful information to the user # And the installation is complete. archinstall.log( f"There are two new accounts in your installation after reboot:") archinstall.log(f" * root (password: airoot)") archinstall.log(f" * devel (password: devel)")
def perform_installation(device, boot_partition, language, mirrors): """ 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(device, boot_partition=boot_partition, hostname=hostname) as 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. archinstall.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') while 'dead' not in (status := archinstall.service_state('reflector')): time.sleep(1) archinstall.use_mirrors(mirrors) # Set the mirrors for the live medium if installation.minimal_installation(): installation.set_mirrors(mirrors) # Set the mirrors in the installation medium installation.set_keyboard_language(language) installation.add_bootloader() if len(packages) and packages[0] != '': installation.add_additional_packages(packages) if len(profile.strip()): installation.install_profile(profile) for user, password in users.items(): sudo = False if len(root_pw.strip()) == 0: sudo = True installation.user_create(user, password, sudo=sudo) if root_pw: installation.user_set_pw('root', root_pw)
def ask_user_questions(): """ 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 not archinstall.arguments.get('keyboard-layout', None): while True: try: archinstall.arguments['keyboard-layout'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() break except archinstall.RequirementError as err: archinstall.log(err, fg="red") # Before continuing, set the preferred keyboard layout/language in the current terminal. # This will just help the user with the next following questions. if len(archinstall.arguments['keyboard-layout']): archinstall.set_keyboard_language(archinstall.arguments['keyboard-layout']) # Set which region to download packages from during the installation if not archinstall.arguments.get('mirror-region', None): while True: try: archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) break except archinstall.RequirementError as e: archinstall.log(e, fg="red") if not archinstall.arguments.get('sys-language', None) and archinstall.arguments.get('advanced', False): archinstall.arguments['sys-language'] = input("Enter a valid locale (language) for your OS, (Default: en_US): ").strip() archinstall.arguments['sys-encoding'] = input("Enter a valid system default encoding for your OS, (Default: utf-8): ").strip() archinstall.log("Keep in mind that if you want multiple locales, post configuration is required.", fg="yellow") if not archinstall.arguments.get('sys-language', None): archinstall.arguments['sys-language'] = 'en_US' if not archinstall.arguments.get('sys-encoding', None): archinstall.arguments['sys-encoding'] = 'utf-8' # Ask which harddrives/block-devices we will install to # and convert them into archinstall.BlockDevice() objects. if archinstall.arguments.get('harddrives', None) is None: _prompt = "Select one or more harddrives to use and configure (leave blank to skip this step): " archinstall.arguments['harddrives'] = archinstall.generic_multi_select(archinstall.all_disks(), text=_prompt, allow_empty=True) if archinstall.arguments.get('harddrives', None) is not None and archinstall.storage.get('disk_layouts', None) is None: archinstall.storage['disk_layouts'] = archinstall.select_disk_layout(archinstall.arguments['harddrives'], archinstall.arguments.get('advanced', False)) # Get disk encryption password (or skip if blank) if archinstall.arguments['harddrives'] and archinstall.arguments.get('!encryption-password', None) is None: if passwd := archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): '): archinstall.arguments['!encryption-password'] = passwd
def perform_filesystem_operations(): print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=logging.DEBUG) user_configuration = json.dumps( { **archinstall.arguments, 'version': archinstall.__version__ }, indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_configuration, level=logging.INFO) if archinstall.arguments.get('disk_layouts'): user_disk_layout = json.dumps(archinstall.arguments['disk_layouts'], indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_disk_layout, level=logging.INFO) print() if archinstall.arguments.get('dry_run'): exit(0) if not archinstall.arguments.get('silent'): input('Press Enter to continue.') """ 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 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.storage.get('disk_layouts', None) is None: archinstall.storage[ 'disk_layouts'] = archinstall.select_disk_layout( archinstall.arguments['harddrives'], archinstall.arguments.get('advanced', False)) # Get disk encryption password (or skip if blank) if archinstall.arguments.get('!encryption-password', None) is None: if passwd := archinstall.get_password( prompt= '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.storage['disk_layouts']))) == 0: archinstall.storage[ 'disk_layouts'] = archinstall.select_encrypted_partitions( archinstall.storage['disk_layouts'], archinstall.arguments['!encryption-password'])
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")
def write_config_files(): print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=logging.DEBUG) user_configuration = json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_configuration, level=logging.INFO) with open("/var/log/archinstall/user_configuration.json", "w") as config_file: config_file.write(user_configuration) if archinstall.storage.get('disk_layouts'): user_disk_layout = json.dumps(archinstall.storage['disk_layouts'], indent=4, sort_keys=True, cls=archinstall.JSON) archinstall.log(user_disk_layout, level=logging.INFO) with open("/var/log/archinstall/user_disk_layout.json", "w") as disk_layout_file: disk_layout_file.write(user_disk_layout) print() if archinstall.arguments.get('dry-run'): exit(0) # it is here so a dry run execution will not save the credentials file ¿? user_credentials = {} if archinstall.arguments.get('!users'): user_credentials["!users"] = archinstall.arguments['!users'] if archinstall.arguments.get('!superusers'): user_credentials["!superusers"] = archinstall.arguments['!superusers'] if archinstall.arguments.get('!encryption-password'): user_credentials["!encryption-password"] = archinstall.arguments[ '!encryption-password'] with open("/var/log/archinstall/user_credentials.json", "w") as config_file: config_file.write( json.dumps(user_credentials, indent=4, sort_keys=True, cls=archinstall.UNSAFE_JSON))
import archinstall # Select a harddrive and a disk password archinstall.log(f"Minimal only supports:") archinstall.log(f" * Being installed to a single disk") if archinstall.arguments.get('help', None): archinstall.log( f" - Optional disk encryption via --!encryption-password=<password>") archinstall.log(f" - Optional filesystem type via --filesystem=<fs type>") archinstall.log(f" - Optional systemd network via --network") archinstall.arguments['harddrive'] = archinstall.select_disk( archinstall.all_disks()) def install_on(mountpoint): # We kick off the installer by telling it where the with archinstall.Installer(mountpoint) as installation: # Strap in the base system, add a boot loader and configure # some other minor details as specified by this profile and user. if installation.minimal_installation(): installation.set_hostname('minimal-arch') installation.add_bootloader() # Optionally enable networking: if archinstall.arguments.get('network', None): installation.copy_ISO_network_config(enable_services=True) installation.add_additional_packages(['nano', 'wget', 'git']) installation.install_profile('minimal')
before continuing any further. """ if not archinstall.storage.get('_selected_servers', None): servers = archinstall.Menu( 'Choose which servers to install, if none then a minimal installation wil be done', available_servers, multi=True).run() archinstall.storage['_selected_servers'] = servers return True if __name__ == 'server': """ This "profile" is a meta-profile. """ archinstall.log('Now installing the selected servers.', level=logging.INFO) archinstall.log(archinstall.storage['_selected_servers'], level=logging.DEBUG) for server in archinstall.storage['_selected_servers']: archinstall.log(f'Installing {server} ...', level=logging.INFO) app = archinstall.Application( archinstall.storage['installation_session'], server) app.install() archinstall.log( 'If your selections included multiple servers with the same port, you may have to reconfigure them.', fg="yellow", level=logging.INFO)
import archinstall import logging # Define the package list in order for lib to source # which packages will be installed by this profile __packages__ = [ "pipewire", "pipewire-alsa", "pipewire-jack", "pipewire-pulse", "gst-plugin-pipewire", "libpulse", "wireplumber" ] archinstall.log('Installing pipewire', level=logging.INFO) archinstall.storage['installation_session'].add_additional_packages( __packages__) @archinstall.plugin def on_user_created(installation: archinstall.Installer, user: str): archinstall.log(f"Enabling pipewire-pulse for {user}", level=logging.INFO) installation.chroot('systemctl enable --user pipewire-pulse.service', run_as=user)
def on_user_created(installation: archinstall.Installer, user: str): archinstall.log(f"Enabling pipewire-pulse for {user}", level=logging.INFO) installation.chroot('systemctl enable --user pipewire-pulse.service', run_as=user)
def ask_user_questions(): """ 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 not archinstall.arguments.get('keyboard-language', None): archinstall.arguments[ 'keyboard-language'] = archinstall.select_language( archinstall.list_keyboard_languages()).strip() # Before continuing, set the preferred keyboard layout/language in the current terminal. # This will just help the user with the next following questions. if len(archinstall.arguments['keyboard-language']): archinstall.set_keyboard_language( archinstall.arguments['keyboard-language']) # Set which region to download packages from during the installation if not archinstall.arguments.get('mirror-region', None): archinstall.arguments[ 'mirror-region'] = archinstall.select_mirror_regions( archinstall.list_mirrors()) else: selected_region = archinstall.arguments['mirror-region'] archinstall.arguments['mirror-region'] = { selected_region: archinstall.list_mirrors()[selected_region] } # Ask which harddrive/block-device we will install to if archinstall.arguments.get('harddrive', None): archinstall.arguments['harddrive'] = archinstall.BlockDevice( archinstall.arguments['harddrive']) else: archinstall.arguments['harddrive'] = archinstall.select_disk( archinstall.all_disks()) # Perform a quick sanity check on the selected harddrive. # 1. Check if it has partitions # 3. Check that we support the current partitions # 2. If so, ask if we should keep them or wipe everything if archinstall.arguments['harddrive'].has_partitions(): archinstall.log( f"{archinstall.arguments['harddrive']} contains the following partitions:", fg='yellow') # We curate a list pf supported paritions # and print those that we don't support. partition_mountpoints = {} for partition in archinstall.arguments['harddrive']: try: if partition.filesystem_supported(): archinstall.log(f" {partition}") partition_mountpoints[partition] = None except archinstall.UnknownFilesystemFormat as err: archinstall.log(f" {partition} (Filesystem not supported)", fg='red') # We then ask what to do with the paritions. if (option := archinstall.ask_for_disk_layout()) == 'abort': archinstall.log( f"Safely aborting the installation. No changes to the disk or system has been made." ) exit(1) elif option == 'keep-existing': archinstall.arguments['harddrive'].keep_partitions = True archinstall.log( f" ** You will now select which partitions to use by selecting mount points (inside the installation). **" ) archinstall.log( f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **" ) while True: # Select a partition partition = archinstall.generic_select( partition_mountpoints.keys(), "Select a partition by number that you want to set a mount-point for (leave blank when done): " ) if not partition: break # Select a mount-point mountpoint = input( f"Enter a mount-point for {partition}: ").strip(' ') if len(mountpoint): # Get a valid & supported filesystem for the parition: while 1: new_filesystem = input( f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): " ).strip(' ') if len(new_filesystem) <= 0: if partition.encrypted and partition.filesystem == 'crypto_LUKS': old_password = archinstall.arguments.get( '!encryption-password', None) if not old_password: old_password = input( f'Enter the old encryption password for {partition}: ' ) if (autodetected_filesystem := partition.detect_inner_filesystem( old_password)): new_filesystem = autodetected_filesystem else: archinstall.log( f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') archinstall.log( f"A filesystem must be defined for the unlocked encrypted partition." ) continue break # Since the potentially new filesystem is new # we have to check if we support it. We can do this by formatting /dev/null with the partitions filesystem. # There's a nice wrapper for this on the partition object itself that supports a path-override during .format() try: partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) except archinstall.UnknownFilesystemFormat: archinstall.log( f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/Torxed/archinstall/issues." ) archinstall.log( f"Until then, please enter another supported filesystem." ) continue except archinstall.SysCallError: pass # Expected exception since mkfs.<format> can not format /dev/null. # But that means our .format() function supported it. break # When we've selected all three criterias, # We can safely mark the partition for formatting and where to mount it. # TODO: allow_formatting might be redundant since target_mountpoint should only be # set if we actually want to format it anyway. partition.allow_formatting = True partition.target_mountpoint = mountpoint # Only overwrite the filesystem definition if we selected one: if len(new_filesystem): partition.filesystem = new_filesystem archinstall.log('Using existing partition table reported above.')
def perform_installation_steps(): global SIG_TRIGGER print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) print() input('Press Enter to continue.') """ Issue a final warning before we continue with something un-revertable. We mention the drive one last time, and count from 5 to 0. """ print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') for i in range(5, 0, -1): print(f"{i}", end='') for x in range(4): sys.stdout.flush() time.sleep(0.25) print(".", end='') if SIG_TRIGGER: abort = input('\nDo you really want to abort (y/n)? ') if abort.strip() != 'n': exit(0) if SIG_TRIGGER is False: sys.stdin.read() SIG_TRIGGER = False signal.signal(signal.SIGINT, sig_handler) # Put back the default/original signal handler now that we're done catching # and interrupting SIGINT with "Do you really want to abort". print() signal.signal(signal.SIGINT, original_sigint_handler) """ Setup the blockdevice, filesystem (and optionally encryption). Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: # Wipe the entire drive if the disk flag `keep_partitions`is False. if archinstall.arguments['harddrive'].keep_partitions is False: fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get( 'filesystem', 'btrfs')) # Check if encryption is desired and mark the root partition as encrypted. if archinstall.arguments.get('!encryption-password', None): root_partition = fs.find_partition('/') root_partition.encrypted = True # After the disk is ready, iterate the partitions and check # which ones are safe to format, and format those. for partition in archinstall.arguments['harddrive']: if partition.safe_to_format(): # Partition might be marked as encrypted due to the filesystem type crypt_LUKS # But we might have omitted the encryption password question to skip encryption. # In which case partition.encrypted will be true, but passwd will be false. if partition.encrypted and (passwd := archinstall.arguments.get( '!encryption-password', None)): partition.encrypt(password=passwd) else: partition.format() else: archinstall.log( f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. # archinstall.luks2() encrypts the partition when entering the with context manager, and # unlocks the drive so that it can be used as a normal block-device within archinstall. with archinstall.luks2( fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: unlocked_device.format(fs.find_partition('/').filesystem) perform_installation( device=unlocked_device, boot_partition=fs.find_partition('/boot'), language=archinstall.arguments['keyboard-language'], mirrors=archinstall.arguments['mirror-region']) else: perform_installation( device=fs.find_partition('/'), boot_partition=fs.find_partition('/boot'), language=archinstall.arguments['keyboard-language'], mirrors=archinstall.arguments['mirror-region'])
def perform_installation(mountpoint): """ 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 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_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 has_uefi(): installation.add_additional_packages("grub") installation.add_bootloader(archinstall.arguments["bootloader"]) # 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': print('Installing pipewire ...') installation.add_additional_packages([ "pipewire", "pipewire-alsa", "pipewire-jack", "pipewire-media-session", "pipewire-pulse", "gst-plugin-pipewire", "libpulse" ]) 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 (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-language']) 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 not archinstall.arguments.get('profile', None): archinstall.arguments['profile'] = archinstall.select_profile( archinstall.list_profiles()) else: archinstall.arguments['profile'] = archinstall.list_profiles()[ archinstall.arguments['profile']] # Check the potentially selected profiles preperations to get early checks if some additional questions are needed. if archinstall.arguments['profile'] and archinstall.arguments[ 'profile'].has_prep_function(): with archinstall.arguments['profile'].load_instructions( namespace=f"{archinstall.arguments['profile'].namespace}.py" ) as imported: if not imported._prep_function(): archinstall.log( ' * Profile\'s preparation requirements was not fulfilled.', bg='black', fg='red') exit(1) # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): archinstall.arguments['packages'] = [ package for package in input( 'Write additional packages to install (space separated, leave blank to skip): ' ).split(' ') if len(package) ] # Verify packages that were given try: archinstall.validate_package_list(archinstall.arguments['packages']) except archinstall.RequirementError as e:
import archinstall from archinstall.lib.general import run_custom_user_commands from archinstall.lib.hardware import * from archinstall.lib.networking import check_mirror_reachable from archinstall.lib.profiles import Profile, is_desktop_profile 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) # 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()}",
import logging import os import time import archinstall from archinstall.lib.general import run_custom_user_commands from archinstall.lib.hardware import has_uefi from archinstall.lib.networking import check_mirror_reachable from archinstall.lib.profiles import Profile if archinstall.arguments.get('help'): print("See `man archinstall` for help.") exit(0) # 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(): """ 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 not archinstall.arguments.get('keyboard-language', None): while True: try: archinstall.arguments[ 'keyboard-language'] = archinstall.select_language( archinstall.list_keyboard_languages()).strip() break
lambda profile: (Profile(None, profile).is_top_level_profile()), archinstall.list_profiles())) else: archinstall.arguments['profile'] = archinstall.list_profiles()[ archinstall.arguments['profile']] # Check the potentially selected profiles preparations to get early checks if some additional questions are needed. if archinstall.arguments['profile'] and archinstall.arguments[ 'profile'].has_prep_function(): with archinstall.arguments['profile'].load_instructions( namespace=f"{archinstall.arguments['profile'].namespace}.py" ) as imported: if not imported._prep_function(): archinstall.log( ' * Profile\'s preparation requirements was not fulfilled.', fg='red') exit(1) # Ask about audio server selection if one is not already set if not archinstall.arguments.get('audio', None): # only ask for audio server selection on a desktop profile if str(archinstall.arguments['profile']) == 'Profile(desktop)': archinstall.arguments[ 'audio'] = archinstall.ask_for_audio_selection() else: # packages installed by a profile may depend on audio and something may get installed anyways, not much we can do about that. # we will not try to remove packages post-installation to not have audio, as that may cause multiple issues archinstall.arguments['audio'] = 'none'
import archinstall, getpass, os from archinstall.lib.general import sys_command # Select a harddrive and a disk password archinstall.log(f"Minimal only supports:") archinstall.log(f" * Being installed to a single disk") USER = "******" class AurPackageSet: def __init__(self, user): self.packages = [] self.user = user def __add__(self, other): self.packages.append(other) return self def __str__(self): user = self.user output = f"""#!/bin/bash mkdir -p /home/{user}/.cache/ cd /home/{user}/.cache """ for package in self.packages: output += f""" git clone https://aur.archlinux.org/{package}.git cd {package} makepkg -si --noconfirm cd .. """ return output
def log_execution_environment(): # 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)
# 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) 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) log_execution_environment() 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) if not archinstall.arguments.get('silent'): ask_user_questions() config_output = ConfigurationOutput(archinstall.arguments) if not archinstall.arguments.get('silent'): config_output.show() config_output.save() if archinstall.arguments.get('dry_run'): exit(0) if not archinstall.arguments.get('silent'): input('Press Enter to continue.')
for kernel in archinstall.storage[ 'installation_session'].kernels: archinstall.storage[ 'installation_session'].add_additional_packages( f"{kernel}-headers" ) # Fixes https://github.com/archlinux/archinstall/issues/585 archinstall.storage[ 'installation_session'].add_additional_packages( "dkms" ) # I've had kernel regen fail if it wasn't installed before nvidia-dkms archinstall.storage[ 'installation_session'].add_additional_packages( "xorg-server xorg-xinit nvidia-dkms") else: archinstall.storage[ 'installation_session'].add_additional_packages( f"xorg-server xorg-xinit {' '.join(archinstall.storage.get('gfx_driver_packages', []))}" ) else: archinstall.storage['installation_session'].add_additional_packages( f"xorg-server xorg-xinit {' '.join(archinstall.storage.get('gfx_driver_packages', []))}" ) except Exception as err: archinstall.log( f"Could not handle nvidia and linuz-zen specific situations during xorg installation: {err}", level=logging.WARNING, fg="yellow") archinstall.storage['installation_session'].add_additional_packages( "xorg-server xorg-xinit" ) # Prep didn't run, so there's no driver to install