feat(applications): add CUPS installation support (#4013)
* feat(applications): add CUPS installation support * fix: use translation for print service preview_action * fix: incorrect action for print service menu item * chore: refactor naming, printer -> print service * fix: commit untracked file * chore: fix formatting to make linter happy
This commit is contained in:
parent
cf31148e46
commit
d7b559c67e
|
|
@ -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)
|
||||||
|
|
@ -2,6 +2,7 @@ from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from archinstall.applications.audio import AudioApp
|
from archinstall.applications.audio import AudioApp
|
||||||
from archinstall.applications.bluetooth import BluetoothApp
|
from archinstall.applications.bluetooth import BluetoothApp
|
||||||
|
from archinstall.applications.print_service import PrintServiceApp
|
||||||
from archinstall.lib.models import Audio
|
from archinstall.lib.models import Audio
|
||||||
from archinstall.lib.models.application import ApplicationConfiguration
|
from archinstall.lib.models.application import ApplicationConfiguration
|
||||||
from archinstall.lib.models.users import User
|
from archinstall.lib.models.users import User
|
||||||
|
|
@ -25,5 +26,8 @@ class ApplicationHandler:
|
||||||
users,
|
users,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if app_config.print_service_config and app_config.print_service_config.enabled:
|
||||||
|
PrintServiceApp().install(install_session)
|
||||||
|
|
||||||
|
|
||||||
application_handler = ApplicationHandler()
|
application_handler = ApplicationHandler()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from typing import override
|
from typing import override
|
||||||
|
|
||||||
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
|
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.lib.translationhandler import tr
|
||||||
from archinstall.tui.curses_menu import SelectMenu
|
from archinstall.tui.curses_menu import SelectMenu
|
||||||
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
|
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
|
||||||
|
|
@ -48,6 +48,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
|
||||||
preview_action=self._prev_audio,
|
preview_action=self._prev_audio,
|
||||||
key='audio_config',
|
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:
|
def _prev_bluetooth(self, item: MenuItem) -> str | None:
|
||||||
|
|
@ -65,6 +71,15 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
|
||||||
return f'{tr("Audio")}: {config.audio.value}'
|
return f'{tr("Audio")}: {config.audio.value}'
|
||||||
return None
|
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:
|
def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
|
||||||
group = MenuItemGroup.yes_no()
|
group = MenuItemGroup.yes_no()
|
||||||
|
|
@ -94,6 +109,34 @@ def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfigur
|
||||||
raise ValueError('Unhandled result type')
|
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:
|
def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration | None:
|
||||||
items = [MenuItem(a.value, value=a) for a in Audio]
|
items = [MenuItem(a.value, value=a) for a in Audio]
|
||||||
group = MenuItemGroup(items)
|
group = MenuItemGroup(items)
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,11 @@ class GlobalMenu(AbstractMenu[None]):
|
||||||
output += f'{tr("Audio")}: {audio_config.audio.value}'
|
output += f'{tr("Audio")}: {audio_config.audio.value}'
|
||||||
output += '\n'
|
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 output
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
from .application import (
|
from .application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration
|
||||||
ApplicationConfiguration,
|
|
||||||
Audio,
|
|
||||||
AudioConfiguration,
|
|
||||||
BluetoothConfiguration,
|
|
||||||
)
|
|
||||||
from .bootloader import Bootloader
|
from .bootloader import Bootloader
|
||||||
from .device import (
|
from .device import (
|
||||||
BDevice,
|
BDevice,
|
||||||
|
|
@ -76,6 +71,7 @@ __all__ = [
|
||||||
'PartitionTable',
|
'PartitionTable',
|
||||||
'PartitionType',
|
'PartitionType',
|
||||||
'PasswordStrength',
|
'PasswordStrength',
|
||||||
|
'PrintServiceConfiguration',
|
||||||
'ProfileConfiguration',
|
'ProfileConfiguration',
|
||||||
'Repository',
|
'Repository',
|
||||||
'SectorSize',
|
'SectorSize',
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,14 @@ class AudioConfigSerialization(TypedDict):
|
||||||
audio: str
|
audio: str
|
||||||
|
|
||||||
|
|
||||||
|
class PrintServiceConfigSerialization(TypedDict):
|
||||||
|
enabled: bool
|
||||||
|
|
||||||
|
|
||||||
class ApplicationSerialization(TypedDict):
|
class ApplicationSerialization(TypedDict):
|
||||||
bluetooth_config: NotRequired[BluetoothConfigSerialization]
|
bluetooth_config: NotRequired[BluetoothConfigSerialization]
|
||||||
audio_config: NotRequired[AudioConfigSerialization]
|
audio_config: NotRequired[AudioConfigSerialization]
|
||||||
|
print_service_config: NotRequired[PrintServiceConfigSerialization]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -50,10 +55,23 @@ class BluetoothConfiguration:
|
||||||
return BluetoothConfiguration(arg['enabled'])
|
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
|
@dataclass
|
||||||
class ApplicationConfiguration:
|
class ApplicationConfiguration:
|
||||||
bluetooth_config: BluetoothConfiguration | None = None
|
bluetooth_config: BluetoothConfiguration | None = None
|
||||||
audio_config: AudioConfiguration | None = None
|
audio_config: AudioConfiguration | None = None
|
||||||
|
print_service_config: PrintServiceConfiguration | None = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_arg(
|
def parse_arg(
|
||||||
|
|
@ -72,6 +90,9 @@ class ApplicationConfiguration:
|
||||||
if args and (audio_config := args.get('audio_config')) is not None:
|
if args and (audio_config := args.get('audio_config')) is not None:
|
||||||
app_config.audio_config = AudioConfiguration.parse_arg(audio_config)
|
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
|
return app_config
|
||||||
|
|
||||||
def json(self) -> ApplicationSerialization:
|
def json(self) -> ApplicationSerialization:
|
||||||
|
|
@ -83,4 +104,7 @@ class ApplicationConfiguration:
|
||||||
if self.audio_config:
|
if self.audio_config:
|
||||||
config['audio_config'] = self.audio_config.json()
|
config['audio_config'] = self.audio_config.json()
|
||||||
|
|
||||||
|
if self.print_service_config:
|
||||||
|
config['print_service_config'] = self.print_service_config.json()
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
|
||||||
|
|
@ -1779,6 +1779,12 @@ msgstr ""
|
||||||
msgid "Would you like to configure Bluetooth?"
|
msgid "Would you like to configure Bluetooth?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Print service"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Would you like to configure the print service?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@
|
||||||
},
|
},
|
||||||
"audio_config": {
|
"audio_config": {
|
||||||
"audio": "pipewire"
|
"audio": "pipewire"
|
||||||
|
},
|
||||||
|
"print_service_config": {
|
||||||
|
"enabled": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auth_config": {
|
"auth_config": {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from pytest import MonkeyPatch
|
||||||
from archinstall.default_profiles.profile import GreeterType
|
from archinstall.default_profiles.profile import GreeterType
|
||||||
from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments
|
from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments
|
||||||
from archinstall.lib.hardware import GfxDriver
|
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.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod
|
||||||
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
|
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
|
||||||
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType
|
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType
|
||||||
|
|
@ -132,6 +132,7 @@ def test_config_file_parsing(
|
||||||
app_config=ApplicationConfiguration(
|
app_config=ApplicationConfiguration(
|
||||||
bluetooth_config=BluetoothConfiguration(enabled=True),
|
bluetooth_config=BluetoothConfiguration(enabled=True),
|
||||||
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
|
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
|
||||||
|
print_service_config=PrintServiceConfiguration(enabled=True),
|
||||||
),
|
),
|
||||||
auth_config=AuthenticationConfiguration(
|
auth_config=AuthenticationConfiguration(
|
||||||
root_enc_password=Password(enc_password='password_hash'),
|
root_enc_password=Password(enc_password='password_hash'),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue