Skip to content

Commit 2954e43

Browse files
authored
Feat: Zram algorithm config (#4042)
* Add configuration for swap algorithm. Backward compatible implementation * Fix interaction to default to Yes and show (default) * Fix mypy error * Any -> str, str * feedback Enums * test file * line length warning * Renames * Fix default values in TUI menu for display * Address feedback * More feedback, really appreciate it. * Adapt to use same | None = None pattern * Pytests * Add missing import for Zram
1 parent 747385a commit 2954e43

File tree

8 files changed

+81
-23
lines changed

8 files changed

+81
-23
lines changed

archinstall/lib/args.py

Lines changed: 5 additions & 3 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.application import ApplicationConfiguration
16+
from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration
1717
from archinstall.lib.models.authentication import AuthenticationConfiguration
1818
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
1919
from archinstall.lib.models.device import DiskEncryption, DiskLayoutConfiguration
@@ -67,12 +67,12 @@ class ArchConfig:
6767
bootloader_config: BootloaderConfiguration | None = None
6868
app_config: ApplicationConfiguration | None = None
6969
auth_config: AuthenticationConfiguration | None = None
70+
swap: ZramConfiguration | None = None
7071
hostname: str = 'archlinux'
7172
kernels: list[str] = field(default_factory=lambda: ['linux'])
7273
ntp: bool = True
7374
packages: list[str] = field(default_factory=list)
7475
parallel_downloads: int = 0
75-
swap: bool = True
7676
timezone: str = 'UTC'
7777
services: list[str] = field(default_factory=list)
7878
custom_commands: list[str] = field(default_factory=list)
@@ -211,7 +211,9 @@ def from_config(cls, args_config: dict[str, Any], args: Arguments) -> 'ArchConfi
211211
if parallel_downloads := args_config.get('parallel_downloads', 0):
212212
arch_config.parallel_downloads = parallel_downloads
213213

214-
arch_config.swap = args_config.get('swap', True)
214+
swap_arg = args_config.get('swap')
215+
if swap_arg is not None:
216+
arch_config.swap = ZramConfiguration.parse_arg(swap_arg)
215217

216218
if timezone := args_config.get('timezone', 'UTC'):
217219
arch_config.timezone = timezone

archinstall/lib/global_menu.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import override
44

55
from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu
6-
from archinstall.lib.models.application import ApplicationConfiguration
6+
from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration
77
from archinstall.lib.models.authentication import AuthenticationConfiguration
88
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType, EncryptionType, FilesystemType, PartitionModification
99
from archinstall.lib.packages import list_available_packages
@@ -80,7 +80,7 @@ def _get_menu_options(self) -> list[MenuItem]:
8080
),
8181
MenuItem(
8282
text=tr('Swap'),
83-
value=True,
83+
value=ZramConfiguration(enabled=True),
8484
action=ask_for_swap,
8585
preview_action=self._prev_swap,
8686
key='swap',
@@ -372,7 +372,9 @@ def _prev_disk_config(self, item: MenuItem) -> str | None:
372372
def _prev_swap(self, item: MenuItem) -> str | None:
373373
if item.value is not None:
374374
output = f'{tr("Swap on zram")}: '
375-
output += tr('Enabled') if item.value else tr('Disabled')
375+
output += tr('Enabled') if item.value.enabled else tr('Disabled')
376+
if item.value.enabled:
377+
output += f'\n{tr("Compression algorithm")}: {item.value.algorithm.value}'
376378
return output
377379
return None
378380

archinstall/lib/installer.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from archinstall.lib.disk.device_handler import device_handler
1717
from archinstall.lib.disk.fido import Fido2
1818
from archinstall.lib.disk.utils import get_lsblk_by_mountpoint, get_lsblk_info
19+
from archinstall.lib.models.application import ZramAlgorithm
1920
from archinstall.lib.models.device import (
2021
DiskEncryption,
2122
DiskLayoutConfiguration,
@@ -991,7 +992,7 @@ def setup_btrfs_snapshot(
991992
self._configure_grub_btrfsd(snapshot_type)
992993
self.enable_service('grub-btrfsd.service')
993994

994-
def setup_swap(self, kind: str = 'zram') -> None:
995+
def setup_swap(self, kind: str = 'zram', algo: ZramAlgorithm = ZramAlgorithm.ZSTD) -> None:
995996
if kind == 'zram':
996997
info('Setting up swap on zram')
997998
self.pacman.strap('zram-generator')
@@ -1000,12 +1001,12 @@ def setup_swap(self, kind: str = 'zram') -> None:
10001001
# Convert KB to MB and divide by 2, with minimum of 4096 MB
10011002
size_mb = max(ram_kb // 2048, 4096)
10021003
info(f'Zram size: {size_mb} from RAM: {ram_kb}')
1003-
# We could use the default example below, but maybe not the best idea: https://github.com/archlinux/archinstall/pull/678#issuecomment-962124813
1004-
# zram_example_location = '/usr/share/doc/zram-generator/zram-generator.conf.example'
1005-
# shutil.copy2(f"{self.target}{zram_example_location}", f"{self.target}/usr/lib/systemd/zram-generator.conf")
1004+
info(f'Zram compression algorithm: {algo.value}')
1005+
10061006
with open(f'{self.target}/etc/systemd/zram-generator.conf', 'w') as zram_conf:
10071007
zram_conf.write('[zram0]\n')
10081008
zram_conf.write(f'zram-size = {size_mb}\n')
1009+
zram_conf.write(f'compression-algorithm = {algo.value}\n')
10091010

10101011
self.enable_service('systemd-zram-setup@zram0.service')
10111012

archinstall/lib/interactions/system_conf.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from archinstall.lib.models.application import ZramAlgorithm, ZramConfiguration
34
from archinstall.lib.translationhandler import tr
45
from archinstall.tui.curses_menu import SelectMenu
56
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
@@ -89,16 +90,12 @@ def select_driver(options: list[GfxDriver] = [], preset: GfxDriver | None = None
8990
return result.get_value()
9091

9192

92-
def ask_for_swap(preset: bool = True) -> bool:
93-
if preset:
94-
default_item = MenuItem.yes()
95-
else:
96-
default_item = MenuItem.no()
97-
93+
def ask_for_swap(preset: ZramConfiguration = ZramConfiguration(enabled=True)) -> ZramConfiguration:
9894
prompt = tr('Would you like to use swap on zram?') + '\n'
9995

10096
group = MenuItemGroup.yes_no()
101-
group.set_focus_by_value(default_item)
97+
group.set_default_by_value(True)
98+
group.set_focus_by_value(preset.enabled)
10299

103100
result = SelectMenu[bool](
104101
group,
@@ -113,6 +110,29 @@ def ask_for_swap(preset: bool = True) -> bool:
113110
case ResultType.Skip:
114111
return preset
115112
case ResultType.Selection:
116-
return result.item() == MenuItem.yes()
113+
enabled = result.item() == MenuItem.yes()
114+
if not enabled:
115+
return ZramConfiguration(enabled=False)
116+
117+
# Ask for compression algorithm
118+
algo_group = MenuItemGroup.from_enum(ZramAlgorithm, sort_items=False)
119+
algo_group.set_default_by_value(ZramAlgorithm.ZSTD)
120+
algo_group.set_focus_by_value(preset.algorithm)
121+
122+
algo_result = SelectMenu[ZramAlgorithm](
123+
algo_group,
124+
header=tr('Select zram compression algorithm:') + '\n',
125+
alignment=Alignment.CENTER,
126+
allow_skip=True,
127+
).run()
128+
129+
algo: ZramAlgorithm
130+
match algo_result.type_:
131+
case ResultType.Skip:
132+
algo = preset.algorithm
133+
case ResultType.Selection:
134+
algo = algo_result.get_value()
135+
136+
return ZramConfiguration(enabled=True, algorithm=algo)
117137
case ResultType.Reset:
118138
raise ValueError('Unhandled result type')

archinstall/lib/models/application.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ class PrintServiceConfigSerialization(TypedDict):
2121
enabled: bool
2222

2323

24+
class ZramAlgorithm(StrEnum):
25+
ZSTD = 'zstd'
26+
LZO_RLE = 'lzo-rle'
27+
LZO = 'lzo'
28+
LZ4 = 'lz4'
29+
LZ4HC = 'lz4hc'
30+
31+
2432
class ApplicationSerialization(TypedDict):
2533
bluetooth_config: NotRequired[BluetoothConfigSerialization]
2634
audio_config: NotRequired[AudioConfigSerialization]
@@ -67,6 +75,21 @@ def parse_arg(arg: dict[str, Any]) -> 'PrintServiceConfiguration':
6775
return PrintServiceConfiguration(arg['enabled'])
6876

6977

78+
@dataclass(frozen=True)
79+
class ZramConfiguration:
80+
enabled: bool
81+
algorithm: ZramAlgorithm = ZramAlgorithm.ZSTD
82+
83+
@staticmethod
84+
def parse_arg(arg: bool | dict[str, Any]) -> 'ZramConfiguration':
85+
if isinstance(arg, bool):
86+
return ZramConfiguration(enabled=arg)
87+
88+
enabled = arg.get('enabled', True)
89+
algo = arg.get('algorithm', arg.get('algo', ZramAlgorithm.ZSTD.value))
90+
return ZramConfiguration(enabled=enabled, algorithm=ZramAlgorithm(algo))
91+
92+
7093
@dataclass
7194
class ApplicationConfiguration:
7295
bluetooth_config: BluetoothConfiguration | None = None

archinstall/scripts/guided.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def perform_installation(mountpoint: Path) -> None:
9898
if mirror_config := config.mirror_config:
9999
installation.set_mirrors(mirror_config, on_target=True)
100100

101-
if config.swap:
102-
installation.setup_swap('zram')
101+
if config.swap and config.swap.enabled:
102+
installation.setup_swap('zram', algo=config.swap.algorithm)
103103

104104
if config.bootloader_config and config.bootloader_config.bootloader != Bootloader.NO_BOOTLOADER:
105105
if config.bootloader_config.bootloader == Bootloader.Grub and SysInfo.has_uefi():

examples/config-sample.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@
146146
},
147147
"script": "guided",
148148
"silent": false,
149-
"swap": true,
149+
"swap": {
150+
"enabled": true,
151+
"algorithm": "zstd"
152+
},
150153
"timezone": "UTC",
151154
"version": "2.8.6"
152155
}

tests/test_args.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
from archinstall.default_profiles.profile import GreeterType
88
from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments
99
from archinstall.lib.hardware import GfxDriver
10-
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration
10+
from archinstall.lib.models.application import (
11+
ApplicationConfiguration,
12+
Audio,
13+
AudioConfiguration,
14+
BluetoothConfiguration,
15+
PrintServiceConfiguration,
16+
ZramConfiguration,
17+
)
1118
from archinstall.lib.models.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod
1219
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
1320
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType
@@ -225,7 +232,7 @@ def test_config_file_parsing(
225232
ntp=True,
226233
packages=['firefox'],
227234
parallel_downloads=66,
228-
swap=False,
235+
swap=ZramConfiguration(enabled=False),
229236
timezone='UTC',
230237
services=['service_1', 'service_2'],
231238
custom_commands=["echo 'Hello, World!'"],

0 commit comments

Comments
 (0)