Skip to content

Commit b2f4131

Browse files
authored
Allow granular plasma configuration (#4389)
* Flexible plasma profile selection * Update * Update * Update * Update
1 parent 101f647 commit b2f4131

File tree

10 files changed

+191
-70
lines changed

10 files changed

+191
-70
lines changed

archinstall/default_profiles/desktops/hyprland.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import override
22

33
from archinstall.default_profiles.desktops import SeatAccess
4-
from archinstall.default_profiles.profile import DisplayServerType, GreeterType, Profile, ProfileType
4+
from archinstall.default_profiles.profile import CustomSetting, DisplayServerType, GreeterType, Profile, ProfileType
55
from archinstall.lib.menu.helpers import Selection
66
from archinstall.lib.translationhandler import tr
77
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
@@ -17,7 +17,7 @@ def __init__(self) -> None:
1717
display_server=DisplayServerType.Wayland,
1818
)
1919

20-
self.custom_settings = {'seat_access': None}
20+
self.custom_settings = {CustomSetting.SeatAccess: None}
2121

2222
@property
2323
@override
@@ -45,7 +45,7 @@ def default_greeter_type(self) -> GreeterType:
4545
@property
4646
@override
4747
def services(self) -> list[str]:
48-
if pref := self.custom_settings.get('seat_access', None):
48+
if pref := self.custom_settings.get(CustomSetting.SeatAccess, None):
4949
return [pref]
5050
return []
5151

@@ -57,7 +57,7 @@ async def _select_seat_access(self) -> None:
5757
items = [MenuItem(s.value, value=s) for s in SeatAccess]
5858
group = MenuItemGroup(items, sort_items=True)
5959

60-
default = self.custom_settings.get('seat_access', None)
60+
default = self.custom_settings.get(CustomSetting.SeatAccess, None)
6161
group.set_default_by_value(default)
6262

6363
result = await Selection[SeatAccess](
@@ -67,7 +67,7 @@ async def _select_seat_access(self) -> None:
6767
).show()
6868

6969
if result.type_ == ResultType.Selection:
70-
self.custom_settings['seat_access'] = result.get_value().value
70+
self.custom_settings[CustomSetting.SeatAccess] = result.get_value().value
7171

7272
@override
7373
async def do_on_select(self) -> None:

archinstall/default_profiles/desktops/labwc.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import override
22

33
from archinstall.default_profiles.desktops import SeatAccess
4-
from archinstall.default_profiles.profile import DisplayServerType, GreeterType, Profile, ProfileType
4+
from archinstall.default_profiles.profile import CustomSetting, DisplayServerType, GreeterType, Profile, ProfileType
55
from archinstall.lib.menu.helpers import Selection
66
from archinstall.lib.translationhandler import tr
77
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
@@ -17,13 +17,13 @@ def __init__(self) -> None:
1717
display_server=DisplayServerType.Wayland,
1818
)
1919

20-
self.custom_settings = {'seat_access': None}
20+
self.custom_settings = {CustomSetting.SeatAccess: None}
2121

2222
@property
2323
@override
2424
def packages(self) -> list[str]:
2525
additional = []
26-
if seat := self.custom_settings.get('seat_access', None):
26+
if seat := self.custom_settings.get(CustomSetting.SeatAccess, None):
2727
additional = [seat]
2828

