From 1f66848b22f99e2fe1d91ec20586bc568bf80d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Sun, 24 May 2026 23:10:33 -0300 Subject: [PATCH 1/2] feat: add plymouth config --- archinstall/lib/args.py | 11 +++ archinstall/lib/global_menu.py | 18 ++++ archinstall/lib/models/__init__.py | 3 + archinstall/lib/models/plymouth.py | 57 +++++++++++++ archinstall/lib/plymouth/__init__.py | 0 archinstall/lib/plymouth/plymouth_handler.py | 87 ++++++++++++++++++++ archinstall/lib/plymouth/plymouth_menu.py | 26 ++++++ archinstall/scripts/guided.py | 4 + 8 files changed, 206 insertions(+) create mode 100644 archinstall/lib/models/plymouth.py create mode 100644 archinstall/lib/plymouth/__init__.py create mode 100644 archinstall/lib/plymouth/plymouth_handler.py create mode 100644 archinstall/lib/plymouth/plymouth_menu.py diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index e3729504dd..97dc019d9a 100644 --- a/archinstall/lib/args.py +++ b/archinstall/lib/args.py @@ -16,6 +16,7 @@ from archinstall.lib.crypt import decrypt from archinstall.lib.log import debug, error, logger, warn from archinstall.lib.menu.util import get_password +from archinstall.lib.models import PlymouthConfiguration from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration from archinstall.lib.models.authentication import AuthenticationConfiguration from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration @@ -88,6 +89,7 @@ class ArchConfigType(StrEnum): SERVICES = 'services' PACKAGES = 'packages' PACMAN_CONFIG = 'pacman_config' + PLYMOUTH_CONFIG = 'plymouth_config' CUSTOM_COMMANDS = 'custom_commands' def text(self) -> str: @@ -130,6 +132,8 @@ def text(self) -> str: return tr('Additional packages') case ArchConfigType.PACMAN_CONFIG: return tr('Pacman') + case ArchConfigType.PLYMOUTH_CONFIG: + return tr('Plymouth') case ArchConfigType.CUSTOM_COMMANDS: return tr('Custom commands') case ArchConfigType.USERS: @@ -159,6 +163,7 @@ class ArchConfig: ntp: bool = True packages: list[str] = field(default_factory=list) pacman_config: PacmanConfiguration = field(default_factory=PacmanConfiguration.default) + plymouth_config: PlymouthConfiguration | None = None timezone: str = 'UTC' services: list[str] = field(default_factory=list) custom_commands: list[str] = field(default_factory=list) @@ -240,6 +245,9 @@ def sub_cfg(self) -> dict[ArchConfigType, SubConfig]: if self.app_config: cfg[ArchConfigType.APP_CONFIG] = self.app_config + if self.plymouth_config: + cfg[ArchConfigType.PLYMOUTH_CONFIG] = self.plymouth_config + return cfg @classmethod @@ -336,6 +344,9 @@ def from_config(cls, args_config: dict[str, Any], args: Arguments) -> Self: if services := args_config.get('services', []): arch_config.services = services + if plymouth_config := args_config.get('plymouth_config', None): + arch_config.plymouth_config = PlymouthConfiguration.parse_arg(plymouth_config) + # DEPRECATED: backwards compatibility root_password = None if root_password := args_config.get('!root-password', None): diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index 45a0e3b473..cc62ae9c36 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -25,11 +25,13 @@ from archinstall.lib.models.package_types import DEFAULT_KERNEL from archinstall.lib.models.packages import Repository from archinstall.lib.models.pacman import PacmanConfiguration +from archinstall.lib.models.plymouth import PlymouthConfiguration from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.network.network_menu import select_network from archinstall.lib.packages.packages import list_available_packages, select_additional_packages from archinstall.lib.pacman.config import PacmanConfig from archinstall.lib.pacman.pacman_menu import PacmanMenu +from archinstall.lib.plymouth.plymouth_menu import select_plymouth_theme from archinstall.lib.translationhandler import Language, tr, translation_handler from archinstall.lib.utils.format import as_table from archinstall.tui.components import tui @@ -150,6 +152,13 @@ def _get_menu_options(self) -> list[MenuItem]: preview_action=self._prev_pacman_config, key='pacman_config', ), + MenuItem( + text=tr('Plymouth'), + action=self._plymouth_configuration, + value=None, + preview_action=self._prev_plymouth_config, + key='plymouth_config', + ), MenuItem( text=tr('Additional packages'), action=self._select_additional_packages, @@ -432,6 +441,15 @@ def _prev_pacman_config(self, item: MenuItem) -> str | None: output += '{}: {}'.format(tr('Color'), config.color) return output + async def _plymouth_configuration(self, preset: PlymouthConfiguration | None) -> PlymouthConfiguration | None: + return await select_plymouth_theme(preset) + + def _prev_plymouth_config(self, item: MenuItem) -> str | None: + if not item.value: + return None + config: PlymouthConfiguration = item.value + return config.preview() + def _prev_kernel(self, item: MenuItem) -> str | None: if item.value: kernel = ', '.join(item.value) diff --git a/archinstall/lib/models/__init__.py b/archinstall/lib/models/__init__.py index 5f808c96f2..3f446fd97e 100644 --- a/archinstall/lib/models/__init__.py +++ b/archinstall/lib/models/__init__.py @@ -30,6 +30,7 @@ from archinstall.lib.models.mirrors import CustomRepository, MirrorConfiguration, MirrorRegion from archinstall.lib.models.network import NetworkConfiguration, Nic, NicType from archinstall.lib.models.packages import LocalPackage, PackageSearch, PackageSearchResult, Repository +from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.models.users import PasswordStrength, User @@ -69,6 +70,8 @@ 'PartitionTable', 'PartitionType', 'PasswordStrength', + 'PlymouthConfiguration', + 'PlymouthTheme', 'PrintServiceConfiguration', 'ProfileConfiguration', 'Repository', diff --git a/archinstall/lib/models/plymouth.py b/archinstall/lib/models/plymouth.py new file mode 100644 index 0000000000..c2aa69b66d --- /dev/null +++ b/archinstall/lib/models/plymouth.py @@ -0,0 +1,57 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Self, TypedDict, override + +from archinstall.lib.models.config import SubConfig +from archinstall.lib.translationhandler import tr + + +class PlymouthConfigSerialization(TypedDict): + plymouth: str + + +class PlymouthTheme(Enum): + DISABLED = 'Disabled' + BGRT = 'bgrt' + FADE_IN = 'fade-in' + GLOW = 'glow' + SCRIPT = 'script' + SOLAR = 'solar' + SPINNER = 'spinner' + SPINFINITY = 'spinfinity' + TRIBAR = 'tribar' + TEXT = 'text' + DETAILS = 'details' + + +@dataclass +class PlymouthConfiguration(SubConfig): + plymouth: PlymouthTheme = PlymouthTheme.DISABLED + + @override + def json(self) -> PlymouthConfigSerialization: + return { + 'plymouth': self.plymouth.value, + } + + @classmethod + def default(cls) -> Self: + return cls() + + @classmethod + def parse_arg(cls, arg: PlymouthConfigSerialization) -> Self: + config = cls.default() + + if 'plymouth' in arg: + config.plymouth = PlymouthTheme(arg['plymouth']) + + return config + + @override + def summary(self) -> str: + if self.plymouth == PlymouthTheme.DISABLED: + return tr('Disabled') + return tr('{} Selected').format(self.plymouth.value) + + def preview(self) -> str: + return f'Plymouth: {tr(self.plymouth.value)}' diff --git a/archinstall/lib/plymouth/__init__.py b/archinstall/lib/plymouth/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/archinstall/lib/plymouth/plymouth_handler.py b/archinstall/lib/plymouth/plymouth_handler.py new file mode 100644 index 0000000000..5fd8a55c7d --- /dev/null +++ b/archinstall/lib/plymouth/plymouth_handler.py @@ -0,0 +1,87 @@ +from typing import TYPE_CHECKING + +from archinstall.lib.log import debug +from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme + +if TYPE_CHECKING: + from archinstall.lib.installer import Installer + + +class PlymouthHandler: + @property + def plymouth_packages(self) -> list[str]: + return [ + 'plymouth', + ] + + @property + def kernel_params(self) -> list[str]: + return [ + 'quiet', + 'splash', + ] + + @property + def plymouth_hook(self) -> str: + return 'plymouth' + + @property + def _hook_anchors(self) -> list[tuple[str, bool]]: + return [ + # hook_name, insert_after + ('encrypt', False), + ('sd-encrypt', False), + ('systemd', True), + ('systemd', True), + ('filesystems', False), + ('keyboard', True), + ] + + def install(self, install_session: Installer, plymouth_config: PlymouthConfiguration) -> None: + debug(f'Installing plymouth with theme: {plymouth_config.plymouth.value}') + + if plymouth_config.plymouth == PlymouthTheme.DISABLED: + debug('No plymouth theme selected, skipping installation.') + return + + install_session.add_additional_packages(self.plymouth_packages) + + self._add_kernel_params(install_session) + self._add_hooks(install_session) + self._set_theme(install_session, plymouth_config.plymouth.value) + self._regenerate_mkinitcpio(install_session) + + debug('Plymouth install completed') + + def _add_kernel_params(self, install_session: Installer) -> None: + debug(f'Adding kernel params for plymouth {self.kernel_params}') + for param in self.kernel_params: + if param not in install_session._kernel_params: + install_session._kernel_params.append(param) + + def _add_hooks(self, install_session: Installer) -> None: + debug('Adding Plymouth hook') + + if self.plymouth_hook in install_session._hooks: + debug(f'{self.plymouth_hook} hook already present') + return + + for hook, insert_after in self._hook_anchors: + try: + index = install_session._hooks.index(hook) + position = index + (1 if insert_after else 0) + install_session._hooks.insert(position, self.plymouth_hook) + debug(f'Plymouth hook inserted {["before", "after"][insert_after]} {hook!r}') + return + except ValueError: + continue + + install_session._hooks.append(self.plymouth_hook) + debug('Plymouth hook appended at end (no anchor hook found)') + + def _set_theme(self, install_session: Installer, theme: str) -> None: + debug(f'Set plymouth theme to {theme}') + install_session.arch_chroot(f'plymouth-set-default-theme {theme}') + + def _regenerate_mkinitcpio(self, install_session: Installer) -> None: + install_session.mkinitcpio(['-P']) diff --git a/archinstall/lib/plymouth/plymouth_menu.py b/archinstall/lib/plymouth/plymouth_menu.py new file mode 100644 index 0000000000..ed1d6d94af --- /dev/null +++ b/archinstall/lib/plymouth/plymouth_menu.py @@ -0,0 +1,26 @@ +from archinstall.lib.menu.helpers import Selection +from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme +from archinstall.lib.translationhandler import tr +from archinstall.tui.menu_item import MenuItem, MenuItemGroup +from archinstall.tui.result import ResultType + + +async def select_plymouth_theme(preset: PlymouthConfiguration | None = None) -> PlymouthConfiguration | None: + items = [MenuItem(t.value, value=t) for t in PlymouthTheme] + group = MenuItemGroup(items, sort_items=False) + group.set_selected_by_value(preset.plymouth if preset else PlymouthTheme.DISABLED) + + result = await Selection[PlymouthTheme]( + group, + header=tr('Select Plymouth theme'), + allow_reset=True, + allow_skip=True, + ).show() + + match result.type_: + case ResultType.Skip: + return preset + case ResultType.Reset: + return None + case ResultType.Selection: + return PlymouthConfiguration(result.get_value()) diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 6f484910de..2eb7cf1b23 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -20,6 +20,7 @@ from archinstall.lib.models.users import User from archinstall.lib.network.network_handler import install_network_config from archinstall.lib.packages.util import check_version_upgrade +from archinstall.lib.plymouth.plymouth_handler import PlymouthHandler from archinstall.lib.profile.profiles_handler import profile_handler from archinstall.lib.translationhandler import tr from archinstall.tui.components import tui @@ -114,6 +115,9 @@ def perform_installation( if config.swap and config.swap.enabled: installation.setup_swap(algo=config.swap.algorithm) + if config.plymouth_config: + PlymouthHandler().install(installation, config.plymouth_config) + if config.bootloader_config and config.bootloader_config.bootloader != Bootloader.NO_BOOTLOADER: installation.add_bootloader( config.bootloader_config.bootloader, From db71fb27351530301a218b64f7e23a926665702b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Mon, 25 May 2026 12:57:48 -0300 Subject: [PATCH 2/2] refactor: move plymouth to bootleader menu --- archinstall/lib/args.py | 11 --- archinstall/lib/bootloader/bootloader_menu.py | 38 +++++++- archinstall/lib/global_menu.py | 18 ---- archinstall/lib/installer.py | 33 +++++-- archinstall/lib/models/__init__.py | 3 - archinstall/lib/models/bootloader.py | 46 +++++++++- archinstall/lib/models/plymouth.py | 57 ------------ archinstall/lib/plymouth/__init__.py | 0 archinstall/lib/plymouth/plymouth_handler.py | 87 ------------------- archinstall/lib/plymouth/plymouth_menu.py | 26 ------ archinstall/scripts/guided.py | 5 +- 11 files changed, 109 insertions(+), 215 deletions(-) delete mode 100644 archinstall/lib/models/plymouth.py delete mode 100644 archinstall/lib/plymouth/__init__.py delete mode 100644 archinstall/lib/plymouth/plymouth_handler.py delete mode 100644 archinstall/lib/plymouth/plymouth_menu.py diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index 97dc019d9a..e3729504dd 100644 --- a/archinstall/lib/args.py +++ b/archinstall/lib/args.py @@ -16,7 +16,6 @@ from archinstall.lib.crypt import decrypt from archinstall.lib.log import debug, error, logger, warn from archinstall.lib.menu.util import get_password -from archinstall.lib.models import PlymouthConfiguration from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration from archinstall.lib.models.authentication import AuthenticationConfiguration from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration @@ -89,7 +88,6 @@ class ArchConfigType(StrEnum): SERVICES = 'services' PACKAGES = 'packages' PACMAN_CONFIG = 'pacman_config' - PLYMOUTH_CONFIG = 'plymouth_config' CUSTOM_COMMANDS = 'custom_commands' def text(self) -> str: @@ -132,8 +130,6 @@ def text(self) -> str: return tr('Additional packages') case ArchConfigType.PACMAN_CONFIG: return tr('Pacman') - case ArchConfigType.PLYMOUTH_CONFIG: - return tr('Plymouth') case ArchConfigType.CUSTOM_COMMANDS: return tr('Custom commands') case ArchConfigType.USERS: @@ -163,7 +159,6 @@ class ArchConfig: ntp: bool = True packages: list[str] = field(default_factory=list) pacman_config: PacmanConfiguration = field(default_factory=PacmanConfiguration.default) - plymouth_config: PlymouthConfiguration | None = None timezone: str = 'UTC' services: list[str] = field(default_factory=list) custom_commands: list[str] = field(default_factory=list) @@ -245,9 +240,6 @@ def sub_cfg(self) -> dict[ArchConfigType, SubConfig]: if self.app_config: cfg[ArchConfigType.APP_CONFIG] = self.app_config - if self.plymouth_config: - cfg[ArchConfigType.PLYMOUTH_CONFIG] = self.plymouth_config - return cfg @classmethod @@ -344,9 +336,6 @@ def from_config(cls, args_config: dict[str, Any], args: Arguments) -> Self: if services := args_config.get('services', []): arch_config.services = services - if plymouth_config := args_config.get('plymouth_config', None): - arch_config.plymouth_config = PlymouthConfiguration.parse_arg(plymouth_config) - # DEPRECATED: backwards compatibility root_password = None if root_password := args_config.get('!root-password', None): diff --git a/archinstall/lib/bootloader/bootloader_menu.py b/archinstall/lib/bootloader/bootloader_menu.py index d32a5a2132..64ad4c8d6f 100644 --- a/archinstall/lib/bootloader/bootloader_menu.py +++ b/archinstall/lib/bootloader/bootloader_menu.py @@ -3,7 +3,7 @@ from archinstall.lib.menu.abstract_menu import AbstractSubMenu from archinstall.lib.menu.helpers import Confirmation, Selection -from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration +from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration, PlymouthTheme from archinstall.lib.translationhandler import tr from archinstall.tui.menu_item import MenuItem, MenuItemGroup from archinstall.tui.result import ResultType @@ -66,6 +66,13 @@ def _define_menu_options(self) -> list[MenuItem]: key='removable', enabled=removable_enabled, ), + MenuItem( + text=tr('Plymouth'), + action=self._select_plymouth, + value=self._bootloader_conf.plymouth, + preview_action=self._prev_plymouth, + key='plymouth', + ), ] def _prev_bootloader(self, item: MenuItem) -> str | None: @@ -85,6 +92,11 @@ def _prev_removable(self, item: MenuItem) -> str | None: return tr('Will install to /EFI/BOOT/ (removable location, safe default)') return tr('Will install to custom location with NVRAM entry') + def _prev_plymouth(self, item: MenuItem) -> str | None: + if item.value: + return f'{tr("Plymouth")}: {item.value.value}' + return None + @override async def show(self) -> BootloaderConfiguration: _ = await super().show() @@ -117,6 +129,9 @@ async def _select_bootloader(self, preset: Bootloader | None) -> Bootloader | No return bootloader + async def _select_plymouth(self, preset: PlymouthTheme | None) -> PlymouthTheme | None: + return await select_plymouth_theme(preset) + async def _select_uki(self, preset: bool) -> bool: prompt = tr('Would you like to use unified kernel images?') + '\n' @@ -215,3 +230,24 @@ async def select_bootloader( return result.get_value() case ResultType.Reset: raise ValueError('Unhandled result type') + + +async def select_plymouth_theme(preset: PlymouthTheme | None = None) -> PlymouthTheme | None: + items = [MenuItem(t.value, value=t) for t in PlymouthTheme] + group = MenuItemGroup(items, sort_items=False) + group.set_selected_by_value(preset.value if preset else None) + + result = await Selection[PlymouthTheme]( + group, + header=tr('Select Plymouth theme'), + allow_reset=True, + allow_skip=True, + ).show() + + match result.type_: + case ResultType.Skip: + return preset + case ResultType.Reset: + return None + case ResultType.Selection: + return PlymouthTheme(result.get_value()) diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index cc62ae9c36..45a0e3b473 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -25,13 +25,11 @@ from archinstall.lib.models.package_types import DEFAULT_KERNEL from archinstall.lib.models.packages import Repository from archinstall.lib.models.pacman import PacmanConfiguration -from archinstall.lib.models.plymouth import PlymouthConfiguration from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.network.network_menu import select_network from archinstall.lib.packages.packages import list_available_packages, select_additional_packages from archinstall.lib.pacman.config import PacmanConfig from archinstall.lib.pacman.pacman_menu import PacmanMenu -from archinstall.lib.plymouth.plymouth_menu import select_plymouth_theme from archinstall.lib.translationhandler import Language, tr, translation_handler from archinstall.lib.utils.format import as_table from archinstall.tui.components import tui @@ -152,13 +150,6 @@ def _get_menu_options(self) -> list[MenuItem]: preview_action=self._prev_pacman_config, key='pacman_config', ), - MenuItem( - text=tr('Plymouth'), - action=self._plymouth_configuration, - value=None, - preview_action=self._prev_plymouth_config, - key='plymouth_config', - ), MenuItem( text=tr('Additional packages'), action=self._select_additional_packages, @@ -441,15 +432,6 @@ def _prev_pacman_config(self, item: MenuItem) -> str | None: output += '{}: {}'.format(tr('Color'), config.color) return output - async def _plymouth_configuration(self, preset: PlymouthConfiguration | None) -> PlymouthConfiguration | None: - return await select_plymouth_theme(preset) - - def _prev_plymouth_config(self, item: MenuItem) -> str | None: - if not item.value: - return None - config: PlymouthConfiguration = item.value - return config.preview() - def _prev_kernel(self, item: MenuItem) -> str | None: if item.value: kernel = ', '.join(item.value) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index bf7d91ba31..f53dcda458 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -32,7 +32,7 @@ from archinstall.lib.log import debug, error, info, log, logger, warn from archinstall.lib.mirror.mirror_handler import MirrorListHandler from archinstall.lib.models.application import ZramAlgorithm -from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration +from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration, PlymouthTheme from archinstall.lib.models.device import ( DiskEncryption, DiskLayoutConfiguration, @@ -1755,6 +1755,28 @@ def _add_refind_bootloader( self._helper_flags['bootloader'] = 'refind' + def _install_plymouth(self, plymouth: PlymouthTheme) -> None: + debug(f'Installing plymouth with theme: {plymouth.value}') + self.add_additional_packages(['plymouth']) + + for param in ('quiet', 'splash'): + if param not in self._kernel_params: + self._kernel_params.append(param) + + if 'plymouth' not in self._hooks: + for hook, insert_after in [('encrypt', False), ('sd-encrypt', False), ('systemd', True), ('filesystems', False), ('keyboard', True)]: + try: + idx = self._hooks.index(hook) + self._hooks.insert(idx + (1 if insert_after else 0), 'plymouth') + break + except ValueError: + continue + else: + self._hooks.append('plymouth') + + self.arch_chroot(f'plymouth-set-default-theme {plymouth.value}') + self.mkinitcpio(['-P']) + def _config_uki( self, root: PartitionModification | LvmVolume, @@ -1807,10 +1829,7 @@ def _config_uki( error('Error generating initramfs (continuing anyway)') def add_bootloader( - self, - bootloader: Bootloader, - uki_enabled: bool = False, - bootloader_removable: bool = False, + self, bootloader: Bootloader, uki_enabled: bool = False, bootloader_removable: bool = False, plymouth: PlymouthTheme | None = None ) -> None: """ Adds a bootloader to the installation instance. @@ -1824,6 +1843,7 @@ def add_bootloader( :param bootloader: Type of bootloader to be added :param uki_enabled: Whether to use unified kernel images :param bootloader_removable: Whether to install to removable media location (UEFI only, for GRUB and Limine) + :param plymouth: Optional Plymouth theme to install and configure """ for plugin in plugins.values(): @@ -1859,6 +1879,9 @@ def add_bootloader( warn(f'Bootloader {bootloader.value} lacks removable support; disabling.') bootloader_removable = False + if plymouth is not None: + self._install_plymouth(plymouth) + if uki_enabled: keep_initramfs = ( bootloader == Bootloader.Grub diff --git a/archinstall/lib/models/__init__.py b/archinstall/lib/models/__init__.py index 3f446fd97e..5f808c96f2 100644 --- a/archinstall/lib/models/__init__.py +++ b/archinstall/lib/models/__init__.py @@ -30,7 +30,6 @@ from archinstall.lib.models.mirrors import CustomRepository, MirrorConfiguration, MirrorRegion from archinstall.lib.models.network import NetworkConfiguration, Nic, NicType from archinstall.lib.models.packages import LocalPackage, PackageSearch, PackageSearchResult, Repository -from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.models.users import PasswordStrength, User @@ -70,8 +69,6 @@ 'PartitionTable', 'PartitionType', 'PasswordStrength', - 'PlymouthConfiguration', - 'PlymouthTheme', 'PrintServiceConfiguration', 'ProfileConfiguration', 'Repository', diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index bd6bce7ed1..040b6746c7 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -60,15 +60,48 @@ def from_arg(cls, bootloader: str, skip_boot: bool) -> Self: return cls(bootloader) +class PlymouthTheme(Enum): + BGRT = 'bgrt' + FADE = 'fade-in' + GLOW = 'glow' + SCRIPT = 'script' + SOLAR = 'solar' + SPINNER = 'spinner' + SPINFINITY = 'spinfinity' + TRIBAR = 'tribar' + TEXT = 'text' + DETAILS = 'details' + + @classmethod + def from_arg(cls, plymouth: str | None) -> Self | None: + if plymouth is None: + return None + + plymouth = plymouth.lower() + + values = [e.value for e in cls] + + if plymouth not in values: + warn(f'Invalid plymouth value "{plymouth}". Allowed values: {", ".join(values)}') + sys.exit(1) + + return cls(plymouth) + + @dataclass class BootloaderConfiguration(SubConfig): bootloader: Bootloader uki: bool = False removable: bool = True + plymouth: PlymouthTheme | None = None @override def json(self) -> dict[str, Any]: - return {'bootloader': self.bootloader.json(), 'uki': self.uki, 'removable': self.removable} + data = {'bootloader': self.bootloader.json(), 'uki': self.uki, 'removable': self.removable} + + if self.plymouth is not None: + data['plymouth'] = self.plymouth.value + return data @override def summary(self) -> list[str]: @@ -78,6 +111,8 @@ def summary(self) -> list[str]: out.append(tr('UKI enabled')) if self.removable: out.append(tr('Removable')) + if self.plymouth is not None: + out.append(tr('Plymouth "{}"').format(self.plymouth.value)) return out @@ -86,14 +121,16 @@ def parse_arg(cls, config: dict[str, Any], skip_boot: bool) -> Self: bootloader = Bootloader.from_arg(config.get('bootloader', ''), skip_boot) uki = config.get('uki', False) removable = config.get('removable', True) - return cls(bootloader=bootloader, uki=uki, removable=removable) + plymouth = PlymouthTheme.from_arg(config.get('plymouth', None)) + return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth) @classmethod def get_default(cls, uefi: bool, skip_boot: bool = False) -> Self: bootloader = Bootloader.get_default(uefi, skip_boot) removable = uefi and bootloader.has_removable_support() uki = uefi and bootloader.has_uki_support() - return cls(bootloader=bootloader, uki=uki, removable=removable) + plymouth = None + return cls(bootloader=bootloader, uki=uki, removable=removable, plymouth=plymouth) def preview(self, uefi: bool) -> str: text = f'{tr("Bootloader")}: {self.bootloader.value}' @@ -112,4 +149,7 @@ def preview(self, uefi: bool) -> str: removable_string = tr('Disabled') text += f'{tr("Removable")}: {removable_string}' text += '\n' + if self.plymouth is not None: + text += f'{tr("Plymouth")}: {self.plymouth.value}' + text += '\n' return text diff --git a/archinstall/lib/models/plymouth.py b/archinstall/lib/models/plymouth.py deleted file mode 100644 index c2aa69b66d..0000000000 --- a/archinstall/lib/models/plymouth.py +++ /dev/null @@ -1,57 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Self, TypedDict, override - -from archinstall.lib.models.config import SubConfig -from archinstall.lib.translationhandler import tr - - -class PlymouthConfigSerialization(TypedDict): - plymouth: str - - -class PlymouthTheme(Enum): - DISABLED = 'Disabled' - BGRT = 'bgrt' - FADE_IN = 'fade-in' - GLOW = 'glow' - SCRIPT = 'script' - SOLAR = 'solar' - SPINNER = 'spinner' - SPINFINITY = 'spinfinity' - TRIBAR = 'tribar' - TEXT = 'text' - DETAILS = 'details' - - -@dataclass -class PlymouthConfiguration(SubConfig): - plymouth: PlymouthTheme = PlymouthTheme.DISABLED - - @override - def json(self) -> PlymouthConfigSerialization: - return { - 'plymouth': self.plymouth.value, - } - - @classmethod - def default(cls) -> Self: - return cls() - - @classmethod - def parse_arg(cls, arg: PlymouthConfigSerialization) -> Self: - config = cls.default() - - if 'plymouth' in arg: - config.plymouth = PlymouthTheme(arg['plymouth']) - - return config - - @override - def summary(self) -> str: - if self.plymouth == PlymouthTheme.DISABLED: - return tr('Disabled') - return tr('{} Selected').format(self.plymouth.value) - - def preview(self) -> str: - return f'Plymouth: {tr(self.plymouth.value)}' diff --git a/archinstall/lib/plymouth/__init__.py b/archinstall/lib/plymouth/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/archinstall/lib/plymouth/plymouth_handler.py b/archinstall/lib/plymouth/plymouth_handler.py deleted file mode 100644 index 5fd8a55c7d..0000000000 --- a/archinstall/lib/plymouth/plymouth_handler.py +++ /dev/null @@ -1,87 +0,0 @@ -from typing import TYPE_CHECKING - -from archinstall.lib.log import debug -from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme - -if TYPE_CHECKING: - from archinstall.lib.installer import Installer - - -class PlymouthHandler: - @property - def plymouth_packages(self) -> list[str]: - return [ - 'plymouth', - ] - - @property - def kernel_params(self) -> list[str]: - return [ - 'quiet', - 'splash', - ] - - @property - def plymouth_hook(self) -> str: - return 'plymouth' - - @property - def _hook_anchors(self) -> list[tuple[str, bool]]: - return [ - # hook_name, insert_after - ('encrypt', False), - ('sd-encrypt', False), - ('systemd', True), - ('systemd', True), - ('filesystems', False), - ('keyboard', True), - ] - - def install(self, install_session: Installer, plymouth_config: PlymouthConfiguration) -> None: - debug(f'Installing plymouth with theme: {plymouth_config.plymouth.value}') - - if plymouth_config.plymouth == PlymouthTheme.DISABLED: - debug('No plymouth theme selected, skipping installation.') - return - - install_session.add_additional_packages(self.plymouth_packages) - - self._add_kernel_params(install_session) - self._add_hooks(install_session) - self._set_theme(install_session, plymouth_config.plymouth.value) - self._regenerate_mkinitcpio(install_session) - - debug('Plymouth install completed') - - def _add_kernel_params(self, install_session: Installer) -> None: - debug(f'Adding kernel params for plymouth {self.kernel_params}') - for param in self.kernel_params: - if param not in install_session._kernel_params: - install_session._kernel_params.append(param) - - def _add_hooks(self, install_session: Installer) -> None: - debug('Adding Plymouth hook') - - if self.plymouth_hook in install_session._hooks: - debug(f'{self.plymouth_hook} hook already present') - return - - for hook, insert_after in self._hook_anchors: - try: - index = install_session._hooks.index(hook) - position = index + (1 if insert_after else 0) - install_session._hooks.insert(position, self.plymouth_hook) - debug(f'Plymouth hook inserted {["before", "after"][insert_after]} {hook!r}') - return - except ValueError: - continue - - install_session._hooks.append(self.plymouth_hook) - debug('Plymouth hook appended at end (no anchor hook found)') - - def _set_theme(self, install_session: Installer, theme: str) -> None: - debug(f'Set plymouth theme to {theme}') - install_session.arch_chroot(f'plymouth-set-default-theme {theme}') - - def _regenerate_mkinitcpio(self, install_session: Installer) -> None: - install_session.mkinitcpio(['-P']) diff --git a/archinstall/lib/plymouth/plymouth_menu.py b/archinstall/lib/plymouth/plymouth_menu.py deleted file mode 100644 index ed1d6d94af..0000000000 --- a/archinstall/lib/plymouth/plymouth_menu.py +++ /dev/null @@ -1,26 +0,0 @@ -from archinstall.lib.menu.helpers import Selection -from archinstall.lib.models.plymouth import PlymouthConfiguration, PlymouthTheme -from archinstall.lib.translationhandler import tr -from archinstall.tui.menu_item import MenuItem, MenuItemGroup -from archinstall.tui.result import ResultType - - -async def select_plymouth_theme(preset: PlymouthConfiguration | None = None) -> PlymouthConfiguration | None: - items = [MenuItem(t.value, value=t) for t in PlymouthTheme] - group = MenuItemGroup(items, sort_items=False) - group.set_selected_by_value(preset.plymouth if preset else PlymouthTheme.DISABLED) - - result = await Selection[PlymouthTheme]( - group, - header=tr('Select Plymouth theme'), - allow_reset=True, - allow_skip=True, - ).show() - - match result.type_: - case ResultType.Skip: - return preset - case ResultType.Reset: - return None - case ResultType.Selection: - return PlymouthConfiguration(result.get_value()) diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 2eb7cf1b23..efc22fc4c9 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -20,7 +20,6 @@ from archinstall.lib.models.users import User from archinstall.lib.network.network_handler import install_network_config from archinstall.lib.packages.util import check_version_upgrade -from archinstall.lib.plymouth.plymouth_handler import PlymouthHandler from archinstall.lib.profile.profiles_handler import profile_handler from archinstall.lib.translationhandler import tr from archinstall.tui.components import tui @@ -115,14 +114,12 @@ def perform_installation( if config.swap and config.swap.enabled: installation.setup_swap(algo=config.swap.algorithm) - if config.plymouth_config: - PlymouthHandler().install(installation, config.plymouth_config) - if config.bootloader_config and config.bootloader_config.bootloader != Bootloader.NO_BOOTLOADER: installation.add_bootloader( config.bootloader_config.bootloader, config.bootloader_config.uki, config.bootloader_config.removable, + config.bootloader_config.plymouth, ) if config.network_config: