Skip to content

Commit cb78e22

Browse files
authored
Merge branch 'archlinux:master' into master
2 parents 79e5283 + 450664c commit cb78e22

12 files changed

Lines changed: 211 additions & 106 deletions

File tree

.pre-commit-config.yaml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,9 @@ repos:
4444
- pytest-mock
4545
- cryptography
4646
- textual
47-
- repo: local
47+
- repo: https://github.com/pycqa/pylint
48+
rev: v4.0.4
4849
hooks:
49-
- id: pylint
50-
name: pylint
51-
entry: pylint
52-
language: system
53-
types: [python]
54-
fail_fast: true
55-
require_serial: true
50+
- id: pylint
51+
fail_fast: true
52+
require_serial: true

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ archinstall
3535
## Running the [guided](https://github.com/archlinux/archinstall/blob/master/archinstall/scripts/guided.py) installer using `git`
3636

3737
```shell
38-
# cd archinstall-git
38+
# git clone https://github.com/archlinux/archinstall
39+
# cd archinstall
3940
# python -m archinstall $@
4041
```
4142

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import TYPE_CHECKING
2+
3+
from archinstall.lib.models.application import Firewall, FirewallConfiguration
4+
from archinstall.lib.output import debug
5+
6+
if TYPE_CHECKING:
7+
from archinstall.lib.installer import Installer
8+
9+
10+
class FirewallApp:
11+
@property
12+
def ufw_packages(self) -> list[str]:
13+
return [
14+
'ufw',
15+
]
16+
17+
@property
18+
def ufw_services(self) -> list[str]:
19+
return [
20+
'ufw.service',
21+
]
22+
23+
def install(
24+
self,
25+
install_session: 'Installer',
26+
firewall_config: FirewallConfiguration,
27+
) -> None:
28+
debug(f'Installing firewall: {firewall_config.firewall.value}')
29+
30+
match firewall_config.firewall:
31+
case Firewall.UFW:
32+
install_session.add_additional_packages(self.ufw_packages)
33+
install_session.enable_service(self.ufw_services)

archinstall/default_profiles/desktops/plasma.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def __init__(self) -> None:
1212
@override
1313
def packages(self) -> list[str]:
1414
return [
15-
'plasma-meta',
15+
'plasma-desktop',
1616
'konsole',
1717
'kate',
1818
'dolphin',

archinstall/lib/applications/application_handler.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from archinstall.applications.audio import AudioApp
44
from archinstall.applications.bluetooth import BluetoothApp
5+
from archinstall.applications.firewall import FirewallApp
56
from archinstall.applications.power_management import PowerManagementApp
67
from archinstall.applications.print_service import PrintServiceApp
78
from archinstall.lib.models import Audio
@@ -36,5 +37,11 @@ def install_applications(self, install_session: 'Installer', app_config: Applica
3637
if app_config.print_service_config and app_config.print_service_config.enabled:
3738
PrintServiceApp().install(install_session)
3839

40+
if app_config.firewall_config:
41+
FirewallApp().install(
42+
install_session,
43+
app_config.firewall_config,
44+
)
45+
3946

4047
application_handler = ApplicationHandler()

archinstall/lib/applications/application_menu.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
Audio,
88
AudioConfiguration,
99
BluetoothConfiguration,
10+
Firewall,
11+
FirewallConfiguration,
1012
PowerManagement,
1113
PowerManagementConfiguration,
1214
PrintServiceConfiguration,
@@ -70,6 +72,12 @@ def _define_menu_options(self) -> list[MenuItem]:
7072
enabled=SysInfo.has_battery(),
7173
key='power_management_config',
7274
),
75+
MenuItem(
76+
text=tr('Firewall'),
77+
action=select_firewall,
78+
preview_action=self._prev_firewall,
79+
key='firewall_config',
80+
),
7381
]
7482

7583
def _prev_power_management(self, item: MenuItem) -> str | None:
@@ -102,6 +110,12 @@ def _prev_print_service(self, item: MenuItem) -> str | None:
102110
return output
103111
return None
104112

113+
def _prev_firewall(self, item: MenuItem) -> str | None:
114+
if item.value is not None:
115+
config: FirewallConfiguration = item.value
116+
return f'{tr("Firewall")}: {config.firewall.value}'
117+
return None
118+
105119