2929
return [
@@ -39,7 +39,7 @@ def default_greeter_type(self) -> GreeterType:
3939
@property
4040
@override
4141
def services(self) -> list[str]:
42-
if pref := self.custom_settings.get('seat_access', None):
42+
if pref := self.custom_settings.get(CustomSetting.SeatAccess, None):
4343
return [pref]
4444
return []
4545

@@ -51,7 +51,7 @@ async def _select_seat_access(self) -> None:
5151
items = [MenuItem(s.value, value=s) for s in SeatAccess]
5252
group = MenuItemGroup(items, sort_items=True)
5353

54-
default = self.custom_settings.get('seat_access', None)
54+
default = self.custom_settings.get(CustomSetting.SeatAccess, None)
5555
group.set_default_by_value(default)
5656

5757
result = await Selection[SeatAccess](
@@ -61,7 +61,7 @@ async def _select_seat_access(self) -> None:
6161
).show()
6262

6363
if result.type_ == ResultType.Selection:
64-
self.custom_settings['seat_access'] = result.get_value().value
64+
self.custom_settings[CustomSetting.SeatAccess] = result.get_value().value
6565

6666
@override
6767
async def do_on_select(self) -> None:

archinstall/default_profiles/desktops/niri.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import override
22

33
from archinstall.default_profiles.desktops import SeatAccess
4-
from archinstall.default_profiles.profile import DisplayServerType, GreeterType, Profile, ProfileType
4+
from archinstall.default_profiles.profile import CustomSetting, DisplayServerType, GreeterType, Profile, ProfileType
55
from archinstall.lib.menu.helpers import Selection
66
from archinstall.lib.translationhandler import tr
77
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
@@ -17,13 +17,13 @@ def __init__(self) -> None:
1717
display_server=DisplayServerType.Wayland,
1818
)
1919

20-
self.custom_settings = {'seat_access': None}
20+
self.custom_settings = {CustomSetting.SeatAccess: None}
2121

2222
@property
2323
@override
2424
def packages(self) -> list[str]:
2525
additional = []
26-
if seat := self.custom_settings.get('seat_access', None):
26+
if seat := self.custom_settings.get(CustomSetting.SeatAccess, None):
2727
additional = [seat]
2828

2929
return [
@@ -47,7 +47,7 @@ def default_greeter_type(self) -> GreeterType:
4747
@property
4848
@override
4949
def services(self) -> list[str]:
50-
if pref := self.custom_settings.get('seat_access', None):
50+
if pref := self.custom_settings.get(CustomSetting.SeatAccess, None):
5151
return [pref]
5252
return []
5353

@@ -59,7 +59,7 @@ async def _select_seat_access(self) -> None:
5959
items = [MenuItem(s.value, value=s) for s in SeatAccess]
6060
group = MenuItemGroup(items, sort_items=True)
6161

62-
default = self.custom_settings.get('seat_access', None)
62+
default = self.custom_settings.get(CustomSetting.SeatAccess, None)
6363
group.set_default_by_value(default)
6464

6565
result = await Selection[SeatAccess](
@@ -69,7 +69,7 @@ async def _select_seat_access(self) -> None:
6969
).show()
7070

7171
if result.type_ == ResultType.Selection:
72-
self.custom_settings['seat_access'] = result.get_value().value
72+
self.custom_settings[CustomSetting.SeatAccess] = result.get_value().value
7373

7474
@override
7575
async def do_on_select(self) -> None:
Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,67 @@
1+
from enum import StrEnum
12
from typing import override
23

3-
from archinstall.default_profiles.profile import DisplayServerType, GreeterType, Profile, ProfileType
4+
from archinstall.default_profiles.profile import CustomSetting, DisplayServerType, GreeterType, Profile, ProfileType
5+
from archinstall.lib.menu.helpers import Selection
6+
from archinstall.lib.packages.packages import available_package, package_group_info
7+
from archinstall.lib.translationhandler import tr
8+
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
9+
from archinstall.tui.ui.result import ResultType
10+
11+
12+
class PlasmaFlavor(StrEnum):
13+
Meta = 'plasma-meta'
14+
Plasma = 'plasma'
15+
Desktop = 'plasma-desktop'
16+
17+
def show(self) -> str:
18+
match self:
19+
case PlasmaFlavor.Meta:
20+
return f'{self.value} ({tr("Recommended")})'
21+
case PlasmaFlavor.Plasma | PlasmaFlavor.Desktop:
22+
return self.value
23+
24+
def package_details(self) -> str:
25+
ty = ''
26+
details = ''
27+
desc = ''
28+
29+
match self:
30+
case PlasmaFlavor.Meta:
31+
ty = tr('Package')
32+
desc = tr('Curated selection of KDE Plasma packages')
33+
info = available_package(self.value)
34+
35+
if info is not None:
36+
details = tr('Dependencies') + '\n'
37+
details += '\n'.join(f'- {entry}' for entry in info.get_depends_on)
38+
case PlasmaFlavor.Plasma:
39+
ty = tr('Package group')
40+
desc = tr('Extensive KDE Plasma installation')
41+
group = package_group_info(self.value)
42+
43+
if group is not None:
44+
details = tr('Packages in group') + '\n'
45+
details += '\n'.join(f'- {entry}' for entry in group.packages)
46+
case PlasmaFlavor.Desktop:
47+
ty = tr('Package group')
48+
desc = tr('Minimal KDE Plasma installation')
49+
info = available_package(self.value)
50+
51+
if info is not None:
52+
details = tr('Dependencies') + '\n'
53+
details += '\n'.join(f'- {entry}' for entry in info.get_depends_on)
54+
55+
return f'{tr("Type")}: {ty}\n{tr("Description")}: {desc}\n\n{details}'
56+
57+
def packages(self) -> list[str]:
58+
match self:
59+
case PlasmaFlavor.Meta:
60+
return ['plasma-meta']
61+
case PlasmaFlavor.Plasma:
62+
return ['plasma']
63+
case PlasmaFlavor.Desktop:
64+
return ['plasma-desktop']
465

566

667
class PlasmaProfile(Profile):
@@ -15,18 +76,45 @@ def __init__(self) -> None:
1576
@property
1677
@override
1778
def packages(self) -> list[str]:
18-
return [
19-
'plasma-desktop',
20-
'kscreen',
21-
'plasma-pa',
22-
'konsole',
23-
'kate',
24-
'dolphin',
25-
'ark',
26-
'plasma-workspace',
27-
]
79+
flavor_str = self.custom_settings.get(CustomSetting.PlasmaFlavor)
80+
81+
if flavor_str is not None:
82+
flavor = PlasmaFlavor(flavor_str)
83+
return flavor.packages()
84+
else:
85+
return PlasmaFlavor.Meta.packages() # use plasma-meta as the recommended default
2886

2987
@property
3088
@override
3189
def default_greeter_type(self) -> GreeterType:
3290
return GreeterType.PlasmaLoginManager
91+
92+
async def _select_flavor(self) -> None:
93+
header = tr('Select a flavor of KDE Plasma to install') + '\n'
94+
95+
items = [
96+
MenuItem(
97+
s.show(),
98+
value=s,
99+
preview_action=lambda x: x.value.package_details() if x.value else None,
100+
)
101+
for s in PlasmaFlavor
102+
]
103+
group = MenuItemGroup(items, sort_items=False)
104+
105+
default = self.custom_settings.get(CustomSetting.PlasmaFlavor, None)
106+
group.set_default_by_value(default)
107+
108+
result = await Selection[PlasmaFlavor](
109+
group,
110+
header=header,
111+
allow_skip=False,
112+
preview_location='right',
113+
).show()
114+
115+
if result.type_ == ResultType.Selection:
116+
self.custom_settings[CustomSetting.PlasmaFlavor] = result.get_value().value
117+
118+
@override
119+
async def do_on_select(self) -> None:
120+
await self._select_flavor()

archinstall/default_profiles/desktops/sway.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import override
22

33
from archinstall.default_profiles.desktops import SeatAccess
4-
from archinstall.default_profiles.profile import DisplayServerType, GreeterType, Profile, ProfileType
4+
from archinstall.default_profiles.profile import CustomSetting, DisplayServerType, GreeterType, Profile, ProfileType
55
from archinstall.lib.menu.helpers import Selection
66
from archinstall.lib.translationhandler import tr
77
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
@@ -17,13 +17,13 @@ def __init__(self) -> None:
1717
display_server=DisplayServerType.Wayland,
1818
)
1919

