Merge branch 'master' into svintooo-fix

Sync branch svintooo-fix with latest code changes on master.
This commit is contained in:
Hugo Ankarloo 2021-09-20 21:52:14 +02:00
commit e71a41377d
10 changed files with 75 additions and 51 deletions

View File

@ -1,8 +1,7 @@
# Contributing to archinstall # Contributing to archinstall
Any contributions through pull requests are welcome as this project aims to be a community based project to ease some Arch Linux installation steps. Any contributions through pull requests are welcome as this project aims to be a community based project to ease some Arch Linux installation steps.
Bear in mind that in the future this repo might be transferred to the official [GitLab repo under Arch Linux](http://gitlab.archlinux.org/archlinux/) Bear in mind that in the future this repo might be transferred to the official [GitLab repo under Arch Linux](http://gitlab.archlinux.org/archlinux/) *(if GitLab becomes open to the general public)*.
*(if GitLab becomes open to the general public)*.
Therefore, guidelines and style changes to the code might come into effect as well as guidelines surrounding bug reporting and discussions. Therefore, guidelines and style changes to the code might come into effect as well as guidelines surrounding bug reporting and discussions.

View File

@ -106,7 +106,6 @@ with archinstall.Installer('/mnt') as installation:
installation.user_create('devel', 'devel') installation.user_create('devel', 'devel')
installation.user_set_pw('root', 'airoot') installation.user_set_pw('root', 'airoot')
``` ```
This installer will perform the following: This installer will perform the following:

View File

@ -110,17 +110,21 @@ def select_disk_larger_than_or_close_to(devices, gigabytes, filter_out=None):
return min(copy_devices, key=(lambda device : abs(device.size - gigabytes))) return min(copy_devices, key=(lambda device : abs(device.size - gigabytes)))
def suggest_single_disk_layout(block_device): def suggest_single_disk_layout(block_device, default_filesystem=None):
if not default_filesystem:
from .user_interaction import ask_for_main_filesystem_format
default_filesystem = ask_for_main_filesystem_format()
MIN_SIZE_TO_ALLOW_HOME_PART = 40 # Gb MIN_SIZE_TO_ALLOW_HOME_PART = 40 # Gb
layout = { layout = {
block_device : { block_device.path : {
"wipe" : True, "wipe" : True,
"partitions" : [] "partitions" : []
} }
} }
layout[block_device]['partitions'].append({ layout[block_device.path]['partitions'].append({
# Boot # Boot
"type" : "primary", "type" : "primary",
"start" : "1MiB", "start" : "1MiB",
@ -133,7 +137,7 @@ def suggest_single_disk_layout(block_device):
"format" : "fat32" "format" : "fat32"
} }
}) })
layout[block_device]['partitions'].append({ layout[block_device.path]['partitions'].append({
# Root # Root
"type" : "primary", "type" : "primary",
"start" : "513MiB", "start" : "513MiB",
@ -142,12 +146,12 @@ def suggest_single_disk_layout(block_device):
"size" : "100%" if block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_device.size, 20)*1024}MiB", "size" : "100%" if block_device.size < MIN_SIZE_TO_ALLOW_HOME_PART else f"{min(block_device.size, 20)*1024}MiB",
"mountpoint" : "/", "mountpoint" : "/",
"filesystem" : { "filesystem" : {
"format" : "btrfs" "format" : default_filesystem
} }
}) })
if block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART: if block_device.size >= MIN_SIZE_TO_ALLOW_HOME_PART:
layout[block_device]['partitions'].append({ layout[block_device.path]['partitions'].append({
# Home # Home
"type" : "primary", "type" : "primary",
"encrypted" : False, "encrypted" : False,
@ -156,14 +160,18 @@ def suggest_single_disk_layout(block_device):
"size" : "100%", "size" : "100%",
"mountpoint" : "/home", "mountpoint" : "/home",
"filesystem" : { "filesystem" : {
"format" : "btrfs" "format" : default_filesystem
} }
}) })
return layout return layout
def suggest_multi_disk_layout(block_devices): def suggest_multi_disk_layout(block_devices, default_filesystem=None):
if not default_filesystem:
from .user_interaction import ask_for_main_filesystem_format
default_filesystem = ask_for_main_filesystem_format()
MIN_SIZE_TO_ALLOW_HOME_PART = 40 # Gb MIN_SIZE_TO_ALLOW_HOME_PART = 40 # Gb
ARCH_LINUX_INSTALLED_SIZE = 20 # Gb, rough estimate taking in to account user desktops etc. TODO: Catch user packages to detect size? ARCH_LINUX_INSTALLED_SIZE = 20 # Gb, rough estimate taking in to account user desktops etc. TODO: Catch user packages to detect size?
@ -175,17 +183,17 @@ def suggest_multi_disk_layout(block_devices):
log(f"Suggesting multi-disk-layout using {len(block_devices)} disks, where {root_device} will be /root and {home_device} will be /home", level=logging.DEBUG) log(f"Suggesting multi-disk-layout using {len(block_devices)} disks, where {root_device} will be /root and {home_device} will be /home", level=logging.DEBUG)
layout = { layout = {
root_device : { root_device.path : {
"wipe" : True, "wipe" : True,
"partitions" : [] "partitions" : []
}, },
home_device : { home_device.path : {
"wipe" : True, "wipe" : True,
"partitions" : [] "partitions" : []
}, },
} }
layout[root_device]['partitions'].append({ layout[root_device.path]['partitions'].append({
# Boot # Boot
"type" : "primary", "type" : "primary",
"start" : "1MiB", "start" : "1MiB",
@ -198,7 +206,7 @@ def suggest_multi_disk_layout(block_devices):
"format" : "fat32" "format" : "fat32"
} }
}) })
layout[root_device]['partitions'].append({ layout[root_device.path]['partitions'].append({
# Root # Root
"type" : "primary", "type" : "primary",
"start" : "513MiB", "start" : "513MiB",
@ -207,11 +215,11 @@ def suggest_multi_disk_layout(block_devices):
"size" : "100%", "size" : "100%",
"mountpoint" : "/", "mountpoint" : "/",
"filesystem" : { "filesystem" : {
"format" : "btrfs" "format" : default_filesystem
} }
}) })
layout[home_device]['partitions'].append({ layout[home_device.path]['partitions'].append({
# Home # Home
"type" : "primary", "type" : "primary",
"encrypted" : False, "encrypted" : False,
@ -220,7 +228,7 @@ def suggest_multi_disk_layout(block_devices):
"size" : "100%", "size" : "100%",
"mountpoint" : "/home", "mountpoint" : "/home",
"filesystem" : { "filesystem" : {
"format" : "btrfs" "format" : default_filesystem
} }
}) })
@ -931,7 +939,9 @@ class Filesystem:
time.sleep(0.025) time.sleep(0.025)
time.sleep(0.5) # Let the kernel catch up with quick block devices (nvme for instance) # Todo: Find a better way to detect if the new UUID of the partition has showed up.
# But this will address (among other issues)
time.sleep(float(storage['arguments'].get('disk-sleep', 2.0))) # Let the kernel catch up with quick block devices (nvme for instance)
return self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop()) return self.blockdevice.get_partition(uuid=(previous_partition_uuids ^ {partition.uuid for partition in self.blockdevice.partitions.values()}).pop())
def set_name(self, partition: int, name: str): def set_name(self, partition: int, name: str):
@ -1069,4 +1079,4 @@ def find_partition_by_mountpoint(block_devices, relative_mountpoint :str):
for device in block_devices: for device in block_devices:
for partition in block_devices[device]['partitions']: for partition in block_devices[device]['partitions']:
if partition.get('mountpoint', None) == relative_mountpoint: if partition.get('mountpoint', None) == relative_mountpoint:
return partition return partition