106120
def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None:
107121
group = MenuItemGroup.from_enum(PowerManagement)
@@ -203,3 +217,26 @@ def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration
203217
return AudioConfiguration(audio=result.get_value())
204218
case ResultType.Reset:
205219
raise ValueError('Unhandled result type')
220+
221+
222+
def select_firewall(preset: FirewallConfiguration | None = None) -> FirewallConfiguration | None:
223+
group = MenuItemGroup.from_enum(Firewall)
224+
225+
if preset:
226+
group.set_focus_by_value(preset.firewall)
227+
228+
result = SelectMenu[Firewall](
229+
group,
230+
allow_skip=True,
231+
alignment=Alignment.CENTER,
232+
allow_reset=True,
233+
frame=FrameProperties.min(tr('Firewall')),
234+
).run()
235+
236+
match result.type_:
237+
case ResultType.Skip:
238+
return preset
239+
case ResultType.Selection:
240+
return FirewallConfiguration(firewall=result.get_value())
241+
case ResultType.Reset:
242+
return None

archinstall/lib/installer.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,14 @@ def _mount_partition(self, part_mod: PartitionModification) -> None:
364364
target = self.target / part_mod.relative_mountpoint
365365
device_handler.mount(part_mod.dev_path, target, options=part_mod.mount_options)
366366
elif part_mod.fs_type == FilesystemType.Btrfs:
367-
self._mount_btrfs_subvol(
368-
part_mod.dev_path,
369-
part_mod.btrfs_subvols,
370-
part_mod.mount_options,
371-
)
367+
# Only mount BTRFS subvolumes that have mountpoints specified
368+
subvols_with_mountpoints = [sv for sv in part_mod.btrfs_subvols if sv.mountpoint is not None]
369+
if subvols_with_mountpoints:
370+
self._mount_btrfs_subvol(
371+
part_mod.dev_path,
372+
part_mod.btrfs_subvols,
373+
part_mod.mount_options,
374+
)
372375
elif part_mod.is_swap():
373376
device_handler.swapon(part_mod.dev_path)
374377

@@ -379,14 +382,20 @@ def _mount_lvm_vol(self, volume: LvmVolume) -> None:
379382
device_handler.mount(volume.dev_path, target, options=volume.mount_options)
380383

381384
if volume.fs_type == FilesystemType.Btrfs and volume.dev_path:
382-
self._mount_btrfs_subvol(volume.dev_path, volume.btrfs_subvols, volume.mount_options)
385+
# Only mount BTRFS subvolumes that have mountpoints specified
386+
subvols_with_mountpoints = [sv for sv in volume.btrfs_subvols if sv.mountpoint is not None]
387+
if subvols_with_mountpoints:
388+
self._mount_btrfs_subvol(volume.dev_path, volume.btrfs_subvols, volume.mount_options)
383389

384390
def _mount_luks_partition(self, part_mod: PartitionModification, luks_handler: Luks2) -> None:
385391
if not luks_handler.mapper_dev:
386392
return None
387393

388394
if part_mod.fs_type == FilesystemType.Btrfs and part_mod.btrfs_subvols:
389-
self._mount_btrfs_subvol(luks_handler.mapper_dev, part_mod.btrfs_subvols, part_mod.mount_options)
395+
# Only mount BTRFS subvolumes that have mountpoints specified
396+
subvols_with_mountpoints = [sv for sv in part_mod.btrfs_subvols if sv.mountpoint is not None]
397+
if subvols_with_mountpoints:
398+
self._mount_btrfs_subvol(luks_handler.mapper_dev, part_mod.btrfs_subvols, part_mod.mount_options)
390399
elif part_mod.mountpoint:
391400
target = self.target / part_mod.relative_mountpoint
392401
device_handler.mount(luks_handler.mapper_dev, target, options=part_mod.mount_options)
@@ -398,15 +407,20 @@ def _mount_luks_volume(self, volume: LvmVolume, luks_handler: Luks2) -> None:
398407
device_handler.mount(luks_handler.mapper_dev, target, options=volume.mount_options)
399408

