Move audio configuration to application config (#3612)

This commit is contained in:
Daniel Girtler 2025-06-20 07:27:23 +10:00 committed by GitHub
parent 63848f645f
commit 37b3985625
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 241 additions and 190 deletions

View File

@ -0,0 +1,80 @@
from typing import TYPE_CHECKING
from archinstall.lib.hardware import SysInfo
from archinstall.lib.models.application import Audio, AudioConfiguration
from archinstall.lib.models.users import User
from archinstall.lib.output import debug
if TYPE_CHECKING:
from archinstall.lib.installer import Installer
class AudioApp:
@property
def pulseaudio_packages(self) -> list[str]:
return [
'pulseaudio',
]
@property
def pipewire_packages(self) -> list[str]:
return [
'pipewire',
'pipewire-alsa',
'pipewire-jack',
'pipewire-pulse',
'gst-plugin-pipewire',
'libpulse',
'wireplumber',
]
def _enable_pipewire(
self,
install_session: 'Installer',
users: list['User'] | None = None,
) -> None:
if users is None:
return
for user in users:
# Create the full path for enabling the pipewire systemd items
service_dir = install_session.target / 'home' / user.username / '.config' / 'systemd' / 'user' / 'default.target.wants'
service_dir.mkdir(parents=True, exist_ok=True)
# Set ownership of the entire user catalogue
install_session.arch_chroot(f'chown -R {user.username}:{user.username} /home/{user.username}')
# symlink in the correct pipewire systemd items
install_session.arch_chroot(
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.service /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.service',
run_as=user.username,
)
install_session.arch_chroot(
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.socket /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.socket',
run_as=user.username,
)
def install(
self,
install_session: 'Installer',
audio_config: AudioConfiguration,
users: list[User] | None = None,
) -> None:
debug(f'Installing audio server: {audio_config.audio.value}')
if audio_config.audio == Audio.NO_AUDIO:
debug('No audio server selected, skipping installation.')
return
if SysInfo.requires_sof_fw():
install_session.add_additional_packages('sof-firmware')
if SysInfo.requires_alsa_fw():
install_session.add_additional_packages('alsa-firmware')
match audio_config.audio:
case Audio.PIPEWIRE:
install_session.add_additional_packages(self.pipewire_packages)
self._enable_pipewire(install_session, users)
case Audio.PULSEAUDIO:
install_session.add_additional_packages(self.pulseaudio_packages)

View File

@ -6,7 +6,7 @@ if TYPE_CHECKING:
from archinstall.lib.installer import Installer from archinstall.lib.installer import Installer
class Bluetooth: class BluetoothApp:
@property @property
def packages(self) -> list[str]: def packages(self) -> list[str]:
return [ return [

View File

@ -1,57 +0,0 @@
from typing import TYPE_CHECKING, override
from archinstall.default_profiles.profile import Profile, ProfileType
if TYPE_CHECKING:
from archinstall.lib.installer import Installer
from archinstall.lib.models.users import User
class PipewireProfile(Profile):
def __init__(self) -> None:
super().__init__('Pipewire', ProfileType.Application)
@property
@override
def packages(self) -> list[str]:
return [
'pipewire',
'pipewire-alsa',
'pipewire-jack',
'pipewire-pulse',
'gst-plugin-pipewire',
'libpulse',
'wireplumber',
]
def _enable_pipewire_for_all(self, install_session: 'Installer') -> None:
from archinstall.lib.args import arch_config_handler
users: list[User] | None = arch_config_handler.config.users
if users is None:
return
for user in users:
# Create the full path for enabling the pipewire systemd items
service_dir = install_session.target / 'home' / user.username / '.config' / 'systemd' / 'user' / 'default.target.wants'
service_dir.mkdir(parents=True, exist_ok=True)
# Set ownership of the entire user catalogue
install_session.arch_chroot(f'chown -R {user.username}:{user.username} /home/{user.username}')
# symlink in the correct pipewire systemd items
install_session.arch_chroot(
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.service /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.service',
run_as=user.username,
)
install_session.arch_chroot(
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.socket /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.socket',
run_as=user.username,
)
@override
def install(self, install_session: 'Installer') -> None:
super().install(install_session)
install_session.add_additional_packages(self.packages)
self._enable_pipewire_for_all(install_session)

View File

@ -1,7 +1,9 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from archinstall.applications.bluetooth import Bluetooth from archinstall.applications.audio import AudioApp
from archinstall.applications.bluetooth import BluetoothApp
from archinstall.lib.models.application import ApplicationConfiguration from archinstall.lib.models.application import ApplicationConfiguration
from archinstall.lib.models.users import User
if TYPE_CHECKING: if TYPE_CHECKING:
from archinstall.lib.installer import Installer from archinstall.lib.installer import Installer
@ -11,13 +13,16 @@ class ApplicationHandler:
def __init__(self) -> None: def __init__(self) -> None:
pass pass
def install_applications( def install_applications(self, install_session: 'Installer', app_config: ApplicationConfiguration, users: list['User'] | None = None) -> None:
self,
install_session: 'Installer',
app_config: ApplicationConfiguration,
) -> None:
if app_config.bluetooth_config: if app_config.bluetooth_config:
Bluetooth().install(install_session) BluetoothApp().install(install_session)
if app_config.audio_config:
AudioApp().install(
install_session,
app_config.audio_config,
users,
)
application_handler = ApplicationHandler() application_handler = ApplicationHandler()

View File

@ -1,11 +1,12 @@
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, BluetoothConfiguration from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration
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
from archinstall.tui.types import Alignment, Orientation from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties, Orientation
class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]): class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
@ -41,6 +42,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
preview_action=self._prev_bluetooth, preview_action=self._prev_bluetooth,
key='bluetooth_config', key='bluetooth_config',
), ),
MenuItem(
text=tr('Audio'),
action=select_audio,
preview_action=self._prev_audio,
key='audio_config',
),
] ]
def _prev_bluetooth(self, item: MenuItem) -> str | None: def _prev_bluetooth(self, item: MenuItem) -> str | None:
@ -52,6 +59,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
return output return output
return None return None
def _prev_audio(self, item: MenuItem) -> str | None:
if item.value is not None:
config: AudioConfiguration = item.value
return f'{tr("Audio")}: {config.audio.value}'
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()
@ -74,3 +87,26 @@ def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfigur
enabled = result.item() == MenuItem.yes() enabled = result.item() == MenuItem.yes()
return BluetoothConfiguration(enabled) return BluetoothConfiguration(enabled)
def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration | None:
items = [MenuItem(a.value, value=a) for a in Audio]
group = MenuItemGroup(items)
if preset:
group.set_focus_by_value(preset.audio)
result = SelectMenu[Audio](
group,
allow_skip=True,
alignment=Alignment.CENTER,
frame=FrameProperties.min(tr('Audio')),
).run()
match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return AudioConfiguration(audio=result.get_value())
case ResultType.Reset:
raise ValueError('Unhandled result type')