View File

@ -163,10 +163,12 @@ class Installer:
self.log(f'Installing packages: {packages}', level=logging.INFO) self.log(f'Installing packages: {packages}', level=logging.INFO)
if (sync_mirrors := SysCommand('/usr/bin/pacman -Syy')).exit_code == 0: if (sync_mirrors := SysCommand('/usr/bin/pacman -Syy')).exit_code == 0:
if (pacstrap := SysCommand(f'/usr/bin/pacstrap {self.target} {" ".join(packages)}', peak_output=True)).exit_code == 0: if (pacstrap := SysCommand(f'/usr/bin/pacstrap {self.target} {" ".join(packages)} --noconfirm', peak_output=True)).exit_code == 0:
return True return True
else: else:
self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=logging.INFO) self.log(f'Could not strap in packages: {pacstrap}', level=logging.ERROR, fg="red")
self.log(f'Could not strap in packages: {pacstrap.exit_code}', level=logging.ERROR, fg="red")
raise RequirementError("Pacstrap failed. See /var/log/archinstall/install.log or above message for error details.")
else: else:
self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=logging.INFO) self.log(f'Could not sync mirrors: {sync_mirrors.exit_code}', level=logging.INFO)
@ -401,9 +403,6 @@ class Installer:
self.pacstrap(self.base_packages) self.pacstrap(self.base_packages)
self.helper_flags['base-strapped'] = True self.helper_flags['base-strapped'] = True
with open(f"{self.target}/etc/fstab", "a") as fstab:
fstab.write("\ntmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0\n") # Redundant \n at the start? who knows?
# TODO: Support locale and timezone # TODO: Support locale and timezone
# os.remove(f'{self.target}/etc/localtime') # os.remove(f'{self.target}/etc/localtime')
# sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{localtime} /etc/localtime') # sys_command(f'/usr/bin/arch-chroot {self.target} ln -s /usr/share/zoneinfo/{localtime} /etc/localtime')
@ -429,7 +428,7 @@ class Installer:
return True return True
def add_bootloader(self, _device, bootloader='systemd-bootctl'): def add_bootloader(self, 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.
@ -535,14 +534,15 @@ class Installer:
SysCommand(f"/usr/bin/arch-chroot {self.target} {enable_CRYPTODISK} {_file}") SysCommand(f"/usr/bin/arch-chroot {self.target} {enable_CRYPTODISK} {_file}")
if has_uefi(): if has_uefi():
self.pacstrap('efibootmgr') self.pacstrap('efibootmgr') # TODO: Do we need?
o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')) SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB')
SysCommand('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') SysCommand(f'/usr/bin/arch-chroot {self.target} grub-mkconfig -o /boot/grub/grub.cfg')
self.helper_flags['bootloader'] = True self.helper_flags['bootloader'] = True
return True return True
else: else:
o = b''.join(SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc --recheck {_device.path}')) boot_partition = filesystem.find_partition(mountpoint=f"{self.target}/boot")
SysCommand('/usr/bin/arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg') SysCommand(f'/usr/bin/arch-chroot {self.target} grub-install --target=i386-pc --recheck {boot_partition.path}')
SysCommand(f'/usr/bin/arch-chroot {self.target} grub-mkconfig -o /boot/grub/grub.cfg')
self.helper_flags['bootloader'] = True self.helper_flags['bootloader'] = True
else: else:
raise RequirementError(f"Unknown (or not yet implemented) bootloader requested: {bootloader}") raise RequirementError(f"Unknown (or not yet implemented) bootloader requested: {bootloader}")

View File

@ -98,4 +98,4 @@ def load_plugin(path :str): # -> module (not sure how to write that in type defi
log(err, level=logging.ERROR) log(err, level=logging.ERROR)
log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR) log(f"The above error was detected when initiating the plugin: {path}", fg="red", level=logging.ERROR)
else: else:
log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING) log(f"Plugin '{path}' is missing a valid entry-point or is corrupt.", fg="yellow", level=logging.WARNING)

View File

@ -575,14 +575,14 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
# log(f"Selecting which partitions to re-use on {block_device}...", fg="yellow", level=logging.INFO) # log(f"Selecting which partitions to re-use on {block_device}...", fg="yellow", level=logging.INFO)
# partitions = generic_multi_select(block_device.partitions.values(), "Select which partitions to re-use (the rest will be left alone): ", sort=True) # partitions = generic_multi_select(block_device.partitions.values(), "Select which partitions to re-use (the rest will be left alone): ", sort=True)
# partitions_to_wipe = generic_multi_select(partitions, "Which partitions do you wish to wipe (multiple can be selected): ", sort=True) # partitions_to_wipe = generic_multi_select(partitions, "Which partitions do you wish to wipe (multiple can be selected): ", sort=True)
# mountpoints = {} # mountpoints = {}
# struct = { # struct = {
# "partitions" : [] # "partitions" : []
# } # }
# for partition in partitions: # for partition in partitions:
# mountpoint = input(f"Select a mountpoint (or skip) for {partition}: ").strip() # mountpoint = input(f"Select a mountpoint (or skip) for {partition}: ").strip()
# part_struct = {} # part_struct = {}
# if mountpoint: # if mountpoint:
# part_struct['mountpoint'] = mountpoint # part_struct['mountpoint'] = mountpoint
@ -590,7 +590,7 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
# part_struct['boot'] = True # part_struct['boot'] = True
# if has_uefi(): # if has_uefi():
# part_struct['ESP'] = True # part_struct['ESP'] = True
# elif mountpoint == '/' and # elif mountpoint == '/' and
# if partition.uuid: # if partition.uuid:
# part_struct['PARTUUID'] = partition.uuid # part_struct['PARTUUID'] = partition.uuid
# if partition in partitions_to_wipe: # if partition in partitions_to_wipe:
@ -632,15 +632,15 @@ def manage_new_and_existing_partitions(block_device :BlockDevice) -> dict:
if not task: if not task:
break break
if task == 'Create a new partition': if task == 'Create a new partition':
if partition_type == 'gpt': if partition_type == 'gpt':
# https://www.gnu.org/software/parted/manual/html_node/mkpart.html # https://www.gnu.org/software/parted/manual/html_node/mkpart.html
# https://www.gnu.org/software/parted/manual/html_node/mklabel.html # https://www.gnu.org/software/parted/manual/html_node/mklabel.html
name = input("Enter a desired name for the partition: ").strip() name = input("Enter a desired name for the partition: ").strip()
fstype = input("Enter a desired filesystem type for the partition: ").strip() fstype = input("Enter a desired filesystem type for the partition: ").strip()
start = input(f"Enter the start sector (percentage or block number, default: {block_device.largest_free_space[0]}): ").strip() start = input(f"Enter the start sector (percentage or block number, default: {block_device.largest_free_space[0]}): ").strip()
if not start.strip(): if not start.strip():
start = block_device.largest_free_space[0] start = block_device.largest_free_space[0]
@ -753,8 +753,8 @@ def select_individual_blockdevice_usage(block_devices :list):
for device in block_devices: for device in block_devices:
layout = manage_new_and_existing_partitions(device) layout = manage_new_and_existing_partitions(device)
result[device] = layout result[device.path] = layout
return result return result