20-
self.custom_settings = {'seat_access': None}
20+
self.custom_settings = {CustomSetting.SeatAccess: None}
2121

2222
@property
2323
@override
2424
def packages(self) -> list[str]:
2525
additional = []
26-
if seat := self.custom_settings.get('seat_access', None):
26+
if seat := self.custom_settings.get(CustomSetting.SeatAccess, None):
2727
additional = [seat]
2828

2929
return [
@@ -49,7 +49,7 @@ def default_greeter_type(self) -> GreeterType:
4949
@property
5050
@override
5151
def services(self) -> list[str]:
52-
if pref := self.custom_settings.get('seat_access', None):
52+
if pref := self.custom_settings.get(CustomSetting.SeatAccess, None):
5353
return [pref]
5454
return []
5555

@@ -61,7 +61,7 @@ async def _select_seat_access(self) -> None:
6161
items = [MenuItem(s.value, value=s) for s in SeatAccess]
6262
group = MenuItemGroup(items, sort_items=True)
6363

64-
default = self.custom_settings.get('seat_access', None)
64+
default = self.custom_settings.get(CustomSetting.SeatAccess, None)
6565
group.set_default_by_value(default)
6666

6767
result = await Selection[SeatAccess](
@@ -71,7 +71,7 @@ async def _select_seat_access(self) -> None:
7171
).show()
7272

7373
if result.type_ == ResultType.Selection:
74-
self.custom_settings['seat_access'] = result.get_value().value
74+
self.custom_settings[CustomSetting.SeatAccess] = result.get_value().value
7575

7676
@override
7777
async def do_on_select(self) -> None:

archinstall/default_profiles/profile.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from enum import Enum, auto
1+
from enum import Enum, StrEnum, auto
22
from typing import TYPE_CHECKING, Self
33

44
from archinstall.lib.translationhandler import tr
@@ -45,6 +45,11 @@ class SelectResult(Enum):
4545
ResetCurrent = auto()
4646

4747

48+
class CustomSetting(StrEnum):
49+
SeatAccess = 'seat_access'
50+
PlasmaFlavor = 'plasma_flavor'
51+
52+
4853
class Profile:
4954
def __init__(
5055
self,
@@ -59,7 +64,7 @@ def __init__(
5964
) -> None:
6065
self.name = name
6166
self.profile_type = profile_type
62-
self.custom_settings: dict[str, str | None] = {}
67+
self.custom_settings: dict[CustomSetting, str | None] = {}
6368

6469
self._support_gfx_driver = support_gfx_driver
6570
self._support_greeter = support_greeter
@@ -128,7 +133,7 @@ async def do_on_select(self) -> SelectResult | None:
128133
"""
129134
return SelectResult.NewSelection
130135

131-
def set_custom_settings(self, settings: dict[str, str | None]) -> None:
136+
def set_custom_settings(self, settings: dict[CustomSetting, str | None]) -> None:
132137
"""
133138
Set the custom settings for the profile.
134139
This is also called when the settings are parsed from the config

archinstall/lib/models/packages.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,26 @@ def info(self) -> str:
142142

143143
return output
144144

145+
@cached_property
146+
def get_depends_on(self) -> list[str]:
147+
return [entry.strip() for entry in self.depends_on.split(' ') if entry.strip()]
148+
149+
@cached_property
150+
def get_optional_deps(self) -> list[str]:
151+
return [entry.strip() for entry in self.optional_deps.split(' ') if entry.strip()]
152+
145153

146154
@dataclass
147155
class PackageGroup:
148156
name: str
149157
packages: list[str] = field(default_factory=list)
150158

159+
@classmethod
160+
def from_package_group_output(cls, data: list[str]) -> Self:
161+
name = data[0].split()[0].strip()
162+
packages = [line.split()[1].strip() for line in data if line.strip()]
163+
return cls(name, packages)
164+
151165
@classmethod
152166
def from_available_packages(
153167
cls,

0 commit comments

Comments
 (0)