Skip to content

Commit 1419adf

Browse files
committed
Merge remote-tracking branch 'origin/master' into fix-3598
2 parents c3de44d + 37b3985 commit 1419adf

24 files changed

Lines changed: 607 additions & 391 deletions

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
default_stages: ['pre-commit']
22
repos:
33
- repo: https://github.com/astral-sh/ruff-pre-commit
4-
rev: v0.11.13
4+
rev: v0.12.0
55
hooks:
66
# fix unused imports and sort them
77
- id: ruff
@@ -31,7 +31,7 @@ repos:
3131
args: [--config=.flake8]
3232
fail_fast: true
3333
- repo: https://github.com/pre-commit/mirrors-mypy
34-
rev: v1.16.0
34+
rev: v1.16.1
3535
hooks:
3636
- id: mypy
3737
args: [

archinstall/applications/audio.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from typing import TYPE_CHECKING
2+
3+
from archinstall.lib.hardware import SysInfo
4+
from archinstall.lib.models.application import Audio, AudioConfiguration
5+
from archinstall.lib.models.users import User
6+
from archinstall.lib.output import debug
7+
8+
if TYPE_CHECKING:
9+
from archinstall.lib.installer import Installer
10+
11+
12+
class AudioApp:
13+
@property
14+
def pulseaudio_packages(self) -> list[str]:
15+
return [
16+
'pulseaudio',
17+
]
18+
19+
@property
20+
def pipewire_packages(self) -> list[str]:
21+
return [
22+
'pipewire',
23+
'pipewire-alsa',
24+
'pipewire-jack',
25+
'pipewire-pulse',
26+
'gst-plugin-pipewire',
27+
'libpulse',
28+
'wireplumber',
29+
]
30+
31+
def _enable_pipewire(
32+
self,
33+
install_session: 'Installer',
34+
users: list['User'] | None = None,
35+
) -> None:
36+
if users is None:
37+
return
38+
39+
for user in users:
40+
# Create the full path for enabling the pipewire systemd items
41+
service_dir = install_session.target / 'home' / user.username / '.config' / 'systemd' / 'user' / 'default.target.wants'
42+
service_dir.mkdir(parents=True, exist_ok=True)
43+
44+
# Set ownership of the entire user catalogue
45+
install_session.arch_chroot(f'chown -R {user.username}:{user.username} /home/{user.username}')
46+
47+
# symlink in the correct pipewire systemd items
48+
install_session.arch_chroot(
49+
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.service /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.service',
50+
run_as=user.username,
51+
)
52+
install_session.arch_chroot(
53+
f'ln -sf /usr/lib/systemd/user/pipewire-pulse.socket /home/{user.username}/.config/systemd/user/default.target.wants/pipewire-pulse.socket',
54+
run_as=user.username,
55+
)
56+
57+
def install(
58+
self,
59+
install_session: 'Installer',
60+
audio_config: AudioConfiguration,
61+
users: list[User] | None = None,
62+
) -> None:
63+
debug(f'Installing audio server: {audio_config.audio.value}')
64+
65+
if audio_config.audio == Audio.NO_AUDIO:
66+
debug('No audio server selected, skipping installation.')
67+
return
68+
69+
if SysInfo.requires_sof_fw():
70+
install_session.add_additional_packages('sof-firmware')
71+
72+
if SysInfo.requires_alsa_fw():
73+
install_session.add_additional_packages('alsa-firmware')
74+
75+
match audio_config.audio:
76+
case Audio.PIPEWIRE:
77+
install_session.add_additional_packages(self.pipewire_packages)
78+
self._enable_pipewire(install_session, users)
79+
case Audio.PULSEAUDIO:
80+
install_session.add_additional_packages(self.pulseaudio_packages)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import TYPE_CHECKING
2+
3+
from archinstall.lib.output import debug
4+
5+
if TYPE_CHECKING:
6+
from archinstall.lib.installer import Installer
7+
8+
9+
class BluetoothApp:
10+
@property
11+
def packages(self) -> list[str]:
12+
return [
13+
'bluez',
14+
'bluez-utils',
15+
]
16+
17+
@property
18+
def services(self) -> list[str]:
19+
return [
20+
'bluetooth.service',
21+
]
22+
23+
def install(self, install_session: 'Installer') -> None:
24+
debug('Installing Bluetooth')
25+
install_session.add_additional_packages(self.packages)
26+
install_session.enable_service(self.services)

archinstall/default_profiles/applications/pipewire.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

archinstall/default_profiles/desktops/cinnamon.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ def packages(self) -> list[str]:
1616
'system-config-printer',
1717
'gnome-keyring',
1818
'gnome-terminal',
19-
'blueman',
20-
'bluez-utils',
2119
'engrampa',
2220
'gnome-screenshot',
2321
'gvfs-smb',
File renamed without changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import TYPE_CHECKING
2+
3+
from archinstall.applications.audio import AudioApp
4+
from archinstall.applications.bluetooth import BluetoothApp
5+
from archinstall.lib.models.application import ApplicationConfiguration
6+
from archinstall.lib.models.users import User
7+
8+
if TYPE_CHECKING:
9+
from archinstall.lib.installer import Installer
10+
11+
12+
class ApplicationHandler:
13+
def __init__(self) -> None:
14+
pass
15+
16+
def install_applications(self, install_session: 'Installer', app_config: ApplicationConfiguration, users: list['User'] | None = None) -> None:
17+
if app_config.bluetooth_config:
18+
BluetoothApp().install(install_session)
19+
20+
if app_config.audio_config:
21+
AudioApp().install(
22+
install_session,
23+
app_config.audio_config,
24+
users,
25+
)
26+
27+
28+
application_handler = ApplicationHandler()
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from typing import override
2+
3+
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
4+
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration
5+
from archinstall.lib.translationhandler import tr
6+
from archinstall.tui.curses_menu import SelectMenu
7+
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
8+
from archinstall.tui.result import ResultType
9+
from archinstall.tui.types import Alignment, FrameProperties, Orientation
10+
11+
12+
class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
13+
def __init__(
14+
self,
15+
preset: ApplicationConfiguration | None = None,
16+
):
17+
if preset:
18+
self._app_config = preset
19+
else:
20+
self._app_config = ApplicationConfiguration()
21+
22+
menu_optioons = self._define_menu_options()
23+
self._item_group = MenuItemGroup(menu_optioons, checkmarks=True)
24+
25+
super().__init__(
26+
self._item_group,
27+
config=self._app_config,
28+
allow_reset=True,
29+
)
30+
31+
@override
32+
def run(self, additional_title: str | None = None) -> ApplicationConfiguration:
33+
super().run(additional_title=additional_title)
34+
return self._app_config
35+
36+
def _define_menu_options(self) -> list[MenuItem]:
37+
return [
38+
MenuItem(
39+
text=tr('Bluetooth'),
40+
action=select_bluetooth,
41+
value=self._app_config.bluetooth_config,
42+
preview_action=self._prev_bluetooth,
43+
key='bluetooth_config',
44+
),
45+
MenuItem(
46+
text=tr('Audio'),
47+
action=select_audio,
48+
preview_action=self._prev_audio,
49+
key='audio_config',
50+
),
51+
]
52+
53+
def _prev_bluetooth(self, item: MenuItem) -> str | None:
54+
if item.value is not None:
55+
bluetooth_config: BluetoothConfiguration = item.value
56+
57+
output = 'Bluetooth: '
58+
output += tr('Enabled') if bluetooth_config.enabled else tr('Disabled')
59+
return output
60+
return None
61+
62+
def _prev_audio(self, item: MenuItem) -> str | None:
63+
if item.value is not None:
64+
config: AudioConfiguration = item.value
65+
return f'{tr("Audio")}: {config.audio.value}'
66+
return None
67+
68+
69+
def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
70+
group = MenuItemGroup.yes_no()
71+
group.focus_item = MenuItem.no()
72+
73+
if preset is not None:
74+
group.set_selected_by_value(preset.enabled)
75+
76+
header = tr('Would you like to configure Bluetooth?') + '\n'
77+
78+
result = SelectMenu[bool](
79+
group,
80+
header=header,
81+
alignment=Alignment.CENTER,
82+
columns=2,
83+
orientation=Orientation.HORIZONTAL,
84+
allow_skip=True,
85+
).run()
86+
87+
enabled = result.item() == MenuItem.yes()
88+
89+
return BluetoothConfiguration(enabled)
90+
91+
92+
def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration | None:
93+
items = [MenuItem(a.value, value=a) for a in Audio]
94+
group = MenuItemGroup(items)
95+
96+
if preset:
97+
group.set_focus_by_value(preset.audio)
98+
99+
result = SelectMenu[Audio](
100+
group,
101+
allow_skip=True,
102+
alignment=Alignment.CENTER,
103+
frame=FrameProperties.min(tr('Audio')),
104+
).run()
105+
106+
match result.type_:
107+
case ResultType.Skip:
108+
return preset
109+
case ResultType.Selection:
110+
return AudioConfiguration(audio=result.get_value())
111+
case ResultType.Reset:
112+
raise ValueError('Unhandled result type')

archinstall/lib/args.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from pydantic.dataclasses import dataclass as p_dataclass
1414

1515
from archinstall.lib.crypt import decrypt
16-
from archinstall.lib.models.audio_configuration import AudioConfiguration
16+
from archinstall.lib.models.application import ApplicationConfiguration
1717
from archinstall.lib.models.bootloader import Bootloader
1818
from archinstall.lib.models.device_model import DiskEncryption, DiskLayoutConfiguration
1919
from archinstall.lib.models.locale import LocaleConfiguration
@@ -63,7 +63,7 @@ class ArchConfig:
6363
network_config: NetworkConfiguration | None = None
6464
bootloader: Bootloader = field(default=Bootloader.get_default())
6565
uki: bool = False
66-
audio_config: AudioConfiguration | None = None
66+
app_config: ApplicationConfiguration | None = None
6767
hostname: str = 'archlinux'
6868
kernels: list[str] = field(default_factory=lambda: ['linux'])
6969
ntp: bool = True
@@ -106,7 +106,7 @@ def safe_json(self) -> dict[str, Any]:
106106
'services': self.services,
107107
'custom_commands': self.custom_commands,
108108
'bootloader': self.bootloader.json(),
109-
'audio_config': self.audio_config.json() if self.audio_config else None,
109+
'app_config': self.app_config.json() if self.app_config else None,
110110
}
111111

112112
if self.locale_config:
@@ -186,8 +186,12 @@ def from_config(cls, args_config: dict[str, Any]) -> 'ArchConfig':
186186
if args_config.get('uki') and not arch_config.bootloader.has_uki_support():
187187
arch_config.uki = False
188188

189-
if audio_config := args_config.get('audio_config', None):
190-
arch_config.audio_config = AudioConfiguration.parse_arg(audio_config)
189+
# deprecated: backwards compatibility
190+
audio_config_args = args_config.get('audio_config', None)
191+
app_config_args = args_config.get('app_config', None)
192+
193+
if audio_config_args is not None or app_config_args is not None:
194+
arch_config.app_config = ApplicationConfiguration.parse_arg(app_config_args, audio_config_args)
191195

192196
if hostname := args_config.get('hostname', ''):
193197
arch_config.hostname = hostname

0 commit comments

Comments
 (0)