From 80da3f14a1d401fe7e47005ae4eec99379152e6a Mon Sep 17 00:00:00 2001 From: Softer Date: Mon, 13 Apr 2026 11:37:51 +0300 Subject: [PATCH] Add Pacman settings submenu with Color and ParallelDownloads (#4404) * Add Pacman settings submenu with Color and ParallelDownloads Replace the standalone Parallel Downloads menu item with a Pacman submenu containing ParallelDownloads (default 5) and Color (default on). Settings are applied to both live and target system pacman.conf. Hidden behind --advanced flag. Backward compatible with old configs using "parallel_downloads" key. * Skip _apply_to_live when user exits Pacman menu without changes * Use TypedDict for PacmanConfiguration serialization * Show Pacman menu by default, keep ParallelDownloads behind --advanced --- archinstall/lib/args.py | 11 +- archinstall/lib/general/__init__.py | 2 - archinstall/lib/general/general_menu.py | 50 --------- archinstall/lib/global_menu.py | 32 ++++-- archinstall/lib/installer.py | 5 + archinstall/lib/models/pacman.py | 42 ++++++++ archinstall/lib/pacman/config.py | 21 +++- archinstall/lib/pacman/pacman_menu.py | 117 +++++++++++++++++++++ archinstall/locales/base.pot | 46 ++++++++ archinstall/locales/uk/LC_MESSAGES/base.mo | Bin 83294 -> 83620 bytes archinstall/locales/uk/LC_MESSAGES/base.po | 56 ++++++++++ archinstall/scripts/guided.py | 5 +- tests/test_args.py | 3 +- 13 files changed, 319 insertions(+), 71 deletions(-) create mode 100644 archinstall/lib/models/pacman.py create mode 100644 archinstall/lib/pacman/pacman_menu.py diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index c61bc5a1..20ff37cf 100644 --- a/archinstall/lib/args.py +++ b/archinstall/lib/args.py @@ -22,6 +22,7 @@ from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.mirrors import MirrorConfiguration from archinstall.lib.models.network import NetworkConfiguration from archinstall.lib.models.packages import Repository +from archinstall.lib.models.pacman import PacmanConfiguration from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.models.users import Password, User, UserSerialization from archinstall.lib.output import debug, error, logger, warn @@ -73,7 +74,7 @@ class ArchConfig: kernels: list[str] = field(default_factory=lambda: ['linux']) ntp: bool = True packages: list[str] = field(default_factory=list) - parallel_downloads: int = 0 + pacman_config: PacmanConfiguration = field(default_factory=PacmanConfiguration.default) timezone: str = 'UTC' services: list[str] = field(default_factory=list) custom_commands: list[str] = field(default_factory=list) @@ -104,7 +105,7 @@ class ArchConfig: 'kernels': self.kernels, 'ntp': self.ntp, 'packages': self.packages, - 'parallel_downloads': self.parallel_downloads, + 'pacman_config': self.pacman_config.json(), 'swap': self.swap, 'timezone': self.timezone, 'services': self.services, @@ -209,8 +210,10 @@ class ArchConfig: if packages := args_config.get('packages', []): arch_config.packages = packages - if parallel_downloads := args_config.get('parallel_downloads', 0): - arch_config.parallel_downloads = parallel_downloads + if pacman_config := args_config.get('pacman_config', None): + arch_config.pacman_config = PacmanConfiguration.parse_arg(pacman_config) + elif parallel_downloads := args_config.get('parallel_downloads', 0): + arch_config.pacman_config = PacmanConfiguration(parallel_downloads=int(parallel_downloads)) swap_arg = args_config.get('swap') if swap_arg is not None: diff --git a/archinstall/lib/general/__init__.py b/archinstall/lib/general/__init__.py index 21add834..7c082d84 100644 --- a/archinstall/lib/general/__init__.py +++ b/archinstall/lib/general/__init__.py @@ -1,5 +1,4 @@ from archinstall.lib.general.general_menu import ( - add_number_of_parallel_downloads, select_archinstall_language, select_hostname, select_ntp, @@ -8,7 +7,6 @@ from archinstall.lib.general.general_menu import ( from archinstall.lib.general.system_menu import select_driver, select_kernel, select_swap __all__ = [ - 'add_number_of_parallel_downloads', 'select_archinstall_language', 'select_driver', 'select_hostname', diff --git a/archinstall/lib/general/general_menu.py b/archinstall/lib/general/general_menu.py index b6cf9a75..ad85c14b 100644 --- a/archinstall/lib/general/general_menu.py +++ b/archinstall/lib/general/general_menu.py @@ -3,7 +3,6 @@ from enum import Enum from archinstall.lib.locale.utils import list_timezones from archinstall.lib.menu.helpers import Confirmation, Input, Selection from archinstall.lib.output import warn -from archinstall.lib.pathnames import PACMAN_CONF from archinstall.lib.translationhandler import Language, tr from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup from archinstall.tui.ui.result import ResultType @@ -126,55 +125,6 @@ async def select_archinstall_language(languages: list[Language], preset: Languag raise ValueError('Language selection not handled') -async def add_number_of_parallel_downloads(preset: int = 1) -> int | None: - max_recommended = 5 - - header = tr('This option enables the number of parallel downloads that can occur during package downloads') + '\n' - header += tr(' - Maximum recommended value : {} ( Allows {} parallel downloads at a time )').format(max_recommended, max_recommended) + '\n\n' - header += tr('Enter the number of parallel downloads to be enabled') - - def validator(s: str) -> str | None: - try: - value = int(s) - - if 1 <= value <= max_recommended: - return None - - return tr('Value must be between 1 and {}').format(max_recommended) - except Exception: - return tr('Please enter a valid number') - - result = await Input( - header=header, - allow_skip=True, - allow_reset=True, - validator_callback=validator, - default_value=str(preset), - ).show() - - downloads = 1 - - match result.type_: - case ResultType.Skip: - return preset - case ResultType.Reset: - return downloads - case ResultType.Selection: - downloads = int(result.get_value()) - - with PACMAN_CONF.open() as f: - pacman_conf = f.read().split('\n') - - with PACMAN_CONF.open('w') as fwrite: - for line in pacman_conf: - if 'ParallelDownloads' in line: - fwrite.write(f'ParallelDownloads = {downloads}\n') - else: - fwrite.write(f'{line}\n') - - return downloads - - async def select_post_installation(elapsed_time: float | None = None) -> PostInstallationAction: header = 'Installation completed' if elapsed_time is not None: diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index bbd530a8..6e4b6720 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -7,7 +7,7 @@ from archinstall.lib.authentication.authentication_menu import AuthenticationMen from archinstall.lib.bootloader.bootloader_menu import BootloaderMenu from archinstall.lib.configuration import save_config from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu -from archinstall.lib.general.general_menu import add_number_of_parallel_downloads, select_hostname, select_ntp, select_timezone +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.hardware import SysInfo from archinstall.lib.locale.locale_menu import LocaleMenu @@ -22,11 +22,13 @@ from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.mirrors import MirrorConfiguration from archinstall.lib.models.network import NetworkConfiguration, NicType from archinstall.lib.models.packages import Repository +from archinstall.lib.models.pacman import PacmanConfiguration from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.network.network_menu import select_network from archinstall.lib.output import FormattedOutput 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.translationhandler import Language, tr, translation_handler from archinstall.tui.ui.components import tui from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup @@ -38,11 +40,13 @@ class GlobalMenu(AbstractMenu[None]): arch_config: ArchConfig, mirror_list_handler: MirrorListHandler | None = None, skip_boot: bool = False, + advanced: bool = False, title: str | None = None, ) -> None: self._arch_config = arch_config self._mirror_list_handler = mirror_list_handler self._skip_boot = skip_boot + self._advanced = advanced self._uefi = SysInfo.has_uefi() menu_options = self._get_menu_options() @@ -138,11 +142,11 @@ class GlobalMenu(AbstractMenu[None]): key='network_config', ), MenuItem( - text=tr('Parallel Downloads'), - action=add_number_of_parallel_downloads, - value=1, - preview_action=self._prev_parallel_dw, - key='parallel_downloads', + text=tr('Pacman'), + action=self._pacman_configuration, + value=PacmanConfiguration.default(), + preview_action=self._prev_pacman_config, + key='pacman_config', ), MenuItem( text=tr('Additional packages'), @@ -413,10 +417,18 @@ class GlobalMenu(AbstractMenu[None]): return f'{tr("Hostname")}: {item.value}' return None - def _prev_parallel_dw(self, item: MenuItem) -> str | None: - if item.value is not None: - return f'{tr("Parallel Downloads")}: {item.value}' - return None + async def _pacman_configuration(self, preset: PacmanConfiguration) -> PacmanConfiguration | None: + return await PacmanMenu(preset, advanced=self._advanced).show() + + def _prev_pacman_config(self, item: MenuItem) -> str | None: + if not item.value: + return None + config: PacmanConfiguration = item.value + output = '' + if self._advanced: + output += '{}: {}\n'.format(tr('Parallel Downloads'), config.parallel_downloads) + output += '{}: {}'.format(tr('Color'), config.color) + return output def _prev_kernel(self, item: MenuItem) -> str | None: if item.value: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index ff56e2e1..43077c63 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -48,6 +48,7 @@ from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.mirrors import MirrorConfiguration from archinstall.lib.models.network import Nic from archinstall.lib.models.packages import Repository +from archinstall.lib.models.pacman import PacmanConfiguration from archinstall.lib.models.users import User from archinstall.lib.output import debug, error, info, log, logger, warn from archinstall.lib.packages.packages import installed_package @@ -886,6 +887,7 @@ class Installer: mkinitcpio: bool = True, hostname: str | None = None, locale_config: LocaleConfiguration | None = LocaleConfiguration.default(), + pacman_config: PacmanConfiguration | None = None, ) -> None: if self._disk_config.lvm_config: lvm = 'lvm2' @@ -932,6 +934,9 @@ class Installer: pacman_conf.persist() + if pacman_config: + pacman_conf.configure(pacman_config) + # Periodic TRIM may improve the performance and longevity of SSDs whilst # having no adverse effect on other devices. Most distributions enable # periodic TRIM by default. diff --git a/archinstall/lib/models/pacman.py b/archinstall/lib/models/pacman.py new file mode 100644 index 00000000..5d271ea9 --- /dev/null +++ b/archinstall/lib/models/pacman.py @@ -0,0 +1,42 @@ +from dataclasses import dataclass +from typing import Self, TypedDict + +from archinstall.lib.translationhandler import tr + + +class PacmanConfigSerialization(TypedDict): + parallel_downloads: int + color: bool + + +@dataclass +class PacmanConfiguration: + parallel_downloads: int = 5 + color: bool = True + + @classmethod + def default(cls) -> Self: + return cls() + + def json(self) -> PacmanConfigSerialization: + return { + 'parallel_downloads': self.parallel_downloads, + 'color': self.color, + } + + def preview(self) -> str: + color_str = str(self.color) + output = '{}: {}\n'.format(tr('Parallel Downloads'), self.parallel_downloads) + output += '{}: {}'.format(tr('Color'), color_str) + return output + + @classmethod + def parse_arg(cls, args: PacmanConfigSerialization) -> Self: + config = cls.default() + + if 'parallel_downloads' in args: + config.parallel_downloads = int(args['parallel_downloads']) + if 'color' in args: + config.color = bool(args['color']) + + return config diff --git a/archinstall/lib/pacman/config.py b/archinstall/lib/pacman/config.py index 1d361542..5785b319 100644 --- a/archinstall/lib/pacman/config.py +++ b/archinstall/lib/pacman/config.py @@ -2,6 +2,7 @@ import re from pathlib import Path from archinstall.lib.models.packages import Repository +from archinstall.lib.models.pacman import PacmanConfiguration from archinstall.lib.pathnames import PACMAN_CONF @@ -50,5 +51,23 @@ class PacmanConfig: f.writelines(content) def persist(self) -> None: - if self._repositories and self._config_remote_path: + if self._config_remote_path: PACMAN_CONF.copy(self._config_remote_path, preserve_metadata=True) + + def configure(self, pacman_config: PacmanConfiguration) -> None: + """Apply PacmanConfiguration (Color, ParallelDownloads) to the target system's pacman.conf.""" + if not self._config_remote_path or not self._config_remote_path.exists(): + return + + content = self._config_remote_path.read_text().splitlines() + result = [] + + for line in content: + if re.match(r'^#?\s*ParallelDownloads', line): + result.append(f'ParallelDownloads = {pacman_config.parallel_downloads}') + elif re.match(r'^#?\s*Color\s*$', line): + result.append('Color' if pacman_config.color else '#Color') + else: + result.append(line) + + self._config_remote_path.write_text('\n'.join(result) + '\n') diff --git a/archinstall/lib/pacman/pacman_menu.py b/archinstall/lib/pacman/pacman_menu.py new file mode 100644 index 00000000..010c3f6d --- /dev/null +++ b/archinstall/lib/pacman/pacman_menu.py @@ -0,0 +1,117 @@ +from typing import override + +from archinstall.lib.menu.abstract_menu import AbstractSubMenu +from archinstall.lib.menu.helpers import Confirmation, Input +from archinstall.lib.models.pacman import PacmanConfiguration +from archinstall.lib.pathnames import PACMAN_CONF +from archinstall.lib.translationhandler import tr +from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup +from archinstall.tui.ui.result import ResultType + + +class PacmanMenu(AbstractSubMenu[PacmanConfiguration]): + def __init__( + self, + pacman_conf: PacmanConfiguration, + advanced: bool = False, + ): + self._pacman_conf = pacman_conf + self._advanced = advanced + menu_options = self._define_menu_options() + + self._item_group = MenuItemGroup(menu_options, sort_items=False, checkmarks=True) + super().__init__( + self._item_group, + config=self._pacman_conf, + allow_reset=True, + ) + + def _define_menu_options(self) -> list[MenuItem]: + return [ + MenuItem( + text=tr('Parallel Downloads'), + action=select_parallel_downloads, + value=self._pacman_conf.parallel_downloads, + preview_action=lambda item: str(item.get_value()), + key='parallel_downloads', + enabled=self._advanced, + ), + MenuItem( + text=tr('Color'), + action=select_color, + value=self._pacman_conf.color, + preview_action=lambda item: str(item.get_value()), + key='color', + ), + ] + + @override + async def show(self) -> PacmanConfiguration | None: + config = await super().show() + + if config is None: + return PacmanConfiguration.default() + + _apply_to_live(config.parallel_downloads) + + return config + + +def _apply_to_live(parallel_downloads: int) -> None: + """Apply ParallelDownloads to live system pacman.conf for faster installation.""" + with PACMAN_CONF.open() as f: + pacman_conf = f.read().split('\n') + + with PACMAN_CONF.open('w') as fwrite: + for line in pacman_conf: + if 'ParallelDownloads' in line: + fwrite.write(f'ParallelDownloads = {parallel_downloads}\n') + else: + fwrite.write(f'{line}\n') + + +async def select_parallel_downloads(preset: int = 5) -> int | None: + max_recommended = 10 + + header = tr('Enter the number of parallel downloads (1-{})').format(max_recommended) + + def validator(s: str) -> str | None: + try: + value = int(s) + if 1 <= value <= max_recommended: + return None + return tr('Value must be between 1 and {}').format(max_recommended) + except Exception: + return tr('Please enter a valid number') + + result = await Input( + header=header, + allow_skip=True, + allow_reset=True, + validator_callback=validator, + default_value=str(preset), + ).show() + + match result.type_: + case ResultType.Skip: + return preset + case ResultType.Reset: + return 5 + case ResultType.Selection: + return int(result.get_value()) + + +async def select_color(preset: bool = True) -> bool | None: + result = await Confirmation( + header=tr('Enable colored output for pacman'), + preset=preset, + allow_skip=True, + ).show() + + match result.type_: + case ResultType.Skip: + return preset + case ResultType.Reset: + return True + case ResultType.Selection: + return result.get_value() diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 27fa4eee..9d61ca77 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -830,6 +830,19 @@ msgstr "" msgid "Parallel Downloads" msgstr "" +msgid "Pacman" +msgstr "" + +msgid "Color" +msgstr "" + +#, python-brace-format +msgid "Enter the number of parallel downloads (1-{})" +msgstr "" + +msgid "Enable colored output for pacman" +msgstr "" + msgid "ESC to skip" msgstr "" @@ -2184,3 +2197,36 @@ msgstr "" #, python-brace-format msgid "Environment type: {} {}" msgstr "" + +msgid "Input cannot be empty" +msgstr "" + +msgid "Recommended" +msgstr "" + +msgid "Package" +msgstr "" + +msgid "Curated selection of KDE Plasma packages" +msgstr "" + +msgid "Dependencies" +msgstr "" + +msgid "Package group" +msgstr "" + +msgid "Extensive KDE Plasma installation" +msgstr "" + +msgid "Packages in group" +msgstr "" + +msgid "Minimal KDE Plasma installation" +msgstr "" + +msgid "Description" +msgstr "" + +msgid "Select a flavor of KDE Plasma to install" +msgstr "" diff --git a/archinstall/locales/uk/LC_MESSAGES/base.mo b/archinstall/locales/uk/LC_MESSAGES/base.mo index ad1301397a91623ff58a2cd270dab383c6b78a3b..1cb241b953ad7bfa04c89f0cc971028c6c9b569b 100644 GIT binary patch delta 14285 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 diff --git a/archinstall/locales/uk/LC_MESSAGES/base.po b/archinstall/locales/uk/LC_MESSAGES/base.po index 5ad4bcb3..04695709 100644 --- a/archinstall/locales/uk/LC_MESSAGES/base.po +++ b/archinstall/locales/uk/LC_MESSAGES/base.po @@ -823,6 +823,19 @@ msgstr "Некоректне введення! Повторіть спробу msgid "Parallel Downloads" msgstr "Паралельні Завантаження" +msgid "Pacman" +msgstr "Pacman" + +msgid "Color" +msgstr "Колір" + +#, python-brace-format +msgid "Enter the number of parallel downloads (1-{})" +msgstr "Введіть кількість паралельних завантажень (1-{})" + +msgid "Enable colored output for pacman" +msgstr "Увімкнути кольоровий вивід для pacman" + msgid "ESC to skip" msgstr "ESC, щоб пропустити" @@ -2119,3 +2132,46 @@ msgstr "Надійність пароля: Сильна" msgid "The selected desktop profile requires a regular user to log in via the greeter" msgstr "Обраний профіль робочого столу вимагає входу звичайного користувача через менеджер входу" + +#, fuzzy, python-brace-format +msgid "Environment type: {} {}" +msgstr "Тип середовища: {}" + +#, fuzzy +msgid "Input cannot be empty" +msgstr "Значення не може бути пустим" + +msgid "Recommended" +msgstr "" + +#, fuzzy +msgid "Package" +msgstr "Група пакетів:" + +msgid "Curated selection of KDE Plasma packages" +msgstr "" + +msgid "Dependencies" +msgstr "" + +#, fuzzy +msgid "Package group" +msgstr "Група пакетів:" + +msgid "Extensive KDE Plasma installation" +msgstr "" + +#, fuzzy +msgid "Packages in group" +msgstr "Група пакетів:" + +msgid "Minimal KDE Plasma installation" +msgstr "" + +#, fuzzy +msgid "Description" +msgstr "Шифрування диска" + +#, fuzzy +msgid "Select a flavor of KDE Plasma to install" +msgstr "Оберіть завантажувач для встановлення" diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 5683ab9e..601ca7bc 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -39,12 +39,10 @@ def show_menu( arch_config_handler.config, mirror_list_handler, arch_config_handler.args.skip_boot, + advanced=arch_config_handler.args.advanced, title=title_text, ) - if not arch_config_handler.args.advanced: - global_menu.set_enabled('parallel_downloads', False) - result: ArchConfig | None = tui.run(global_menu) if result is None: sys.exit(0) @@ -106,6 +104,7 @@ def perform_installation( mkinitcpio=run_mkinitcpio, hostname=arch_config_handler.config.hostname, locale_config=locale_config, + pacman_config=config.pacman_config, ) if mirror_config := config.mirror_config: diff --git a/tests/test_args.py b/tests/test_args.py index 1b052ec0..4cbad41b 100644 --- a/tests/test_args.py +++ b/tests/test_args.py @@ -22,6 +22,7 @@ from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.mirrors import CustomRepository, CustomServer, MirrorConfiguration, MirrorRegion, SignCheck, SignOption from archinstall.lib.models.network import NetworkConfiguration, Nic, NicType from archinstall.lib.models.packages import Repository +from archinstall.lib.models.pacman import PacmanConfiguration from archinstall.lib.models.profile import ProfileConfiguration from archinstall.lib.models.users import Password, User from archinstall.lib.profile.profiles_handler import profile_handler @@ -234,7 +235,7 @@ def test_config_file_parsing( kernels=['linux-zen'], ntp=True, packages=['firefox'], - parallel_downloads=66, + pacman_config=PacmanConfiguration(parallel_downloads=66), swap=ZramConfiguration(enabled=False), timezone='UTC', services=['service_1', 'service_2'],