feat(#4466): support `optdepends` of `linux-firmware`

Signed-off-by: h8d13 <hadean-eon-dev@proton.me>
This commit is contained in:
h8d13 2026-08-12 14:03:32 +02:00
parent 5ebdd27ceb
commit f60f9ff032
No known key found for this signature in database
GPG Key ID: 4066352FC2E0674B
6 changed files with 70 additions and 2 deletions

View File

@ -88,6 +88,7 @@ class ArchConfigType(StrEnum):
ENCRYPTION_PASSWORD = 'encryption_password'
HOSTNAME = 'hostname'
KERNELS = 'kernels'
FIRMWARE_OPTDEPS = 'firmware_optdeps'
NTP = 'ntp'
TIMEZONE = 'timezone'
SERVICES = 'services'
@ -166,6 +167,7 @@ class ArchConfig:
swap: ZramConfiguration | None = None
hostname: str = 'archlinux'
kernels: list[str] = field(default_factory=lambda: [DEFAULT_KERNEL.value])
firmware_optdeps: list[str] = field(default_factory=list)
ntp: bool = True
packages: list[str] = field(default_factory=list)
pacman_config: PacmanConfiguration = field(default_factory=PacmanConfiguration)
@ -211,6 +213,7 @@ class ArchConfig:
return {
ArchConfigType.HOSTNAME: self.hostname,
ArchConfigType.KERNELS: self.kernels,
ArchConfigType.FIRMWARE_OPTDEPS: self.firmware_optdeps,
ArchConfigType.NTP: self.ntp,
ArchConfigType.TIMEZONE: self.timezone,
ArchConfigType.SERVICES: self.services,
@ -326,6 +329,9 @@ class ArchConfig:
if kernels := args_config.get('kernels', []):
arch_config.kernels = kernels
if firmware_optdeps := args_config.get('firmware_optdeps', []):
arch_config.firmware_optdeps = firmware_optdeps
arch_config.ntp = args_config.get('ntp', True)
if packages := args_config.get('packages', []):

View File

@ -3,7 +3,7 @@ from typing import assert_never
from archinstall.lib.hardware import GfxDriver, SysInfo
from archinstall.lib.menu.helpers import Confirmation, Selection
from archinstall.lib.models.application import ZramAlgorithm, ZramConfiguration
from archinstall.lib.models.package_types import DEFAULT_KERNEL, Kernel
from archinstall.lib.models.package_types import DEFAULT_KERNEL, FirmwareOptdep, Kernel
from archinstall.lib.translationhandler import tr
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
from archinstall.tui.result import ResultType
@ -37,6 +37,32 @@ async def select_kernel(preset: list[Kernel] = []) -> list[Kernel]:
return result.get_values()
async def select_firmware_optdeps(preset: list[FirmwareOptdep] = []) -> list[FirmwareOptdep]:
"""
Asks the user which of linux-firmware's optional dependencies to install.
:return: The selected firmware packages
:rtype: list[FirmwareOptdep]
"""
group = MenuItemGroup.from_enum(FirmwareOptdep, sort_items=True, preset=preset)
result = await Selection[FirmwareOptdep](
group,
header=tr('Select optional firmware to install (none are pulled in by linux-firmware)'),
allow_skip=True,
allow_reset=True,
multi=True,
).show()
match result.type_:
case ResultType.Skip:
return preset
case ResultType.Reset:
return []
case ResultType.Selection:
return result.get_values()
async def select_uki(preset: bool = True) -> bool:
prompt = tr('Would you like to use unified kernel images?') + '\n'

View File

@ -9,7 +9,7 @@ from archinstall.lib.bootloader.utils import validate_bootloader_layout
from archinstall.lib.configuration import save_config
from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu
from archinstall.lib.general.general_menu import select_hostname, select_ntp, select_timezone
from archinstall.lib.general.system_menu import select_kernel, select_swap
from archinstall.lib.general.system_menu import select_firmware_optdeps, select_kernel, select_swap
from archinstall.lib.hardware import SysInfo
from archinstall.lib.locale.locale_menu import LocaleMenu
from archinstall.lib.menu.abstract_menu import AbstractMenu, SpecialMenuKey
@ -110,6 +110,13 @@ class GlobalMenu(AbstractMenu[None]):
mandatory=True,
key='kernels',
),
MenuItem(
text=tr('Optional firmware'),
value=[],
action=select_firmware_optdeps,
preview_action=self._prev_firmware_optdeps,
key='firmware_optdeps',
),
MenuItem(
text=tr('Hostname'),
value='archlinux',
@ -438,6 +445,12 @@ class GlobalMenu(AbstractMenu[None]):
return f'{tr("Kernel")}: {kernel}'
return None
def _prev_firmware_optdeps(self, item: MenuItem) -> str | None:
if item.value:
firmware = ', '.join(item.value)
return f'{tr("Optional firmware")}: {firmware}'
return None
def _prev_bootloader_config(self, item: MenuItem) -> str | None:
bootloader_config: BootloaderConfiguration | None = item.value
if bootloader_config:

View File

@ -79,6 +79,7 @@ class Installer:
disk_config: DiskLayoutConfiguration,
base_packages: list[str] = [],
kernels: list[str] | None = None,
firmware: list[str] | None = None,
silent: bool = False,
):
"""
@ -101,6 +102,10 @@ class Installer:
for kernel in self.kernels:
self._base_packages.append(kernel)
# linux-firmware pulls in its hard deps only, so the optional ones are
# strapped alongside base or their blobs never reach the target
self._base_packages.extend(firmware or [])
# If using accessibility tools in the live environment, append those to the packages list
if accessibility_tools_in_use():
self._base_packages.extend(__accessibility_packages__)

View File

@ -10,3 +10,20 @@ class Kernel(StrEnum):
DEFAULT_KERNEL: Final = Kernel.LINUX
class FirmwareOptdep(StrEnum):
"""linux-firmware's optional dependencies.
The metapackage pulls in its hard deps only, so these blobs never reach the
target: hardware that needs one (a Marvell wifi card, a Mellanox NIC) comes
up without firmware and there is nothing in the installer that says so.
Mirrors `pacman -Si linux-firmware` optdepends.
"""
LIQUIDIO = 'linux-firmware-liquidio'
MARVELL = 'linux-firmware-marvell'
MELLANOX = 'linux-firmware-mellanox'
NFP = 'linux-firmware-nfp'
QCOM = 'linux-firmware-qcom'
QLOGIC = 'linux-firmware-qlogic'

View File

@ -80,6 +80,7 @@ def perform_installation(
mountpoint,
disk_config,
kernels=config.kernels,
firmware=config.firmware_optdeps,
silent=arch_config_handler.args.silent,
) as installation:
# Mount all the drives to the desired mountpoint