View File

@ -14,7 +14,6 @@ from pydantic.dataclasses import dataclass as p_dataclass
from archinstall.lib.crypt import decrypt from archinstall.lib.crypt import decrypt
from archinstall.lib.models.application import ApplicationConfiguration from archinstall.lib.models.application import ApplicationConfiguration
from archinstall.lib.models.audio_configuration import AudioConfiguration
from archinstall.lib.models.bootloader import Bootloader from archinstall.lib.models.bootloader import Bootloader
from archinstall.lib.models.device_model import DiskEncryption, DiskLayoutConfiguration from archinstall.lib.models.device_model import DiskEncryption, DiskLayoutConfiguration
from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.locale import LocaleConfiguration
@ -63,8 +62,7 @@ class ArchConfig:
network_config: NetworkConfiguration | None = None network_config: NetworkConfiguration | None = None
bootloader: Bootloader = field(default=Bootloader.get_default()) bootloader: Bootloader = field(default=Bootloader.get_default())
uki: bool = False uki: bool = False
audio_config: AudioConfiguration | None = None app_config: ApplicationConfiguration | None = None
application_config: ApplicationConfiguration | None = None
hostname: str = 'archlinux' hostname: str = 'archlinux'
kernels: list[str] = field(default_factory=lambda: ['linux']) kernels: list[str] = field(default_factory=lambda: ['linux'])
ntp: bool = True ntp: bool = True
@ -106,8 +104,7 @@ class ArchConfig:
'services': self.services, 'services': self.services,
'custom_commands': self.custom_commands, 'custom_commands': self.custom_commands,
'bootloader': self.bootloader.json(), 'bootloader': self.bootloader.json(),
'audio_config': self.audio_config.json() if self.audio_config else None, 'app_config': self.app_config.json() if self.app_config else None,
'app_config': self.application_config.json() if self.application_config else None,
} }
if self.locale_config: if self.locale_config:
@ -184,11 +181,12 @@ class ArchConfig:
if args_config.get('uki') and not arch_config.bootloader.has_uki_support(): if args_config.get('uki') and not arch_config.bootloader.has_uki_support():
arch_config.uki = False arch_config.uki = False
if audio_config := args_config.get('audio_config', None): # deprecated: backwards compatibility
arch_config.audio_config = AudioConfiguration.parse_arg(audio_config) audio_config_args = args_config.get('audio_config', None)
app_config_args = args_config.get('app_config', None)
if app_config := args_config.get('app_config', None): if audio_config_args is not None or app_config_args is not None:
arch_config.application_config = ApplicationConfiguration.parse_arg(app_config) arch_config.app_config = ApplicationConfiguration.parse_arg(app_config_args, audio_config_args)
if hostname := args_config.get('hostname', ''): if hostname := args_config.get('hostname', ''):
arch_config.hostname = hostname arch_config.hostname = hostname

