Merging in master to feature branch.

This commit is contained in:
Anton Hvornum 2021-04-17 09:52:09 +02:00
commit 5fba277dda
12 changed files with 138 additions and 82 deletions

View File

@ -2,7 +2,16 @@
name: Build Arch ISO with ArchInstall Commit name: Build Arch ISO with ArchInstall Commit
on: pull_request on:
pull_request:
paths-ignore:
- '.github/**'
- 'docs/**'
- '**.editorconfig'
- '**.gitignore'
- '**.md'
- 'LICENSE'
- 'PKGBUILD'
jobs: jobs:
build: build:

View File

@ -1,4 +1,9 @@
# <img src="https://github.com/archlinux/archinstall/raw/master/docs/logo.png" alt="drawing" width="200"/> <!-- <div align="center"> -->
<img src="https://github.com/archlinux/archinstall/raw/master/docs/logo.png" alt="drawing" width="200"/>
# Arch Installer
<!-- </div> -->
Just another guided/automated [Arch Linux](https://wiki.archlinux.org/index.php/Arch_Linux) installer with a twist. Just another guided/automated [Arch Linux](https://wiki.archlinux.org/index.php/Arch_Linux) installer with a twist.
The installer also doubles as a python library to install Arch Linux and manage services, packages and other things inside the installed system *(Usually from a live medium)*. The installer also doubles as a python library to install Arch Linux and manage services, packages and other things inside the installed system *(Usually from a live medium)*.
@ -51,7 +56,7 @@ disk_password = getpass.getpass(prompt='Disk password (won\'t echo): ')
harddrive.keep_partitions = False harddrive.keep_partitions = False
# First, we configure the basic filesystem layout # First, we configure the basic filesystem layout
with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: with archinstall.Filesystem(harddrive, archinstall.GPT) as fs:
# We create a filesystem layout that will use the entire drive # We create a filesystem layout that will use the entire drive
# (this is a helper function, you can partition manually as well) # (this is a helper function, you can partition manually as well)
fs.use_entire_disk(root_filesystem_type='btrfs') fs.use_entire_disk(root_filesystem_type='btrfs')
@ -61,9 +66,9 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT)
boot.format('vfat') boot.format('vfat')
# Set the flat for encrypted to allow for encryption and then encrypt # Set the flag for encrypted to allow for encryption and then encrypt
root.encrypted = True root.encrypted = True
root.encrypt(password=archinstall.arguments.get('!encryption-password', None)) root.encrypt(password=disk_password)
with archinstall.luks2(root, 'luksloop', disk_password) as unlocked_root: with archinstall.luks2(root, 'luksloop', disk_password) as unlocked_root:
unlocked_root.format(root.filesystem) unlocked_root.format(root.filesystem)

View File

@ -76,7 +76,7 @@ class sys_command():#Thread):
""" """
Stolen from archinstall_gui Stolen from archinstall_gui
""" """
def __init__(self, cmd, callback=None, start_callback=None, peak_output=False, *args, **kwargs): def __init__(self, cmd, callback=None, start_callback=None, peak_output=False, environment_vars={}, *args, **kwargs):
kwargs.setdefault("worker_id", gen_uid()) kwargs.setdefault("worker_id", gen_uid())
kwargs.setdefault("emulate", False) kwargs.setdefault("emulate", False)
kwargs.setdefault("suppress_errors", False) kwargs.setdefault("suppress_errors", False)
@ -102,6 +102,7 @@ class sys_command():#Thread):
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.peak_output = peak_output self.peak_output = peak_output
self.environment_vars = environment_vars
self.kwargs.setdefault("worker", None) self.kwargs.setdefault("worker", None)
self.callback = callback self.callback = callback
@ -200,7 +201,7 @@ class sys_command():#Thread):
# Replace child process with our main process # Replace child process with our main process
if not self.kwargs['emulate']: if not self.kwargs['emulate']:
try: try:
os.execv(self.cmd[0], self.cmd) os.execve(self.cmd[0], self.cmd, {**os.environ, **self.environment_vars})
except FileNotFoundError: except FileNotFoundError:
self.status = 'done' self.status = 'done'
self.log(f"{self.cmd[0]} does not exist.", level=LOG_LEVELS.Debug) self.log(f"{self.cmd[0]} does not exist.", level=LOG_LEVELS.Debug)
@ -304,6 +305,11 @@ class sys_command():#Thread):
with open(f'{self.cwd}/trace.log', 'wb') as fh: with open(f'{self.cwd}/trace.log', 'wb') as fh:
fh.write(self.trace_log) fh.write(self.trace_log)
try:
os.close(child_fd)
except:
pass
def prerequisite_check(): def prerequisite_check():
if not os.path.isdir("/sys/firmware/efi"): if not os.path.isdir("/sys/firmware/efi"):