View File

@ -1,6 +1,7 @@
import json import json
import logging import logging
import os import os
import pathlib
import time import time
import archinstall import archinstall
@ -28,7 +29,9 @@ archinstall.log(f"Disk states before installing: {archinstall.disk_layouts()}",
def load_config(): def load_config():
if archinstall.arguments.get('harddrives', None) is not None: if archinstall.arguments.get('harddrives', None) is not None:
archinstall.arguments['harddrives'] = [archinstall.BlockDevice(BlockDev) for BlockDev in archinstall.arguments['harddrives'].split(',')] if type(archinstall.arguments['harddrives']) is str:
archinstall.arguments['harddrives'] = archinstall.arguments['harddrives'].split(',')
archinstall.arguments['harddrives'] = [archinstall.BlockDevice(BlockDev) for BlockDev in archinstall.arguments['harddrives']]
# Temporarily disabling keep_partitions if config file is loaded # Temporarily disabling keep_partitions if config file is loaded
# Temporary workaround to make Desktop Environments work # Temporary workaround to make Desktop Environments work
if archinstall.arguments.get('profile', None) is not None: if archinstall.arguments.get('profile', None) is not None:
@ -51,7 +54,19 @@ def load_config():
archinstall.storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(archinstall.arguments.get('gfx_driver', None), 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: if archinstall.arguments.get('servers', None) is not None:
archinstall.storage['_selected_servers'] = archinstall.arguments.get('servers', None) archinstall.storage['_selected_servers'] = archinstall.arguments.get('servers', None)
if archinstall.arguments.get('disk_layouts', None) is not None:
if (dl_path := pathlib.Path(archinstall.arguments['disk_layouts'])).exists() and str(dl_path).endswith('.json'):
try:
with open(dl_path) as fh:
archinstall.storage['disk_layouts'] = json.load(fh)
except Exception as e:
raise ValueError(f"--disk_layouts does not contain a valid JSON format: {e}")
else:
try:
archinstall.storage['disk_layouts'] = json.loads(archinstall.arguments['disk_layouts'])
except:
raise ValueError("--disk_layouts=<json> needs either a JSON file or a JSON string given with a valid disk layout.")
def ask_user_questions(): def ask_user_questions():
""" """
First, we'll ask the user for a bunch of user input. First, we'll ask the user for a bunch of user input.
@ -94,14 +109,12 @@ def ask_user_questions():
# Ask which harddrives/block-devices we will install to # Ask which harddrives/block-devices we will install to
# and convert them into archinstall.BlockDevice() objects. # and convert them into archinstall.BlockDevice() objects.
if archinstall.arguments.get('harddrives', None): if archinstall.arguments.get('harddrives', None) is None:
archinstall.arguments['harddrives'] = [archinstall.BlockDevice(BlockDev) for BlockDev in archinstall.arguments['harddrives'].split(',')]
else:
archinstall.arguments['harddrives'] = archinstall.generic_multi_select(archinstall.all_disks(), 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): ", text="Select one or more harddrives to use and configure (leave blank to skip this step): ",
allow_empty=True) allow_empty=True)
if archinstall.arguments.get('harddrives', None): 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.storage['disk_layouts'] = archinstall.select_disk_layout(archinstall.arguments['harddrives'])
# Get disk encryption password (or skip if blank) # Get disk encryption password (or skip if blank)
@ -238,8 +251,7 @@ def perform_filesystem_operations():
for drive in archinstall.arguments['harddrives']: for drive in archinstall.arguments['harddrives']:
with archinstall.Filesystem(drive, mode) as fs: with archinstall.Filesystem(drive, mode) as fs:
fs.load_layout(archinstall.storage['disk_layouts'][drive]) fs.load_layout(archinstall.storage['disk_layouts'][drive.path])
def perform_installation(mountpoint): def perform_installation(mountpoint):
""" """
@ -269,7 +281,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["harddrive"], archinstall.arguments["bootloader"]) installation.add_bootloader(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
@ -359,4 +371,4 @@ if not archinstall.arguments.get('silent'):
ask_user_questions() ask_user_questions()
perform_filesystem_operations() perform_filesystem_operations()
perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt')) perform_installation(archinstall.storage.get('MOUNT_POINT', '/mnt'))

View File

@ -10,6 +10,8 @@ __packages__ = [
"pavucontrol", "pavucontrol",
"lightdm", "lightdm",
"lightdm-gtk-greeter", "lightdm-gtk-greeter",
"gvfs",
"network-manager-applet",
] ]

View File

@ -39,6 +39,8 @@ if __name__ == 'xorg':
try: try:
if "nvidia" in archinstall.storage.get("gfx_driver_packages", None): if "nvidia" in archinstall.storage.get("gfx_driver_packages", None):
if "linux-zen" in archinstall.storage['installation_session'].base_packages or "linux-lts" in archinstall.storage['installation_session'].base_packages: if "linux-zen" in archinstall.storage['installation_session'].base_packages or "linux-lts" in archinstall.storage['installation_session'].base_packages:
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("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") archinstall.storage['installation_session'].add_additional_packages("xorg-server xorg-xinit nvidia-dkms")
else: else:

View File

@ -29,7 +29,7 @@ include =
archinstall.* archinstall.*
[options.package_data] [options.package_data]
archinstall = archinstall =
examples/*.py examples/*.py
profiles/*.py profiles/*.py
profiles/applications/*.py profiles/applications/*.py