diff --git a/archinstall/applications/print_service.py b/archinstall/applications/print_service.py new file mode 100644 index 00000000..7660bad4 --- /dev/null +++ b/archinstall/applications/print_service.py @@ -0,0 +1,23 @@ +from typing import TYPE_CHECKING + +from archinstall.lib.output import debug + +if TYPE_CHECKING: + from archinstall.lib.installer import Installer + + +class PrintServiceApp: + @property + def packages(self) -> list[str]: + return ['cups', 'system-config-printer', 'cups-pk-helper'] + + @property + def services(self) -> list[str]: + return [ + 'cups.service', + ] + + def install(self, install_session: 'Installer') -> None: + debug('Installing print service') + install_session.add_additional_packages(self.packages) + install_session.enable_service(self.services) diff --git a/archinstall/lib/applications/application_handler.py b/archinstall/lib/applications/application_handler.py index 29e30f47..990b49fb 100644 --- a/archinstall/lib/applications/application_handler.py +++ b/archinstall/lib/applications/application_handler.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING from archinstall.applications.audio import AudioApp from archinstall.applications.bluetooth import BluetoothApp +from archinstall.applications.print_service import PrintServiceApp from archinstall.lib.models import Audio from archinstall.lib.models.application import ApplicationConfiguration from archinstall.lib.models.users import User @@ -25,5 +26,8 @@ class ApplicationHandler: users, ) + if app_config.print_service_config and app_config.print_service_config.enabled: + PrintServiceApp().install(install_session) + application_handler = ApplicationHandler() diff --git a/archinstall/lib/applications/application_menu.py b/archinstall/lib/applications/application_menu.py index c633ea4d..30ca4dbb 100644 --- a/archinstall/lib/applications/application_menu.py +++ b/archinstall/lib/applications/application_menu.py @@ -1,7 +1,7 @@ from typing import override from archinstall.lib.menu.abstract_menu import AbstractSubMenu -from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration +from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration from archinstall.lib.translationhandler import tr from archinstall.tui.curses_menu import SelectMenu from archinstall.tui.menu_item import MenuItem, MenuItemGroup @@ -48,6 +48,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]): preview_action=self._prev_audio, key='audio_config', ), + MenuItem( + text=tr('Print service'), + action=select_print_service, + preview_action=self._prev_print_service, + key='print_service_config', + ), ] def _prev_bluetooth(self, item: MenuItem) -> str | None: @@ -65,6 +71,15 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]): return f'{tr("Audio")}: {config.audio.value}' return None + def _prev_print_service(self, item: MenuItem) -> str | None: + if item.value is not None: + print_service_config: PrintServiceConfiguration = item.value + + output = f'{tr("Print service")}: ' + output += tr('Enabled') if print_service_config.enabled else tr('Disabled') + return output + return None + def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None: group = MenuItemGroup.yes_no() @@ -94,6 +109,34 @@ def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfigur raise ValueError('Unhandled result type') +def select_print_service(preset: PrintServiceConfiguration | None) -> PrintServiceConfiguration | None: + group = MenuItemGroup.yes_no() + group.focus_item = MenuItem.no() + + if preset is not None: + group.set_selected_by_value(preset.enabled) + + header = tr('Would you like to configure the print service?') + '\n' + + result = SelectMenu[bool]( + group, + header=header, + alignment=Alignment.CENTER, + columns=2, + orientation=Orientation.HORIZONTAL, + allow_skip=True, + ).run() + + match result.type_: + case ResultType.Selection: + enabled = result.item() == MenuItem.yes() + return PrintServiceConfiguration(enabled) + case ResultType.Skip: + return preset + case _: + raise ValueError('Unhandled result type') + + def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration | None: items = [MenuItem(a.value, value=a) for a in Audio] group = MenuItemGroup(items) diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index 8c13daf4..9f7ec103 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -324,6 +324,11 @@ class GlobalMenu(AbstractMenu[None]): output += f'{tr("Audio")}: {audio_config.audio.value}' output += '\n' + if app_config.print_service_config: + output += f'{tr("Print service")}: ' + output += tr('Enabled') if app_config.print_service_config.enabled else tr('Disabled') + output += '\n' + return output return None diff --git a/archinstall/lib/models/__init__.py b/archinstall/lib/models/__init__.py index 45d2b025..d742bc9f 100644 --- a/archinstall/lib/models/__init__.py +++ b/archinstall/lib/models/__init__.py @@ -1,9 +1,4 @@ -from .application import ( - ApplicationConfiguration, - Audio, - AudioConfiguration, - BluetoothConfiguration, -) +from .application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration from .bootloader import Bootloader from .device import ( BDevice, @@ -76,6 +71,7 @@ __all__ = [ 'PartitionTable', 'PartitionType', 'PasswordStrength', + 'PrintServiceConfiguration', 'ProfileConfiguration', 'Repository', 'SectorSize', diff --git a/archinstall/lib/models/application.py b/archinstall/lib/models/application.py index eeced898..f5f9e99d 100644 --- a/archinstall/lib/models/application.py +++ b/archinstall/lib/models/application.py @@ -17,9 +17,14 @@ class AudioConfigSerialization(TypedDict): audio: str +class PrintServiceConfigSerialization(TypedDict): + enabled: bool + + class ApplicationSerialization(TypedDict): bluetooth_config: NotRequired[BluetoothConfigSerialization] audio_config: NotRequired[AudioConfigSerialization] + print_service_config: NotRequired[PrintServiceConfigSerialization] @dataclass @@ -50,10 +55,23 @@ class BluetoothConfiguration: return BluetoothConfiguration(arg['enabled']) +@dataclass +class PrintServiceConfiguration: + enabled: bool + + def json(self) -> PrintServiceConfigSerialization: + return {'enabled': self.enabled} + + @staticmethod + def parse_arg(arg: dict[str, Any]) -> 'PrintServiceConfiguration': + return PrintServiceConfiguration(arg['enabled']) + + @dataclass class ApplicationConfiguration: bluetooth_config: BluetoothConfiguration | None = None audio_config: AudioConfiguration | None = None + print_service_config: PrintServiceConfiguration | None = None @staticmethod def parse_arg( @@ -72,6 +90,9 @@ class ApplicationConfiguration: if args and (audio_config := args.get('audio_config')) is not None: app_config.audio_config = AudioConfiguration.parse_arg(audio_config) + if args and (print_service_config := args.get('print_service_config')) is not None: + app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config) + return app_config def json(self) -> ApplicationSerialization: @@ -83,4 +104,7 @@ class ApplicationConfiguration: if self.audio_config: config['audio_config'] = self.audio_config.json() + if self.print_service_config: + config['print_service_config'] = self.print_service_config.json() + return config diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 67da11b2..11dc6e54 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -1779,6 +1779,12 @@ msgstr "" msgid "Would you like to configure Bluetooth?" msgstr "" +msgid "Print service" +msgstr "" + +msgid "Would you like to configure the print service?" +msgstr "" + msgid "Authentication" msgstr "" diff --git a/tests/data/test_config.json b/tests/data/test_config.json index a01c831b..618bd8e9 100644 --- a/tests/data/test_config.json +++ b/tests/data/test_config.json @@ -7,6 +7,9 @@ }, "audio_config": { "audio": "pipewire" + }, + "print_service_config": { + "enabled": true } }, "auth_config": { diff --git a/tests/test_args.py b/tests/test_args.py index 87ab1a3f..d3400c83 100644 --- a/tests/test_args.py +++ b/tests/test_args.py @@ -7,7 +7,7 @@ from pytest import MonkeyPatch from archinstall.default_profiles.profile import GreeterType from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments from archinstall.lib.hardware import GfxDriver -from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration +from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration from archinstall.lib.models.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType @@ -132,6 +132,7 @@ def test_config_file_parsing( app_config=ApplicationConfiguration( bluetooth_config=BluetoothConfiguration(enabled=True), audio_config=AudioConfiguration(audio=Audio.PIPEWIRE), + print_service_config=PrintServiceConfiguration(enabled=True), ), auth_config=AuthenticationConfiguration( root_enc_password=Password(enc_password='password_hash'),