From 8a3f50c74bcfda1c56b1fc56e3c09d736c0861b1 Mon Sep 17 00:00:00 2001 From: h8d13 Date: Fri, 9 Jan 2026 14:19:11 +0100 Subject: [PATCH 1/4] Init mngmnt --- archinstall/applications/management.py | 20 ++++++++++ .../lib/applications/application_handler.py | 7 ++++ .../lib/applications/application_menu.py | 39 +++++++++++++++++++ archinstall/lib/global_menu.py | 5 +++ archinstall/lib/models/application.py | 34 ++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 archinstall/applications/management.py diff --git a/archinstall/applications/management.py b/archinstall/applications/management.py new file mode 100644 index 0000000000..ed59ab83d7 --- /dev/null +++ b/archinstall/applications/management.py @@ -0,0 +1,20 @@ +from typing import TYPE_CHECKING + +from archinstall.lib.models.application import Management, ManagementConfiguration +from archinstall.lib.output import debug + +if TYPE_CHECKING: + from archinstall.lib.installer import Installer + + +class ManagementApp: + def install( + self, + install_session: 'Installer', + management_config: ManagementConfiguration, + ) -> None: + debug(f'Installing management tools: {[t.value for t in management_config.tools]}') + + packages = [tool.value for tool in management_config.tools] + if packages: + install_session.add_additional_packages(packages) diff --git a/archinstall/lib/applications/application_handler.py b/archinstall/lib/applications/application_handler.py index e7d16058d5..fb30663c32 100644 --- a/archinstall/lib/applications/application_handler.py +++ b/archinstall/lib/applications/application_handler.py @@ -3,6 +3,7 @@ from archinstall.applications.audio import AudioApp from archinstall.applications.bluetooth import BluetoothApp from archinstall.applications.firewall import FirewallApp +from archinstall.applications.management import ManagementApp from archinstall.applications.power_management import PowerManagementApp from archinstall.applications.print_service import PrintServiceApp from archinstall.lib.models import Audio @@ -43,5 +44,11 @@ def install_applications(self, install_session: 'Installer', app_config: Applica app_config.firewall_config, ) + if app_config.management_config and app_config.management_config.tools: + ManagementApp().install( + install_session, + app_config.management_config, + ) + application_handler = ApplicationHandler() diff --git a/archinstall/lib/applications/application_menu.py b/archinstall/lib/applications/application_menu.py index 7dd56e9871..18b4e7a7ab 100644 --- a/archinstall/lib/applications/application_menu.py +++ b/archinstall/lib/applications/application_menu.py @@ -9,6 +9,8 @@ BluetoothConfiguration, Firewall, FirewallConfiguration, + Management, + ManagementConfiguration, PowerManagement, PowerManagementConfiguration, PrintServiceConfiguration, @@ -78,6 +80,12 @@ def _define_menu_options(self) -> list[MenuItem]: preview_action=self._prev_firewall, key='firewall_config', ), + MenuItem( + text=tr('Management'), + action=select_management, + preview_action=self._prev_management, + key='management_config', + ), ] def _prev_power_management(self, item: MenuItem) -> str | None: @@ -116,6 +124,13 @@ def _prev_firewall(self, item: MenuItem) -> str | None: return f'{tr("Firewall")}: {config.firewall.value}' return None + def _prev_management(self, item: MenuItem) -> str | None: + if item.value is not None: + config: ManagementConfiguration = item.value + tools = ', '.join([t.value for t in config.tools]) + return f'{tr("Management")}: {tools}' + return None + def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None: group = MenuItemGroup.from_enum(PowerManagement) @@ -240,3 +255,27 @@ def select_firewall(preset: FirewallConfiguration | None = None) -> FirewallConf return FirewallConfiguration(firewall=result.get_value()) case ResultType.Reset: return None + + +def select_management(preset: ManagementConfiguration | None = None) -> ManagementConfiguration | None: + group = MenuItemGroup.from_enum(Management) + + if preset: + group.set_selected_by_value(preset.tools) + + result = SelectMenu[Management]( + group, + allow_skip=True, + alignment=Alignment.CENTER, + allow_reset=True, + frame=FrameProperties.min(tr('Management')), + multi=True, + ).run() + + match result.type_: + case ResultType.Skip: + return preset + case ResultType.Selection: + return ManagementConfiguration(tools=result.get_values()) + case ResultType.Reset: + return None diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index dbf728a2cb..3a71f8423c 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -346,6 +346,11 @@ def _prev_applications(self, item: MenuItem) -> str | None: output += f'{tr("Firewall")}: {firewall_config.firewall.value}' output += '\n' + if app_config.management_config and app_config.management_config.tools: + tools = ', '.join([t.value for t in app_config.management_config.tools]) + output += f'{tr("Management")}: {tools}' + output += '\n' + return output return None diff --git a/archinstall/lib/models/application.py b/archinstall/lib/models/application.py index 7ecb7a0717..0f02ef8f8a 100644 --- a/archinstall/lib/models/application.py +++ b/archinstall/lib/models/application.py @@ -38,6 +38,16 @@ class FirewallConfigSerialization(TypedDict): firewall: str +class Management(StrEnum): + MAN = 'man-db' + PACMAN_CONTRIB = 'pacman-contrib' + REFLECTOR = 'reflector' + + +class ManagementConfigSerialization(TypedDict): + tools: list[str] + + class ZramAlgorithm(StrEnum): ZSTD = 'zstd' LZO_RLE = 'lzo-rle' @@ -52,6 +62,7 @@ class ApplicationSerialization(TypedDict): power_management_config: NotRequired[PowerManagementConfigSerialization] print_service_config: NotRequired[PrintServiceConfigSerialization] firewall_config: NotRequired[FirewallConfigSerialization] + management_config: NotRequired[ManagementConfigSerialization] @dataclass @@ -126,6 +137,22 @@ def parse_arg(arg: dict[str, Any]) -> 'FirewallConfiguration': ) +@dataclass +class ManagementConfiguration: + tools: list[Management] + + def json(self) -> ManagementConfigSerialization: + return { + 'tools': [t.value for t in self.tools], + } + + @staticmethod + def parse_arg(arg: dict[str, Any]) -> 'ManagementConfiguration': + return ManagementConfiguration( + tools=[Management(t) for t in arg['tools']], + ) + + @dataclass(frozen=True) class ZramConfiguration: enabled: bool @@ -148,6 +175,7 @@ class ApplicationConfiguration: power_management_config: PowerManagementConfiguration | None = None print_service_config: PrintServiceConfiguration | None = None firewall_config: FirewallConfiguration | None = None + management_config: ManagementConfiguration | None = None @staticmethod def parse_arg( @@ -175,6 +203,9 @@ def parse_arg( if args and (firewall_config := args.get('firewall_config')) is not None: app_config.firewall_config = FirewallConfiguration.parse_arg(firewall_config) + if args and (management_config := args.get('management_config')) is not None: + app_config.management_config = ManagementConfiguration.parse_arg(management_config) + return app_config def json(self) -> ApplicationSerialization: @@ -195,4 +226,7 @@ def json(self) -> ApplicationSerialization: if self.firewall_config: config['firewall_config'] = self.firewall_config.json() + if self.management_config: + config['management_config'] = self.management_config.json() + return config From dd2cc650a93c5409a780b2799547a38582c54ba9 Mon Sep 17 00:00:00 2001 From: h8d13 Date: Fri, 9 Jan 2026 14:24:06 +0100 Subject: [PATCH 2/4] Imports --- archinstall/applications/management.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/applications/management.py b/archinstall/applications/management.py index ed59ab83d7..ae0e1a2bdf 100644 --- a/archinstall/applications/management.py +++ b/archinstall/applications/management.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING -from archinstall.lib.models.application import Management, ManagementConfiguration +from archinstall.lib.models.application import ManagementConfiguration from archinstall.lib.output import debug if TYPE_CHECKING: From 2ce2ba5a3d81beac1bffd119c5af27d3b88a8b1f Mon Sep 17 00:00:00 2001 From: h8d13 Date: Fri, 9 Jan 2026 14:44:56 +0100 Subject: [PATCH 3/4] correctmost feedback --- archinstall/lib/models/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/lib/models/application.py b/archinstall/lib/models/application.py index 0f02ef8f8a..088fd67d53 100644 --- a/archinstall/lib/models/application.py +++ b/archinstall/lib/models/application.py @@ -147,7 +147,7 @@ def json(self) -> ManagementConfigSerialization: } @staticmethod - def parse_arg(arg: dict[str, Any]) -> 'ManagementConfiguration': + def parse_arg(arg: ManagementConfigSerialization) -> 'ManagementConfiguration': return ManagementConfiguration( tools=[Management(t) for t in arg['tools']], ) From bb437661d2052911cf4d6a2f9485828baf19b776 Mon Sep 17 00:00:00 2001 From: h8d13 Date: Fri, 9 Jan 2026 17:07:17 +0100 Subject: [PATCH 4/4] Add header --- archinstall/lib/applications/application_menu.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/archinstall/lib/applications/application_menu.py b/archinstall/lib/applications/application_menu.py index 18b4e7a7ab..0095996f23 100644 --- a/archinstall/lib/applications/application_menu.py +++ b/archinstall/lib/applications/application_menu.py @@ -260,11 +260,14 @@ def select_firewall(preset: FirewallConfiguration | None = None) -> FirewallConf def select_management(preset: ManagementConfiguration | None = None) -> ManagementConfiguration | None: group = MenuItemGroup.from_enum(Management) + header = tr('Would you like to install management tools?') + '\n' + if preset: group.set_selected_by_value(preset.tools) result = SelectMenu[Management]( group, + header=header, allow_skip=True, alignment=Alignment.CENTER, allow_reset=True,