400409
if volume.fs_type == FilesystemType.Btrfs and luks_handler.mapper_dev:
401-
self._mount_btrfs_subvol(luks_handler.mapper_dev, volume.btrfs_subvols, volume.mount_options)
410+
# Only mount BTRFS subvolumes that have mountpoints specified
411+
subvols_with_mountpoints = [sv for sv in volume.btrfs_subvols if sv.mountpoint is not None]
412+
if subvols_with_mountpoints:
413+
self._mount_btrfs_subvol(luks_handler.mapper_dev, volume.btrfs_subvols, volume.mount_options)
402414

403415
def _mount_btrfs_subvol(
404416
self,
405417
dev_path: Path,
406418
subvolumes: list[SubvolumeModification],
407419
mount_options: list[str] = [],
408420
) -> None:
409-
for subvol in sorted(subvolumes, key=lambda x: x.relative_mountpoint):
421+
# Filter out subvolumes without mountpoints to avoid errors when sorting
422+
subvols_with_mountpoints = [sv for sv in subvolumes if sv.mountpoint is not None]
423+
for subvol in sorted(subvols_with_mountpoints, key=lambda x: x.relative_mountpoint):
410424
mountpoint = self.target / subvol.relative_mountpoint
411425
options = mount_options + [f'subvol={subvol.name}']
412426
device_handler.mount(dev_path, mountpoint, options=options)

archinstall/lib/models/application.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ class PrintServiceConfigSerialization(TypedDict):
3030
enabled: bool
3131

3232

33+
class Firewall(StrEnum):
34+
UFW = 'ufw'
35+
36+
37+
class FirewallConfigSerialization(TypedDict):
38+
firewall: str
39+
40+
3341
class ZramAlgorithm(StrEnum):
3442
ZSTD = 'zstd'
3543
LZO_RLE = 'lzo-rle'
@@ -43,6 +51,7 @@ class ApplicationSerialization(TypedDict):
4351
audio_config: NotRequired[AudioConfigSerialization]
4452
power_management_config: NotRequired[PowerManagementConfigSerialization]
4553
print_service_config: NotRequired[PrintServiceConfigSerialization]
54+
firewall_config: NotRequired[FirewallConfigSerialization]
4655

4756

4857
@dataclass
@@ -101,6 +110,22 @@ def parse_arg(arg: dict[str, Any]) -> 'PrintServiceConfiguration':
101110
return PrintServiceConfiguration(arg['enabled'])
102111

103112

113+
@dataclass
114+
class FirewallConfiguration:
115+
firewall: Firewall
116+
117+
def json(self) -> FirewallConfigSerialization:
118+
return {
119+
'firewall': self.firewall.value,
120+
}
121+
122+
@staticmethod
123+
def parse_arg(arg: dict[str, Any]) -> 'FirewallConfiguration':
124+
return FirewallConfiguration(
125+
Firewall(arg['firewall']),
126+
)
127+
128+
104129
@dataclass(frozen=True)
105130
class ZramConfiguration:
106131
enabled: bool
@@ -122,6 +147,7 @@ class ApplicationConfiguration:
122147
audio_config: AudioConfiguration | None = None
123148
power_management_config: PowerManagementConfiguration | None = None
124149
print_service_config: PrintServiceConfiguration | None = None
150+
firewall_config: FirewallConfiguration | None = None
125151

126152
@staticmethod
127153
def parse_arg(
@@ -146,6 +172,9 @@ def parse_arg(
146172
if args and (print_service_config := args.get('print_service_config')) is not None:
147173
app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config)
148174

175+
if args and (firewall_config := args.get('firewall_config')) is not None:
176+
app_config.firewall_config = FirewallConfiguration.parse_arg(firewall_config)
177+
149178
return app_config
150179

151180
def json(self) -> ApplicationSerialization:
@@ -163,4 +192,7 @@ def json(self) -> ApplicationSerialization:
163192
if self.print_service_config:
164193
config['print_service_config'] = self.print_service_config.json()
165194

195+
if self.firewall_config:
196+
config['firewall_config'] = self.firewall_config.json()
197+
166198
return config
1.69 KB
Binary file not shown.

0 commit comments

Comments
 (0)