View File

@ -86,6 +86,7 @@ class Installer():
if not (missing_steps := self.post_install_check()): if not (missing_steps := self.post_install_check()):
self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info) self.log('Installation completed without any errors. You may now reboot.', bg='black', fg='green', level=LOG_LEVELS.Info)
self.sync_log_to_install_medium() self.sync_log_to_install_medium()
return True return True
else: else:
self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning) self.log('Some required steps were not successfully installed/configured before leaving the installer:', bg='black', fg='red', level=LOG_LEVELS.Warning)
@ -195,6 +196,9 @@ class Installer():
def arch_chroot(self, cmd, *args, **kwargs): def arch_chroot(self, cmd, *args, **kwargs):
return self.run_command(cmd) return self.run_command(cmd)
def drop_to_shell(self):
subprocess.check_call(f"/usr/bin/arch-chroot {self.target}", shell=True)
def configure_nic(self, nic, dhcp=True, ip=None, gateway=None, dns=None, *args, **kwargs): def configure_nic(self, nic, dhcp=True, ip=None, gateway=None, dns=None, *args, **kwargs):
if dhcp: if dhcp:
conf = Networkd(Match={"Name": nic}, Network={"DHCP": "yes"}) conf = Networkd(Match={"Name": nic}, Network={"DHCP": "yes"})
@ -474,10 +478,18 @@ class Installer():
o = b''.join(sys_command(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\"")) o = b''.join(sys_command(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{user}:{password}' | chpasswd\""))
pass pass
def user_set_shell(self, user, shell):
self.log(f'Setting shell for {user} to {shell}', level=LOG_LEVELS.Info)
o = b''.join(sys_command(f"/usr/bin/arch-chroot {self.target} sh -c \"chsh -s {shell} {user}\""))
pass
def set_keyboard_language(self, language): def set_keyboard_language(self, language):
if len(language.strip()): if len(language.strip()):
with open(f'{self.target}/etc/vconsole.conf', 'w') as vconsole: with open(f'{self.target}/etc/vconsole.conf', 'w') as vconsole:
vconsole.write(f'KEYMAP={language}\n') vconsole.write(f'KEYMAP={language}\n')
vconsole.write(f'FONT=lat9w-16\n') vconsole.write(f'FONT=lat9w-16\n')
else:
self.log(f'Keyboard language was not changed from default (no language specified).', fg="yellow", level=LOG_LEVELS.Info)
return True return True

View File

@ -1,29 +1,25 @@
import subprocess
import os import os
from .exceptions import * from .exceptions import *
# from .general import sys_command # from .general import sys_command
def list_keyboard_languages(layout='qwerty'): def list_keyboard_languages():
locale_dir = '/usr/share/kbd/keymaps/' locale_dir = '/usr/share/kbd/keymaps/'
if not os.path.isdir(locale_dir): if not os.path.isdir(locale_dir):
raise RequirementError(f'Directory containing locales does not exist: {locale_dir}') raise RequirementError(f'Directory containing locales does not exist: {locale_dir}')
for root, folders, files in os.walk(locale_dir): for root, folders, files in os.walk(locale_dir):
# Since qwerty is under /i386/ but other layouts are
# in different spots, we'll need to filter the last foldername
# of the path to verify against the desired layout.
if os.path.basename(root) != layout:
continue
for file in files: for file in files:
if os.path.splitext(file)[1] == '.gz': if os.path.splitext(file)[1] == '.gz':
yield file.strip('.gz').strip('.map') yield file.strip('.gz').strip('.map')
def search_keyboard_layout(filter, layout='qwerty'): def search_keyboard_layout(filter):
for language in list_keyboard_languages(layout): for language in list_keyboard_languages():
if filter.lower() in language.lower(): if filter.lower() in language.lower():
yield language yield language
def set_keyboard_language(locale): def set_keyboard_language(locale):
return os.system(f'loadkeys {locale}') == 0 return subprocess.call(['loadkeys', locale]) == 0

View File

@ -74,10 +74,15 @@ def re_rank_mirrors(top=10, *positionals, **kwargs):
def list_mirrors(): def list_mirrors():
url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on" url = f"https://archlinux.org/mirrorlist/?protocol=https&ip_version=4&ip_version=6&use_mirror_status=on"
response = urllib.request.urlopen(url)
regions = {} regions = {}
try:
response = urllib.request.urlopen(url)
except urllib.error.URLError as err:
log(f'Could not fetch an active mirror-list: {err}', level=LOG_LEVELS.Warning, fg="yellow")
return regions
region = 'Unknown region' region = 'Unknown region'
for line in response.readlines(): for line in response.readlines():
if len(line.strip()) == 0: if len(line.strip()) == 0:

View File

@ -177,7 +177,7 @@ class Profile(Script):
if hasattr(imported, '_prep_function'): if hasattr(imported, '_prep_function'):
return True return True
return False return False
"""
def has_post_install(self): def has_post_install(self):
with open(self.path, 'r') as source: with open(self.path, 'r') as source:
source_data = source.read() source_data = source.read()
@ -193,7 +193,6 @@ class Profile(Script):
with self.load_instructions(namespace=f"{self.namespace}.py") as imported: with self.load_instructions(namespace=f"{self.namespace}.py") as imported:
if hasattr(imported, '_post_install'): if hasattr(imported, '_post_install'):
return True return True
"""
def is_top_level_profile(self): def is_top_level_profile(self):
with open(self.path, 'r') as source: with open(self.path, 'r') as source:

View File

@ -7,6 +7,6 @@ def service_state(service_name: str):
if os.path.splitext(service_name)[1] != '.service': if os.path.splitext(service_name)[1] != '.service':
service_name += '.service' # Just to be safe service_name += '.service' # Just to be safe
state = b''.join(sys_command(f'systemctl show -p SubState --value {service_name}')) state = b''.join(sys_command(f'systemctl show --no-pager -p SubState --value {service_name}', environment_vars={'SYSTEMD_COLORS' : '0'}))
return state.strip().decode('UTF-8') return state.strip().decode('UTF-8')

View File

@ -132,7 +132,9 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan
return users, super_users return users, super_users
def ask_for_a_timezone(): def ask_for_a_timezone():
timezone = input('Enter a valid timezone (Example: Europe/Stockholm): ').strip() timezone = input('Enter a valid timezone (examples: Europe/Stockholm, US/Eastern) or press enter to use UTC: ').strip()
if timezone == '':
timezone = 'UTC'
if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists():
return timezone return timezone
else: else:
@ -186,7 +188,7 @@ def ask_to_configure_network():
elif nic: elif nic:
return nic return nic
return None return {}
def ask_for_disk_layout(): def ask_for_disk_layout():
options = { options = {
@ -323,6 +325,8 @@ def select_language(options, show_only_country_codes=True):
:return: The language/dictionary key of the selected language :return: The language/dictionary key of the selected language
:rtype: str :rtype: str
""" """
DEFAULT_KEYBOARD_LANGUAGE = 'us'
if show_only_country_codes: if show_only_country_codes:
languages = sorted([language for language in list(options) if len(language) == 2]) languages = sorted([language for language in list(options) if len(language) == 2])
else: else:
@ -332,9 +336,12 @@ def select_language(options, show_only_country_codes=True):
for index, language in enumerate(languages): for index, language in enumerate(languages):
print(f"{index}: {language}") print(f"{index}: {language}")
print(' -- You can enter ? or help to search for more languages --') print(' -- You can enter ? or help to search for more languages, or skip to use US layout --')
selected_language = input('Select one of the above keyboard languages (by number or full name): ') selected_language = input('Select one of the above keyboard languages (by number or full name): ')
if selected_language.lower() in ('?', 'help'):
if len(selected_language.strip()) == 0:
return DEFAULT_KEYBOARD_LANGUAGE
elif selected_language.lower() in ('?', 'help'):
while True: while True:
filter_string = input('Search for layout containing (example: "sv-"): ') filter_string = input('Search for layout containing (example: "sv-"): ')
new_options = list(search_keyboard_layout(filter_string)) new_options = list(search_keyboard_layout(filter_string))
@ -347,6 +354,7 @@ def select_language(options, show_only_country_codes=True):
elif selected_language.isdigit() and (pos := int(selected_language)) <= len(languages)-1: elif selected_language.isdigit() and (pos := int(selected_language)) <= len(languages)-1:
selected_language = languages[pos] selected_language = languages[pos]
return selected_language
# I'm leaving "options" on purpose here. # I'm leaving "options" on purpose here.
# Since languages possibly contains a filtered version of # Since languages possibly contains a filtered version of
# all possible language layouts, and we might want to write # all possible language layouts, and we might want to write
@ -354,9 +362,9 @@ def select_language(options, show_only_country_codes=True):
# go through the search step. # go through the search step.
elif selected_language in options: elif selected_language in options:
selected_language = options[options.index(selected_language)] selected_language = options[options.index(selected_language)]
return selected_language
else: else:
RequirementError("Selected language does not exist.") raise RequirementError("Selected language does not exist.")
return selected_language
raise RequirementError("Selecting languages require a least one language to be given as an option.") raise RequirementError("Selecting languages require a least one language to be given as an option.")
@ -380,27 +388,30 @@ def select_mirror_regions(mirrors, show_top_mirrors=True):
selected_mirrors = {} selected_mirrors = {}
if len(regions) >= 1: if len(regions) >= 1:
print_large_list(regions, margin_bottom=2) print_large_list(regions, margin_bottom=4)
print(' -- You can skip this step by leaving the option blank --') print(' -- You can skip this step by leaving the option blank --')
selected_mirror = input('Select one of the above regions to download packages from (by number or full name): ') selected_mirror = input('Select one of the above regions to download packages from (by number or full name): ')
if len(selected_mirror.strip()) == 0: if len(selected_mirror.strip()) == 0:
# Returning back empty options which can be both used to
# do "if x:" logic as well as do `x.get('mirror', {}).get('sub', None)` chaining
return {} return {}
elif selected_mirror.isdigit() and (pos := int(selected_mirror)) <= len(regions)-1: elif selected_mirror.isdigit() and int(selected_mirror) <= len(regions)-1:
# I'm leaving "mirrors" on purpose here.
# Since region possibly contains a known region of
# all possible regions, and we might want to write
# for instance Sweden (if we know that exists) without having to
# go through the search step.
region = regions[int(selected_mirror)] region = regions[int(selected_mirror)]
selected_mirrors[region] = mirrors[region] selected_mirrors[region] = mirrors[region]
# I'm leaving "mirrors" on purpose here.
# Since region possibly contains a known region of
# all possible regions, and we might want to write
# for instance Sweden (if we know that exists) without having to
# go through the search step.
elif selected_mirror in mirrors: elif selected_mirror in mirrors:
selected_mirrors[selected_mirror] = mirrors[selected_mirror] selected_mirrors[selected_mirror] = mirrors[selected_mirror]
else: else:
RequirementError("Selected region does not exist.") raise RequirementError("Selected region does not exist.")
return selected_mirrors return selected_mirrors
<<<<<<< HEAD
raise RequirementError("Selecting mirror region require a least one region to be given as an option.") raise RequirementError("Selecting mirror region require a least one region to be given as an option.")

View File

@ -3,24 +3,6 @@ import archinstall
from archinstall.lib.hardware import hasUEFI from archinstall.lib.hardware import hasUEFI
from archinstall.lib.profiles import Profile from archinstall.lib.profiles import Profile
"""
This signal-handler chain (and global variable)
is used to trigger the "Are you sure you want to abort?" question further down.
It might look a bit odd, but have a look at the line: "if SIG_TRIGGER:"
"""
SIG_TRIGGER = False
def kill_handler(sig, frame):
print()
exit(0)
def sig_handler(sig, frame):
global SIG_TRIGGER
SIG_TRIGGER = True
signal.signal(signal.SIGINT, kill_handler)
original_sigint_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, sig_handler)
if archinstall.arguments.get('help'): if archinstall.arguments.get('help'):
print("See `man archinstall` for help.") print("See `man archinstall` for help.")
exit(0) exit(0)
@ -32,7 +14,12 @@ def ask_user_questions():
will we continue with the actual installation steps. will we continue with the actual installation steps.
""" """
if not archinstall.arguments.get('keyboard-language', None): if not archinstall.arguments.get('keyboard-language', None):
archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() while True:
try:
archinstall.arguments['keyboard-language'] = 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. # Before continuing, set the preferred keyboard layout/language in the current terminal.
# This will just help the user with the next following questions. # This will just help the user with the next following questions.
@ -41,7 +28,12 @@ def ask_user_questions():
# Set which region to download packages from during the installation # Set which region to download packages from during the installation
if not archinstall.arguments.get('mirror-region', None): if not archinstall.arguments.get('mirror-region', None):
archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) 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")
else: else:
selected_region = archinstall.arguments['mirror-region'] selected_region = archinstall.arguments['mirror-region']
archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]} archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]}
@ -193,22 +185,27 @@ def ask_user_questions():
else: else:
# packages installed by a profile may depend on audio and something may get installed anyways, not much we can do about that. # 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 # we will not try to remove packages post-installation to not have audio, as that may cause multiple issues
archinstall.arguments['audio'] = 'none' archinstall.arguments['audio'] = None
# Additional packages (with some light weight error handling for invalid package names) # Additional packages (with some light weight error handling for invalid package names)
if not archinstall.arguments.get('packages', None): while True:
print("Packages not part of the desktop environment are not installed by default.") if not archinstall.arguments.get('packages', None):
print("If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.") print("Only packages such as base, base-devel, linux, linux-firmware, efibootmgr and optional profile packages are installed.")
archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)] print("If you desire a web browser, such as firefox or chromium, you may specify it in the following prompt.")
archinstall.arguments['packages'] = [package for package in input('Write additional packages to install (space separated, leave blank to skip): ').split(' ') if len(package)]
if len(archinstall.arguments['packages']): if len(archinstall.arguments['packages']):
# Verify packages that were given # Verify packages that were given
try: try:
archinstall.log(f"Verifying that additional packages exist (this might take a few seconds)") archinstall.log(f"Verifying that additional packages exist (this might take a few seconds)")
archinstall.validate_package_list(archinstall.arguments['packages']) archinstall.validate_package_list(archinstall.arguments['packages'])
except archinstall.RequirementError as e: break
archinstall.log(e, fg='red') except archinstall.RequirementError as e:
exit(1) archinstall.log(e, fg='red')
archinstall.arguments['packages'] = None # Clear the packages to trigger a new input question
else:
# no additional packages were selected, which we'll allow
break
# Ask or Call the helper function that asks the user to optionally configure a network. # Ask or Call the helper function that asks the user to optionally configure a network.
if not archinstall.arguments.get('nic', None): if not archinstall.arguments.get('nic', None):
@ -299,32 +296,36 @@ def perform_installation(mountpoint):
# Certain services might be running that affects the system during installation. # 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 # 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. # We need to wait for it before we continue since we opted in to use a custom mirror/region.
installation.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') installation.log(f'Waiting for automatic mirror selection (reflector) to complete.', level=archinstall.LOG_LEVELS.Info)
while 'dead' not in (status := archinstall.service_state('reflector')): while archinstall.service_state('reflector') not in ('dead', 'failed'):
time.sleep(1) time.sleep(1)
archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium # 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(): if installation.minimal_installation():
installation.set_hostname(archinstall.arguments['hostname']) installation.set_hostname(archinstall.arguments['hostname'])
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium if archinstall.arguments['mirror-region'].get("mirrors",{})!= None:
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
installation.set_keyboard_language(archinstall.arguments['keyboard-language']) installation.set_keyboard_language(archinstall.arguments['keyboard-language'])
installation.add_bootloader() installation.add_bootloader()
# If user selected to copy the current ISO network configuration # If user selected to copy the current ISO network configuration
# Perform a copy of the config # Perform a copy of the config
if archinstall.arguments.get('nic', None) == 'Copy ISO network configuration to installation': 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. 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): elif archinstall.arguments.get('nic', {}).get('NetworkManager',False):
installation.add_additional_packages("networkmanager") installation.add_additional_packages("networkmanager")
installation.enable_service('NetworkManager.service') installation.enable_service('NetworkManager.service')
# Otherwise, if a interface was selected, configure that interface # Otherwise, if a interface was selected, configure that interface
elif archinstall.arguments.get('nic', None): elif archinstall.arguments.get('nic', {}):
installation.configure_nic(**archinstall.arguments.get('nic', {})) installation.configure_nic(**archinstall.arguments.get('nic', {}))
installation.enable_service('systemd-networkd') installation.enable_service('systemd-networkd')
installation.enable_service('systemd-resolved') installation.enable_service('systemd-resolved')
if archinstall.arguments.get('audio', None) != None: if archinstall.arguments.get('audio', None) != None:
installation.log(f"The {archinstall.arguments.get('audio', None)} audio server will be used.", level=archinstall.LOG_LEVELS.Info) installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=archinstall.LOG_LEVELS.Info)
if archinstall.arguments.get('audio', None) == 'pipewire': if archinstall.arguments.get('audio', None) == 'pipewire':
print('Installing pipewire ...') print('Installing pipewire ...')
@ -332,6 +333,8 @@ def perform_installation(mountpoint):
elif archinstall.arguments.get('audio', None) == 'pulseaudio': elif archinstall.arguments.get('audio', None) == 'pulseaudio':
print('Installing pulseaudio ...') print('Installing pulseaudio ...')
installation.add_additional_packages("pulseaudio") installation.add_additional_packages("pulseaudio")
else:
installation.log("No audio server will be installed.", level=archinstall.LOG_LEVELS.Info)
if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '':
installation.add_additional_packages(archinstall.arguments.get('packages', None)) installation.add_additional_packages(archinstall.arguments.get('packages', None))
@ -350,6 +353,7 @@ def perform_installation(mountpoint):
if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
installation.user_set_pw('root', root_pw) installation.user_set_pw('root', root_pw)
if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_post_install(): 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: with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported:
if not imported._post_install(): if not imported._post_install():
@ -359,5 +363,14 @@ def perform_installation(mountpoint):
) )
exit(1) exit(1)
installation.log("For post-installation tips, see https://wiki.archlinux.org/index.php/Installation_guide#Post-installation", fg="yellow")
choice = input("Would you like to chroot into the newly created installation and perform post-installation configuration? [Y/n] ")
if choice.lower() in ("y", ""):
try:
installation.drop_to_shell()
except:
pass
ask_user_questions() ask_user_questions()
perform_installation_steps() perform_installation_steps()

