Skip to content

Commit 80da3f1

Browse files
authored
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
1 parent bf9b9cb commit 80da3f1

File tree

13 files changed

+319
-71
lines changed

13 files changed

+319
-71
lines changed

archinstall/lib/args.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from archinstall.lib.models.mirrors import MirrorConfiguration
2323
from archinstall.lib.models.network import NetworkConfiguration
2424
from archinstall.lib.models.packages import Repository
25+
from archinstall.lib.models.pacman import PacmanConfiguration
2526
from archinstall.lib.models.profile import ProfileConfiguration
2627
from archinstall.lib.models.users import Password, User, UserSerialization
2728
from archinstall.lib.output import debug, error, logger, warn
@@ -73,7 +74,7 @@ class ArchConfig:
7374
kernels: list[str] = field(default_factory=lambda: ['linux'])
7475
ntp: bool = True
7576
packages: list[str] = field(default_factory=list)
76-
parallel_downloads: int = 0
77+
pacman_config: PacmanConfiguration = field(default_factory=PacmanConfiguration.default)
7778
timezone: str = 'UTC'
7879
services: list[str] = field(default_factory=list)
7980
custom_commands: list[str] = field(default_factory=list)
@@ -104,7 +105,7 @@ def safe_config(self) -> dict[str, Any]:
104105
'kernels': self.kernels,
105106
'ntp': self.ntp,
106107
'packages': self.packages,
107-
'parallel_downloads': self.parallel_downloads,
108+
'pacman_config': self.pacman_config.json(),
108109
'swap': self.swap,
109110
'timezone': self.timezone,
110111
'services': self.services,
@@ -209,8 +210,10 @@ def from_config(cls, args_config: dict[str, Any], args: Arguments) -> Self:
209210
if packages := args_config.get('packages', []):
210211
arch_config.packages = packages
211212

212-
if parallel_downloads := args_config.get('parallel_downloads', 0):
213-
arch_config.parallel_downloads = parallel_downloads
213+
if pacman_config := args_config.get('pacman_config', None):
214+
arch_config.pacman_config = PacmanConfiguration.parse_arg(pacman_config)
215+
elif parallel_downloads := args_config.get('parallel_downloads', 0):
216+
arch_config.pacman_config = PacmanConfiguration(parallel_downloads=int(parallel_downloads))
214217

215218
swap_arg = args_config.get('swap')
216219
if swap_arg is not None:

archinstall/lib/general/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from archinstall.lib.general.general_menu import (
2-
add_number_of_parallel_downloads,
32
select_archinstall_language,
43
select_hostname,
54
select_ntp,
@@ -8,7 +7,6 @@
87
from archinstall.lib.general.system_menu import select_driver, select_kernel, select_swap
98

109
__all__ = [
11-
'add_number_of_parallel_downloads',
1210
'select_archinstall_language',
1311
'select_driver',
1412
'select_hostname',

archinstall/lib/general/general_menu.py

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from archinstall.lib.locale.utils import list_timezones
44
from archinstall.lib.menu.helpers import Confirmation, Input, Selection
55
from archinstall.lib.output import warn
6-
from archinstall.lib.pathnames import PACMAN_CONF
76
from archinstall.lib.translationhandler import Language, tr
87
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
98
from archinstall.tui.ui.result import ResultType
@@ -126,55 +125,6 @@ async def select_archinstall_language(languages: list[Language], preset: Languag
126125
raise ValueError('Language selection not handled')
127126

128127

129-
async def add_number_of_parallel_downloads(preset: int = 1) -> int | None:
130-
max_recommended = 5
131-
132-
header = tr('This option enables the number of parallel downloads that can occur during package downloads') + '\n'
133-
header += tr(' - Maximum recommended value : {} ( Allows {} parallel downloads at a time )').format(max_recommended, max_recommended) + '\n\n'
134-
header += tr('Enter the number of parallel downloads to be enabled')
135-
136-
def validator(s: str) -> str | None:
137-
try:
138-
value = int(s)
139-
140-
if 1 <= value <= max_recommended:
141-
return None
142-
143-
return tr('Value must be between 1 and {}').format(max_recommended)
144-
except Exception:
145-
return tr('Please enter a valid number')
146-
147-
result = await Input(
148-
header=header,
149-
allow_skip=True,
150-
allow_reset=True,
151-
validator_callback=validator,
152-
default_value=str(preset),
153-
).show()
154-
155-
downloads = 1
156-
157-
match result.type_:
158-
case ResultType.Skip:
159-
return preset
160-
case ResultType.Reset:
161-
return downloads
162-
case ResultType.Selection:
163-
downloads = int(result.get_value())
164-
165-
with PACMAN_CONF.open() as f:
166-
pacman_conf = f.read().split('\n')
167-
168-
with PACMAN_CONF.open('w') as fwrite:
169-
for line in pacman_conf:
170-
if 'ParallelDownloads' in line:
171-
fwrite.write(f'ParallelDownloads = {downloads}\n')
172-
else:
173-
fwrite.write(f'{line}\n')
174-
175-
return downloads
176-
177-
178128
async def select_post_installation(elapsed_time: float | None = None) -> PostInstallationAction:
179129
header = 'Installation completed'
180130
if elapsed_time is not None:

archinstall/lib/global_menu.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from archinstall.lib.bootloader.bootloader_menu import BootloaderMenu
88
from archinstall.lib.configuration import save_config
99
from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu
10-
from archinstall.lib.general.general_menu import add_number_of_parallel_downloads, select_hostname, select_ntp, select_timezone
10+
from archinstall.lib.general.general_menu import select_hostname, select_ntp, select_timezone
1111
from archinstall.lib.general.system_menu import select_kernel, select_swap
1212
from archinstall.lib.hardware import SysInfo
1313
from archinstall.lib.locale.locale_menu import LocaleMenu
@@ -22,11 +22,13 @@
2222
from archinstall.lib.models.mirrors import MirrorConfiguration
2323
from archinstall.lib.models.network import NetworkConfiguration, NicType
2424
from archinstall.lib.models.packages import Repository
25+
from archinstall.lib.models.pacman import PacmanConfiguration
2526
from archinstall.lib.models.profile import ProfileConfiguration
2627
from archinstall.lib.network.network_menu import select_network
2728
from archinstall.lib.output import FormattedOutput
2829
from archinstall.lib.packages.packages import list_available_packages, select_additional_packages
2930
from archinstall.lib.pacman.config import PacmanConfig
31+
from archinstall.lib.pacman.pacman_menu import PacmanMenu
3032
from archinstall.lib.translationhandler import Language, tr, translation_handler
3133
from archinstall.tui.ui.components import tui
3234
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
@@ -38,11 +40,13 @@ def __init__(
3840
arch_config: ArchConfig,
3941
mirror_list_handler: MirrorListHandler | None = None,
4042
skip_boot: bool = False,
43+
advanced: bool = False,
4144
title: str | None = None,
4245
) -> None:
4346
self._arch_config = arch_config
4447
self._mirror_list_handler = mirror_list_handler
4548
self._skip_boot = skip_boot
49+
self._advanced = advanced
4650
self._uefi = SysInfo.has_uefi()
4751
menu_options = self._get_menu_options()
4852

@@ -138,11 +142,11 @@ def _get_menu_options(self) -> list[MenuItem]:
138142
key='network_config',
139143
),
140144
MenuItem(
141-
text=tr('Parallel Downloads'),
142-
action=add_number_of_parallel_downloads,
143-
value=1,
144-
preview_action=self._prev_parallel_dw,
145-
key='parallel_downloads',
145+
text=tr('Pacman'),
146+
action=self._pacman_configuration,
147+
value=PacmanConfiguration.default(),
148+
preview_action=self._prev_pacman_config,
149+
key='pacman_config',
146150
),
147151
MenuItem(
148152
text=tr('Additional packages'),
@@ -413,10 +417,18 @@ def _prev_hostname(self, item: MenuItem) -> str | None:
413417
return f'{tr("Hostname")}: {item.value}'
414418
return None
415419

416-
def _prev_parallel_dw(self, item: MenuItem) -> str | None:
417-
if item.value is not None:
418-
return f'{tr("Parallel Downloads")}: {item.value}'
419-
return None
420+
async def _pacman_configuration(self, preset: PacmanConfiguration) -> PacmanConfiguration | None:
421+
return await PacmanMenu(preset, advanced=self._advanced).show()
422+
423+
def _prev_pacman_config(self, item: MenuItem) -> str | None:
424+
if not item.value:
425+
return None
426+
config: PacmanConfiguration = item.value
427+
output = ''
428+
if self._advanced:
429+
output += '{}: {}\n'.format(tr('Parallel Downloads'), config.parallel_downloads)
430+
output += '{}: {}'.format(tr('Color'), config.color)
431+
return output
420432

421433
def _prev_kernel(self, item: MenuItem) -> str | None:
422434
if item.value:

archinstall/lib/installer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from archinstall.lib.models.mirrors import MirrorConfiguration
4949
from archinstall.lib.models.network import Nic
5050
from archinstall.lib.models.packages import Repository
51+
from archinstall.lib.models.pacman import PacmanConfiguration
5152
from archinstall.lib.models.users import User
5253
from archinstall.lib.output import debug, error, info, log, logger, warn
5354
from archinstall.lib.packages.packages import installed_package
@@ -886,6 +887,7 @@ def minimal_installation(
886887
mkinitcpio: bool = True,
887888
hostname: str | None = None,
888889
locale_config: LocaleConfiguration | None = LocaleConfiguration.default(),
890+
pacman_config: PacmanConfiguration | None = None,
889891
) -> None:
890892
if self._disk_config.lvm_config:
891893
lvm = 'lvm2'
@@ -932,6 +934,9 @@ def minimal_installation(
932934

933935
pacman_conf.persist()
934936

937+
if pacman_config:
938+
pacman_conf.configure(pacman_config)
939+
935940
# Periodic TRIM may improve the performance and longevity of SSDs whilst
936941
# having no adverse effect on other devices. Most distributions enable
937942
# periodic TRIM by default.

archinstall/lib/models/pacman.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from dataclasses import dataclass
2+
from typing import Self, TypedDict
3+
4+
from archinstall.lib.translationhandler import tr
5+
6+
7+
class PacmanConfigSerialization(TypedDict):
8+
parallel_downloads: int
9+
color: bool
10+
11+
12+
@dataclass
13+
class PacmanConfiguration:
14+
parallel_downloads: int = 5
15+
color: bool = True
16+
17+
@classmethod
18+
def default(cls) -> Self:
19+
return cls()
20+
21+
def json(self) -> PacmanConfigSerialization:
22+
return {
23+
'parallel_downloads': self.parallel_downloads,
24+
'color': self.color,
25+
}
26+
27+
def preview(self) -> str:
28+
color_str = str(self.color)
29+
output = '{}: {}\n'.format(tr('Parallel Downloads'), self.parallel_downloads)
30+
output += '{}: {}'.format(tr('Color'), color_str)
31+
return output
32+
33+
@classmethod
34+
def parse_arg(cls, args: PacmanConfigSerialization) -> Self:
35+
config = cls.default()
36+
37+
if 'parallel_downloads' in args:
38+
config.parallel_downloads = int(args['parallel_downloads'])
39+
if 'color' in args:
40+
config.color = bool(args['color'])
41+
42+
return config

archinstall/lib/pacman/config.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from pathlib import Path
33

44
from archinstall.lib.models.packages import Repository
5+
from archinstall.lib.models.pacman import PacmanConfiguration
56
from archinstall.lib.pathnames import PACMAN_CONF
67

78

@@ -50,5 +51,23 @@ def apply(self) -> None:
5051
f.writelines(content)
5152

5253
def persist(self) -> None:
53-
if self._repositories and self._config_remote_path:
54+
if self._config_remote_path:
5455
PACMAN_CONF.copy(self._config_remote_path, preserve_metadata=True)
56+
57+
def configure(self, pacman_config: PacmanConfiguration) -> None:
58+
"""Apply PacmanConfiguration (Color, ParallelDownloads) to the target system's pacman.conf."""
59+
if not self._config_remote_path or not self._config_remote_path.exists():
60+
return
61+
62+
content = self._config_remote_path.read_text().splitlines()
63+
result = []
64+
65+
for line in content:
66+
if re.match(r'^#?\s*ParallelDownloads', line):
67+
result.append(f'ParallelDownloads = {pacman_config.parallel_downloads}')
68+
elif re.match(r'^#?\s*Color\s*$', line):
69+
result.append('Color' if pacman_config.color else '#Color')
70+
else:
71+
result.append(line)
72+
73+
self._config_remote_path.write_text('\n'.join(result) + '\n')

0 commit comments

Comments
 (0)