Merge branch 'master' into master

This commit is contained in:
Anton Hvornum 2021-09-06 15:01:37 +02:00 committed by GitHub
commit 48fd68124a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 95 additions and 90 deletions

View File

@ -64,7 +64,7 @@ def initialize_arguments():
config[key] = val config[key] = val
config["script"] = args.script config["script"] = args.script
if args.dry_run is not None: if args.dry_run is not None:
config["dry_run"] = args.dry_run config["dry-run"] = args.dry_run
return config return config

View File

@ -347,6 +347,11 @@ class Partition:
raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
self.filesystem = 'ext4' self.filesystem = 'ext4'
elif filesystem == 'ext2':
if (handle := SysCommand(f'/usr/bin/mkfs.ext2 -F {path}')).exit_code != 0:
raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
self.filesystem = 'ext2'
elif filesystem == 'xfs': elif filesystem == 'xfs':
if (handle := SysCommand(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: if (handle := SysCommand(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0:
raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
@ -518,12 +523,24 @@ class Filesystem:
self.blockdevice.partition[0].allow_formatting = True self.blockdevice.partition[0].allow_formatting = True
self.blockdevice.partition[1].allow_formatting = True self.blockdevice.partition[1].allow_formatting = True
else: else:
# we don't need a seprate boot partition it would be a waste of space if not self.parted_mklabel(self.blockdevice.device, "msdos"):
self.add_partition('primary', start='1MB', end='100%') raise KeyError(f"Could not create a MSDOS label on {self}")
self.blockdevice.partition[0].filesystem = root_filesystem_type
log(f"Set the root partition {self.blockdevice.partition[0]} to use filesystem {root_filesystem_type}.", level=logging.DEBUG) self.add_partition('primary', start='1MiB', end='513MiB', partition_format='ext4')
self.blockdevice.partition[0].target_mountpoint = '/' self.set(0, 'boot on')
self.add_partition('primary', start='513MiB', end='100%')
self.blockdevice.partition[0].filesystem = 'ext4' # TODO: Up for debate weither or not this should be user-supplied: https://github.com/archlinux/archinstall/pull/595/files
self.blockdevice.partition[1].filesystem = root_filesystem_type
log(f"Set the boot partition {self.blockdevice.partition[0]} to use filesystem {'ext4'}.", level=logging.DEBUG)
log(f"Set the root partition {self.blockdevice.partition[1]} to use filesystem {root_filesystem_type}.", level=logging.DEBUG)
self.blockdevice.partition[0].target_mountpoint = '/boot'
self.blockdevice.partition[1].target_mountpoint = '/'
self.blockdevice.partition[0].allow_formatting = True self.blockdevice.partition[0].allow_formatting = True
self.blockdevice.partition[1].allow_formatting = True
def add_partition(self, partition_type, start, end, partition_format=None): def add_partition(self, partition_type, start, end, partition_format=None):
log(f'Adding partition to {self.blockdevice}', level=logging.INFO) log(f'Adding partition to {self.blockdevice}', level=logging.INFO)
@ -539,11 +556,9 @@ class Filesystem:
if partitioning: if partitioning:
start_wait = time.time() start_wait = time.time()
while previous_partitions == self.blockdevice.partitions: time.sleep(0.025) # Let the new partition come up in the kernel
time.sleep(0.025) # Let the new partition come up in the kernel if time.time() - start_wait > 20:
if time.time() - start_wait > 10: raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
raise DiskError(f"New partition never showed up after adding new partition on {self} (timeout 10 seconds).")
return True return True
def set_name(self, partition: int, name: str): def set_name(self, partition: int, name: str):

View File

@ -98,10 +98,7 @@ class JsonEncoder:
elif isinstance(obj, (datetime, date)): elif isinstance(obj, (datetime, date)):
return obj.isoformat() return obj.isoformat()
elif isinstance(obj, (list, set, tuple)): elif isinstance(obj, (list, set, tuple)):
r = [] return [json.loads(json.dumps(item, cls=JSON)) for item in obj]
for item in obj:
r.append(json.loads(json.dumps(item, cls=JSON)))
return r
else: else:
return obj return obj

View File

@ -131,7 +131,10 @@ def product_name() -> Optional[str]:
def mem_info(): def mem_info():
# This implementation is from https://stackoverflow.com/a/28161352 # This implementation is from https://stackoverflow.com/a/28161352
return dict((i.split()[0].rstrip(':'), int(i.split()[1])) for i in open('/proc/meminfo').readlines()) return {
i.split()[0].rstrip(':'): int(i.split()[1])
for i in open('/proc/meminfo').readlines()
}
def mem_available() -> Optional[str]: def mem_available() -> Optional[str]:

View File

@ -409,7 +409,7 @@ class Installer:
return True return True
def add_bootloader(self, bootloader='systemd-bootctl'): def add_bootloader(self, _device, bootloader='systemd-bootctl'):
for plugin in plugins.values(): for plugin in plugins.values():
if hasattr(plugin, 'on_add_bootloader'): if hasattr(plugin, 'on_add_bootloader'):
# Allow plugins to override the boot-loader handling. # Allow plugins to override the boot-loader handling.
@ -500,7 +500,16 @@ class Installer:
self.helper_flags['bootloader'] = bootloader self.helper_flags['bootloader'] = bootloader
elif bootloader == "grub-install": elif bootloader == "grub-install":
self.pacstrap('grub') self.pacstrap('grub') # no need?
if real_device := self.detect_encryption(root_partition):
_file = "/etc/default/grub"
root_uuid = SysCommand(f"blkid -s UUID -o value {real_device.path}").decode().rstrip()
add_to_CMDLINE_LINUX = f"sed -i 's/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID={root_uuid}:cryptlvm\"/'"
enable_CRYPTODISK = "sed -i 's/#GRUB_ENABLE_CRYPTODISK=y/GRUB_ENABLE_CRYPTODISK=y/'"
SysCommand(f"/usr/bin/arch-chroot {self.target} {add_to_CMDLINE_LINUX} {_file}")
SysCommand(f"/usr/bin/arch-chroot {self.target} {enable_CRYPTODISK} {_file}")
if has_uefi(): if has_uefi():
self.pacstrap('efibootmgr') self.pacstrap('efibootmgr')
@ -509,10 +518,7 @@ class Installer:
self.helper_flags['bootloader'] = True self.helper_flags['bootloader'] = True
return True return True
else: else:
root_device = subprocess.check_output(f'basename "$(readlink -f /sys/class/block/{root_partition.path.replace("/dev/", "")}/..)"', shell=True).decode().strip() o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc --recheck {_device.path}'))
if root_device == "block":
root_device = f"{root_partition.path}"
o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc /dev/{root_device}'))
SysCommand('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') SysCommand('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg')
self.helper_flags['bootloader'] = True self.helper_flags['bootloader'] = True
else: else:

View File

@ -59,9 +59,7 @@ def filter_mirrors_by_region(regions, destination='/etc/pacman.d/mirrorlist', so
:param regions: A series of country codes separated by `,`. For instance `SE,US` for sweden and United States. :param regions: A series of country codes separated by `,`. For instance `SE,US` for sweden and United States.
:type regions: str :type regions: str
""" """
region_list = [] region_list = [f'country={region}' for region in regions.split(',')]
for region in regions.split(','):
region_list.append(f'country={region}')
response = urllib.request.urlopen(urllib.request.Request(f"https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on'", headers={'User-Agent': 'ArchInstall'})) response = urllib.request.urlopen(urllib.request.Request(f"https://archlinux.org/mirrorlist/?{'&'.join(region_list)}&protocol=https&protocol=http&ip_version=4&ip_version=6&use_mirror_status=on'", headers={'User-Agent': 'ArchInstall'}))
new_list = response.read().replace(b"#Server", b"Server") new_list = response.read().replace(b"#Server", b"Server")

View File

@ -46,10 +46,7 @@ def find_packages(*names):
The function itself is rather slow, so consider not sending to The function itself is rather slow, so consider not sending to
many packages to the search query. many packages to the search query.
""" """
result = {} return {package: find_package(package) for package in names}
for package in names:
result[package] = find_package(package)
return result
def validate_package_list(packages: list): def validate_package_list(packages: list):
@ -57,11 +54,11 @@ def validate_package_list(packages: list):
Validates a list of given packages. Validates a list of given packages.
Raises `RequirementError` if one or more packages are not found. Raises `RequirementError` if one or more packages are not found.
""" """
invalid_packages = [] invalid_packages = [
for package in packages: package
if not find_package(package)['results'] and not find_group(package): for package in packages
invalid_packages.append(package) if not find_package(package)['results'] and not find_group(package)
]
if invalid_packages: if invalid_packages:
raise RequirementError(f"Invalid package names: {invalid_packages}") raise RequirementError(f"Invalid package names: {invalid_packages}")

View File

@ -710,7 +710,8 @@ def select_driver(options=AVAILABLE_GFX_DRIVERS):
if has_nvidia_graphics(): if has_nvidia_graphics():
print('For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.') print('For the best compatibility with your Nvidia hardware, you may want to use the Nvidia proprietary driver.')
arguments['gfx_driver'] = generic_select(drivers, input_text="Select a graphics driver or leave blank to install all open-source drivers: ") if not arguments.get('gfx_driver', None):
arguments['gfx_driver'] = generic_select(drivers, input_text="Select a graphics driver or leave blank to install all open-source drivers: ")
if arguments.get('gfx_driver', None) is None: if arguments.get('gfx_driver', None) is None:
arguments['gfx_driver'] = "All open-source (default)" arguments['gfx_driver'] = "All open-source (default)"

View File

@ -7,9 +7,7 @@ sys.path.insert(0, os.path.abspath('..'))
def process_docstring(app, what, name, obj, options, lines): def process_docstring(app, what, name, obj, options, lines):
spaces_pat = re.compile(r"( {8})") spaces_pat = re.compile(r"( {8})")
ll = [] ll = [spaces_pat.sub(" ", line) for line in lines]
for line in lines:
ll.append(spaces_pat.sub(" ", line))
lines[:] = ll lines[:] = ll

View File

@ -26,6 +26,32 @@ archinstall.log(f"Graphics devices detected: {archinstall.graphics_devices().key
# For support reasons, we'll log the disk layout pre installation to match against post-installation layout # 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) archinstall.log(f"Disk states before installing: {archinstall.disk_layouts()}", level=logging.DEBUG)
def load_config():
if archinstall.arguments.get('harddrive', None) is not None:
archinstall.arguments['harddrive'] = archinstall.BlockDevice(path=archinstall.arguments['harddrive']['path'])
# Temporarily disabling keep_partitions if config file is loaded
archinstall.arguments['harddrive'].keep_partitions = False
# Temporary workaround to make Desktop Environments work
if archinstall.arguments.get('profile', None) is not None:
if type(archinstall.arguments.get('profile', None)) is dict:
archinstall.arguments['profile'] = archinstall.Profile(None, archinstall.arguments.get('profile', None)['path'])
else:
archinstall.arguments['profile'] = archinstall.Profile(None, archinstall.arguments.get('profile', None))
archinstall.storage['_desktop_profile'] = archinstall.arguments.get('desktop-environment', None)
if archinstall.arguments.get('mirror-region', None) is not None:
if type(archinstall.arguments.get('mirror-region', None)) is dict:
archinstall.arguments['mirror-region'] = archinstall.arguments.get('mirror-region', None)
else:
selected_region = archinstall.arguments.get('mirror-region', None)
archinstall.arguments['mirror-region'] = {selected_region: archinstall.list_mirrors()[selected_region]}
if archinstall.arguments.get('sys-language', None) is not None:
archinstall.arguments['sys-language'] = archinstall.arguments.get('sys-language', 'en_US')
if archinstall.arguments.get('sys-encoding', None) is not None:
archinstall.arguments['sys-encoding'] = archinstall.arguments.get('sys-encoding', 'utf-8')
if archinstall.arguments.get('gfx_driver', None) is not None:
archinstall.storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None)
if archinstall.arguments.get('servers', None) is not None:
archinstall.storage['_selected_servers'] = archinstall.arguments.get('servers', None)
def ask_user_questions(): def ask_user_questions():
""" """
@ -54,9 +80,6 @@ def ask_user_questions():
break break
except archinstall.RequirementError as e: except archinstall.RequirementError as e:
archinstall.log(e, fg="red") archinstall.log(e, fg="red")
else:
selected_region = archinstall.arguments['mirror-region']
archinstall.arguments['mirror-region'] = {selected_region: archinstall.list_mirrors()[selected_region]}
if not archinstall.arguments.get('sys-language', None) and archinstall.arguments.get('advanced', False): 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-language'] = input("Enter a valid locale (language) for your OS, (Default: en_US): ").strip()
@ -69,9 +92,7 @@ def ask_user_questions():
archinstall.arguments['sys-encoding'] = 'utf-8' archinstall.arguments['sys-encoding'] = 'utf-8'
# Ask which harddrive/block-device we will install to # Ask which harddrive/block-device we will install to
if archinstall.arguments.get('harddrive', None): if not archinstall.arguments.get('harddrive', None):
archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive'])
else:
archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks())
if archinstall.arguments['harddrive'] is None: if archinstall.arguments['harddrive'] is None:
archinstall.arguments['target-mount'] = archinstall.storage.get('MOUNT_POINT', '/mnt') archinstall.arguments['target-mount'] = archinstall.storage.get('MOUNT_POINT', '/mnt')
@ -188,20 +209,15 @@ def ask_user_questions():
archinstall.arguments['!root-password'] = archinstall.get_password(prompt='Enter root password (Recommendation: leave blank to leave root disabled): ') archinstall.arguments['!root-password'] = archinstall.get_password(prompt='Enter root password (Recommendation: leave blank to leave root disabled): ')
# Ask for additional users (super-user if root pw was not set) # Ask for additional users (super-user if root pw was not set)
archinstall.arguments['users'] = {} if not archinstall.arguments.get('!root-password', None) and not archinstall.arguments.get('superusers', None):
archinstall.arguments['superusers'] = {}
if not archinstall.arguments.get('!root-password', None):
archinstall.arguments['superusers'] = archinstall.ask_for_superuser_account('Create a required super-user with sudo privileges: ', forced=True) archinstall.arguments['superusers'] = archinstall.ask_for_superuser_account('Create a required super-user with sudo privileges: ', forced=True)
users, superusers = archinstall.ask_for_additional_users('Enter a username to create a additional user (leave blank to skip & continue): ')
users, superusers = archinstall.ask_for_additional_users('Enter a username to create a additional user (leave blank to skip & continue): ') archinstall.arguments['users'] = users
archinstall.arguments['users'] = users archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], **superusers}
archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], **superusers}
# Ask for archinstall-specific profiles (such as desktop environments etc) # Ask for archinstall-specific profiles (such as desktop environments etc)
if not archinstall.arguments.get('profile', None): if not archinstall.arguments.get('profile', None):
archinstall.arguments['profile'] = archinstall.select_profile() archinstall.arguments['profile'] = archinstall.select_profile()
else:
archinstall.arguments['profile'] = Profile(installer=None, path=archinstall.arguments['profile'])
# Check the potentially selected profiles preparations to get early checks if some additional questions are needed. # 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(): if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_prep_function():
@ -266,7 +282,7 @@ def perform_installation_steps():
config_file.write(user_configuration) config_file.write(user_configuration)
print() print()
if archinstall.arguments.get('dry_run'): if archinstall.arguments.get('dry-run'):
exit(0) exit(0)
if not archinstall.arguments.get('silent'): if not archinstall.arguments.get('silent'):
@ -322,8 +338,7 @@ def perform_installation_steps():
else: else:
fs.find_partition('/').mount(archinstall.storage.get('MOUNT_POINT', '/mnt')) fs.find_partition('/').mount(archinstall.storage.get('MOUNT_POINT', '/mnt'))
if has_uefi(): fs.find_partition('/boot').mount(archinstall.storage.get('MOUNT_POINT', '/mnt') + '/boot')
fs.find_partition('/boot').mount(archinstall.storage.get('MOUNT_POINT', '/mnt') + '/boot')
perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt')) perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'))
@ -352,7 +367,7 @@ def perform_installation(mountpoint):
installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium installation.set_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors in the installation medium
if archinstall.arguments["bootloader"] == "grub-install" and has_uefi(): if archinstall.arguments["bootloader"] == "grub-install" and has_uefi():
installation.add_additional_packages("grub") installation.add_additional_packages("grub")
installation.add_bootloader(archinstall.arguments["bootloader"]) installation.add_bootloader(archinstall.arguments["harddrive"], archinstall.arguments["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
@ -437,33 +452,8 @@ if not check_mirror_reachable():
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") 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) exit(1)
load_config()
if not archinstall.arguments.get('silent'): if not archinstall.arguments.get('silent'):
ask_user_questions() ask_user_questions()
else:
# Workarounds if config is loaded from a file
# The harddrive section should be moved to perform_installation_steps, where it's actually being performed
# Blockdevice object should be created in perform_installation_steps
# This needs to be done until then
archinstall.arguments['harddrive'] = archinstall.BlockDevice(path=archinstall.arguments['harddrive']['path'])
# Temporarily disabling keep_partitions if config file is loaded
archinstall.arguments['harddrive'].keep_partitions = False
# Temporary workaround to make Desktop Environments work
if archinstall.arguments.get('profile', None) is not None:
if type(archinstall.arguments.get('profile', None)) is dict:
archinstall.arguments['profile'] = archinstall.Profile(None, archinstall.arguments.get('profile', None)['path'])
else:
archinstall.arguments['profile'] = archinstall.Profile(None, archinstall.arguments.get('profile', None))
else:
archinstall.arguments['profile'] = None
if archinstall.arguments.get('mirror-region', None) is not None:
if type(archinstall.arguments.get('mirror-region', None)) is dict:
archinstall.arguments['mirror-region'] = archinstall.arguments.get('mirror-region', None)
else:
selected_region = archinstall.arguments.get('mirror-region', None)
archinstall.arguments['mirror-region'] = {selected_region: archinstall.list_mirrors()[selected_region]}
archinstall.arguments['sys-language'] = archinstall.arguments.get('sys-language', 'en_US')
archinstall.arguments['sys-encoding'] = archinstall.arguments.get('sys-encoding', 'utf-8')
if archinstall.arguments.get('gfx_driver', None) is not None:
archinstall.storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), None)
perform_installation_steps() perform_installation_steps()

View File

@ -50,12 +50,11 @@ def _prep_function(*args, **kwargs):
# Temporarily store the selected desktop profile # Temporarily store the selected desktop profile
# in a session-safe location, since this module will get reloaded # in a session-safe location, since this module will get reloaded
# the next time it gets executed. # the next time it gets executed.
if '_desktop_profile' not in archinstall.storage.keys(): if not archinstall.storage.get('_desktop_profile', None):
archinstall.storage['_desktop_profile'] = desktop archinstall.storage['_desktop_profile'] = desktop
if not archinstall.arguments.get('desktop-environment', None):
archinstall.arguments['desktop-environment'] = desktop
profile = archinstall.Profile(None, desktop) profile = archinstall.Profile(None, desktop)
# Set the resolved profile path to the actual desktop environment
archinstall.arguments['profile'] = profile
# Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered. # Loading the instructions with a custom namespace, ensures that a __name__ comparison is never triggered.
with profile.load_instructions(namespace=f"{desktop}.py") as imported: with profile.load_instructions(namespace=f"{desktop}.py") as imported:
if hasattr(imported, '_prep_function'): if hasattr(imported, '_prep_function'):

View File

@ -26,8 +26,9 @@ def _prep_function(*args, **kwargs):
Magic function called by the importing installer Magic function called by the importing installer
before continuing any further. before continuing any further.
""" """
selected_servers = archinstall.generic_multi_select(available_servers, "Choose which servers to install and enable (leave blank for a minimal installation): ") if not archinstall.storage.get('_selected_servers', None):
archinstall.storage['_selected_servers'] = selected_servers selected_servers = archinstall.generic_multi_select(available_servers, "Choose which servers to install and enable (leave blank for a minimal installation): ")
archinstall.storage['_selected_servers'] = selected_servers
return True return True