View File

@ -6,7 +6,7 @@ installation.install_profile('xorg')
installation.add_additional_packages(__packages__) installation.add_additional_packages(__packages__)
with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'r') as xinitrc: with open(f'{installation.target}/etc/X11/xinit/xinitrc', 'r') as xinitrc:
xinitrc_data = xinitrc.read() xinitrc_data = xinitrc.read()
for line in xinitrc_data.split('\n'): for line in xinitrc_data.split('\n'):
@ -20,5 +20,5 @@ for line in xinitrc_data.split('\n'):
xinitrc_data += '\n' xinitrc_data += '\n'
xinitrc_data += 'exec awesome\n' xinitrc_data += 'exec awesome\n'
with open(f'{installation.mountpoint}/etc/X11/xinit/xinitrc', 'w') as xinitrc: with open(f'{installation.target}/etc/X11/xinit/xinitrc', 'w') as xinitrc:
xinitrc.write(xinitrc_data) xinitrc.write(xinitrc_data)

View File

@ -39,13 +39,13 @@ if __name__ == 'awesome':
alacritty.install() alacritty.install()
# TODO: Copy a full configuration to ~/.config/awesome/rc.lua instead. # TODO: Copy a full configuration to ~/.config/awesome/rc.lua instead.
with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'r') as fh: with open(f'{installation.target}/etc/xdg/awesome/rc.lua', 'r') as fh:
awesome_lua = fh.read() awesome_lua = fh.read()
## Replace xterm with alacritty for a smoother experience. ## Replace xterm with alacritty for a smoother experience.
awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"') awesome_lua = awesome_lua.replace('"xterm"', '"alacritty"')
with open(f'{installation.mountpoint}/etc/xdg/awesome/rc.lua', 'w') as fh: with open(f'{installation.target}/etc/xdg/awesome/rc.lua', 'w') as fh:
fh.write(awesome_lua) fh.write(awesome_lua)
## TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config) ## TODO: Configure the right-click-menu to contain the above packages that were installed. (as a user config)