View File

@ -16,7 +16,6 @@ from .interactions.general_conf import (
add_number_of_parallel_downloads, add_number_of_parallel_downloads,
ask_additional_packages_to_install, ask_additional_packages_to_install,
ask_for_a_timezone, ask_for_a_timezone,
ask_for_audio_selection,
ask_hostname, ask_hostname,
ask_ntp, ask_ntp,
) )
@ -26,7 +25,6 @@ from .interactions.system_conf import ask_for_bootloader, ask_for_swap, ask_for_
from .locale.locale_menu import LocaleMenu from .locale.locale_menu import LocaleMenu
from .menu.abstract_menu import CONFIG_KEY, AbstractMenu from .menu.abstract_menu import CONFIG_KEY, AbstractMenu
from .mirrors import MirrorMenu from .mirrors import MirrorMenu
from .models.audio_configuration import AudioConfiguration
from .models.bootloader import Bootloader from .models.bootloader import Bootloader
from .models.locale import LocaleConfiguration from .models.locale import LocaleConfiguration
from .models.mirrors import MirrorConfiguration from .models.mirrors import MirrorConfiguration
@ -128,12 +126,6 @@ class GlobalMenu(AbstractMenu[None]):
preview_action=self._prev_profile, preview_action=self._prev_profile,
key='profile_config', key='profile_config',
), ),
MenuItem(
text=tr('Audio'),
action=ask_for_audio_selection,
preview_action=self._prev_audio,
key='audio_config',
),
MenuItem( MenuItem(
text=tr('Applications'), text=tr('Applications'),
action=self._select_applications, action=self._select_applications,
@ -311,7 +303,13 @@ class GlobalMenu(AbstractMenu[None]):
if app_config.bluetooth_config: if app_config.bluetooth_config:
output += f'{tr("Bluetooth")}: ' output += f'{tr("Bluetooth")}: '
output += tr('Enabled') if app_config.bluetooth_config.enabled else tr('Disabled') + '\n' output += tr('Enabled') if app_config.bluetooth_config.enabled else tr('Disabled')
output += '\n'
if app_config.audio_config:
audio_config = app_config.audio_config
output += f'{tr("Audio")}: {audio_config.audio.value}'
output += '\n'
return output return output
@ -378,12 +376,6 @@ class GlobalMenu(AbstractMenu[None]):
return f'{tr("Root password")}: {password.hidden()}' return f'{tr("Root password")}: {password.hidden()}'
return None return None
def _prev_audio(self, item: MenuItem) -> str | None:
if item.value is not None:
config: AudioConfiguration = item.value
return f'{tr("Audio")}: {config.audio.value}'
return None
def _prev_parallel_dw(self, item: MenuItem) -> str | None: def _prev_parallel_dw(self, item: MenuItem) -> str | None:
if item.value is not None: if item.value is not None:
return f'{tr("Parallel Downloads")}: {item.value}' return f'{tr("Parallel Downloads")}: {item.value}'

View File

@ -10,7 +10,6 @@ from .general_conf import (
add_number_of_parallel_downloads, add_number_of_parallel_downloads,
ask_additional_packages_to_install, ask_additional_packages_to_install,
ask_for_a_timezone, ask_for_a_timezone,
ask_for_audio_selection,
ask_hostname, ask_hostname,
ask_ntp, ask_ntp,
select_archinstall_language, select_archinstall_language,
@ -26,7 +25,6 @@ __all__ = [
'ask_additional_packages_to_install', 'ask_additional_packages_to_install',
'ask_for_a_timezone', 'ask_for_a_timezone',
'ask_for_additional_users', 'ask_for_additional_users',
'ask_for_audio_selection',
'ask_for_bootloader', 'ask_for_bootloader',
'ask_for_swap', 'ask_for_swap',
'ask_for_uki', 'ask_for_uki',

View File

@ -13,7 +13,6 @@ from archinstall.tui.result import ResultType
from archinstall.tui.types import Alignment, FrameProperties, Orientation, PreviewStyle from archinstall.tui.types import Alignment, FrameProperties, Orientation, PreviewStyle
from ..locale.utils import list_timezones from ..locale.utils import list_timezones
from ..models.audio_configuration import Audio, AudioConfiguration
from ..models.packages import AvailablePackage, PackageGroup from ..models.packages import AvailablePackage, PackageGroup
from ..output import warn from ..output import warn
from ..translationhandler import Language from ..translationhandler import Language
@ -102,29 +101,6 @@ def ask_for_a_timezone(preset: str | None = None) -> str | None:
return result.get_value() return result.get_value()
def ask_for_audio_selection(preset: AudioConfiguration | None = None) -> AudioConfiguration | None:
items = [MenuItem(a.value, value=a) for a in Audio]
group = MenuItemGroup(items)
if preset:
group.set_focus_by_value(preset.audio)
result = SelectMenu[Audio](
group,
allow_skip=True,
alignment=Alignment.CENTER,
frame=FrameProperties.min(tr('Audio')),
).run()
match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return AudioConfiguration(audio=result.get_value())
case ResultType.Reset:
raise ValueError('Unhandled result type')
def select_language(preset: str | None = None) -> str | None: def select_language(preset: str | None = None) -> str | None:
from ..locale.locale_menu import select_kb_layout from ..locale.locale_menu import select_kb_layout

View File

@ -1,4 +1,9 @@
from .audio_configuration import Audio, AudioConfiguration from .application import (
ApplicationConfiguration,
Audio,
AudioConfiguration,
BluetoothConfiguration,
)
from .bootloader import Bootloader from .bootloader import Bootloader
from .device_model import ( from .device_model import (
BDevice, BDevice,
@ -35,9 +40,11 @@ from .profile_model import ProfileConfiguration
from .users import PasswordStrength, User from .users import PasswordStrength, User
__all__ = [ __all__ = [
'ApplicationConfiguration',
'Audio', 'Audio',
'AudioConfiguration', 'AudioConfiguration',
'BDevice', 'BDevice',
'BluetoothConfiguration',
'Bootloader', 'Bootloader',
'CustomRepository', 'CustomRepository',
'DeviceGeometry', 'DeviceGeometry',

View File

@ -1,13 +1,41 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import NotRequired, TypedDict from enum import StrEnum, auto
from typing import Any, NotRequired, TypedDict
class BluetoothConfigSerialization(TypedDict): class BluetoothConfigSerialization(TypedDict):
enabled: bool enabled: bool
class Audio(StrEnum):
NO_AUDIO = 'No audio server'
PIPEWIRE = auto()
PULSEAUDIO = auto()
class AudioConfigSerialization(TypedDict):
audio: str
class ApplicationSerialization(TypedDict): class ApplicationSerialization(TypedDict):
bluetooth_config: NotRequired[BluetoothConfigSerialization] bluetooth_config: NotRequired[BluetoothConfigSerialization]
audio_config: NotRequired[AudioConfigSerialization]
@dataclass
class AudioConfiguration:
audio: Audio
def json(self) -> AudioConfigSerialization:
return {
'audio': self.audio.value,
}
@staticmethod
def parse_arg(arg: dict[str, Any]) -> 'AudioConfiguration':
return AudioConfiguration(
Audio(arg['audio']),
)
@dataclass @dataclass
@ -18,23 +46,33 @@ class BluetoothConfiguration:
return {'enabled': self.enabled} return {'enabled': self.enabled}
@staticmethod @staticmethod
def parse_arg(arg: BluetoothConfigSerialization) -> 'BluetoothConfiguration': def parse_arg(arg: dict[str, Any]) -> 'BluetoothConfiguration':
return BluetoothConfiguration(arg['enabled']) return BluetoothConfiguration(arg['enabled'])
@dataclass @dataclass
class ApplicationConfiguration: class ApplicationConfiguration:
bluetooth_config: BluetoothConfiguration | None = None bluetooth_config: BluetoothConfiguration | None = None
audio_config: AudioConfiguration | None = None
@staticmethod @staticmethod
def parse_arg(args: ApplicationSerialization) -> 'ApplicationConfiguration': def parse_arg(
bluetooth_config: BluetoothConfiguration | None = None args: dict[str, Any] | None = None,
if 'bluetooth_config' in args: old_audio_config: dict[str, Any] | None = None,
bluetooth_config = BluetoothConfiguration.parse_arg(args['bluetooth_config']) ) -> 'ApplicationConfiguration':
app_config = ApplicationConfiguration()
return ApplicationConfiguration( if args and (bluetooth_config := args.get('bluetooth_config')) is not None:
bluetooth_config=bluetooth_config, app_config.bluetooth_config = BluetoothConfiguration.parse_arg(bluetooth_config)
)
# deprecated: backwards compatibility
if old_audio_config is not None:
app_config.audio_config = AudioConfiguration.parse_arg(old_audio_config)
if args and (audio_config := args.get('audio_config')) is not None:
app_config.audio_config = AudioConfiguration.parse_arg(audio_config)
return app_config
def json(self) -> ApplicationSerialization: def json(self) -> ApplicationSerialization:
config: ApplicationSerialization = {} config: ApplicationSerialization = {}
@ -42,4 +80,7 @@ class ApplicationConfiguration:
if self.bluetooth_config: if self.bluetooth_config:
config['bluetooth_config'] = self.bluetooth_config.json() config['bluetooth_config'] = self.bluetooth_config.json()
if self.audio_config:
config['audio_config'] = self.audio_config.json()
return config return config

View File

@ -1,52 +0,0 @@
from dataclasses import dataclass
from enum import StrEnum, auto
from typing import TYPE_CHECKING
from ..hardware import SysInfo
from ..output import info
if TYPE_CHECKING:
from archinstall.lib.installer import Installer
class Audio(StrEnum):
NO_AUDIO = 'No audio server'
PIPEWIRE = auto()
PULSEAUDIO = auto()
@dataclass
class AudioConfiguration:
audio: Audio
def json(self) -> dict[str, str]:
return {
'audio': self.audio.value,
}
@staticmethod
def parse_arg(arg: dict[str, str]) -> 'AudioConfiguration':
return AudioConfiguration(
Audio(arg['audio']),
)
def install_audio_config(
self,
installation: 'Installer',
) -> None:
info(f'Installing audio server: {self.audio.name}')
from ...default_profiles.applications.pipewire import PipewireProfile
match self.audio:
case Audio.PIPEWIRE:
PipewireProfile().install(installation)
case Audio.PULSEAUDIO:
installation.add_additional_packages('pulseaudio')
if self.audio != Audio.NO_AUDIO:
if SysInfo.requires_sof_fw():
installation.add_additional_packages('sof-firmware')
if SysInfo.requires_alsa_fw():
installation.add_additional_packages('alsa-firmware')

View File

@ -116,19 +116,13 @@ def perform_installation(mountpoint: Path) -> None:
if users := config.users: if users := config.users:
installation.create_users(users) installation.create_users(users)
audio_config = config.audio_config
if audio_config:
audio_config.install_audio_config(installation)
else:
info('No audio server will be installed')
if config.packages and config.packages[0] != '': if config.packages and config.packages[0] != '':
installation.add_additional_packages(config.packages) installation.add_additional_packages(config.packages)
if profile_config := config.profile_config: if profile_config := config.profile_config:
profile_handler.install_profile_config(installation, profile_config) profile_handler.install_profile_config(installation, profile_config)
if app_config := config.application_config: if app_config := config.app_config:
application_handler.install_applications(installation, app_config) application_handler.install_applications(installation, app_config)
if timezone := config.timezone: if timezone := config.timezone:

View File

@ -33,6 +33,11 @@ def deprecated_mirror_config() -> Path:
return Path(__file__).parent / 'data' / 'test_deprecated_mirror_config.json' return Path(__file__).parent / 'data' / 'test_deprecated_mirror_config.json'
@pytest.fixture(scope='session')
def deprecated_audio_config() -> Path:
return Path(__file__).parent / 'data' / 'test_deprecated_audio_config.json'
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def mirrorlist_no_country_fixture() -> Path: def mirrorlist_no_country_fixture() -> Path:
return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_no_country' return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_no_country'

View File

@ -3,6 +3,9 @@
"app_config": { "app_config": {
"bluetooth_config": { "bluetooth_config": {
"enabled": true "enabled": true
},
"audio_config": {
"audio": "pipewire"
} }
}, },
"audio_config": { "audio_config": {

View File

@ -0,0 +1,5 @@
{
"audio_config": {
"audio": "pipewire"
}
}

View File

@ -6,8 +6,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, BluetoothConfiguration from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration
from archinstall.lib.models.audio_configuration import Audio, AudioConfiguration
from archinstall.lib.models.bootloader import Bootloader from archinstall.lib.models.bootloader import Bootloader
from archinstall.lib.models.device_model import DiskLayoutConfiguration, DiskLayoutType from archinstall.lib.models.device_model import DiskLayoutConfiguration, DiskLayoutType
from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.locale import LocaleConfiguration
@ -128,8 +127,9 @@ def test_config_file_parsing(
assert arch_config == ArchConfig( assert arch_config == ArchConfig(
version='3.0.2', version='3.0.2',
application_config=ApplicationConfiguration( app_config=ApplicationConfiguration(
bluetooth_config=BluetoothConfiguration(enabled=True), bluetooth_config=BluetoothConfiguration(enabled=True),
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
), ),
locale_config=LocaleConfiguration( locale_config=LocaleConfiguration(
kb_layout='us', kb_layout='us',
@ -199,7 +199,6 @@ def test_config_file_parsing(
), ),
bootloader=Bootloader.Systemd, bootloader=Bootloader.Systemd,
uki=False, uki=False,
audio_config=AudioConfiguration(Audio.PIPEWIRE),
hostname='archy', hostname='archy',
kernels=['linux-zen'], kernels=['linux-zen'],
ntp=True, ntp=True,
@ -285,6 +284,27 @@ def test_deprecated_creds_config_parsing(
] ]
def test_deprecated_audio_config_parsing(
monkeypatch: MonkeyPatch,
deprecated_audio_config: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--config',
str(deprecated_audio_config),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.app_config == ApplicationConfiguration(
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
)
def test_encrypted_creds_with_arg( def test_encrypted_creds_with_arg(
monkeypatch: MonkeyPatch, monkeypatch: MonkeyPatch,
encrypted_creds_fixture: Path, encrypted_creds_fixture: Path,