Skip to content
Merged
8 changes: 5 additions & 3 deletions archinstall/lib/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from pydantic.dataclasses import dataclass as p_dataclass

from archinstall.lib.crypt import decrypt
from archinstall.lib.models.application import ApplicationConfiguration
from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration
from archinstall.lib.models.authentication import AuthenticationConfiguration
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
from archinstall.lib.models.device import DiskEncryption, DiskLayoutConfiguration
Expand Down Expand Up @@ -67,12 +67,12 @@ class ArchConfig:
bootloader_config: BootloaderConfiguration | None = None
app_config: ApplicationConfiguration | None = None
auth_config: AuthenticationConfiguration | None = None
swap: ZramConfiguration | None = None
hostname: str = 'archlinux'
kernels: list[str] = field(default_factory=lambda: ['linux'])
ntp: bool = True
packages: list[str] = field(default_factory=list)
parallel_downloads: int = 0
swap: bool = True
timezone: str = 'UTC'
services: list[str] = field(default_factory=list)
custom_commands: list[str] = field(default_factory=list)
Expand Down Expand Up @@ -211,7 +211,9 @@ def from_config(cls, args_config: dict[str, Any], args: Arguments) -> 'ArchConfi
if parallel_downloads := args_config.get('parallel_downloads', 0):
arch_config.parallel_downloads = parallel_downloads

arch_config.swap = args_config.get('swap', True)
swap_arg = args_config.get('swap')
if swap_arg is not None:
arch_config.swap = ZramConfiguration.parse_arg(swap_arg)

if timezone := args_config.get('timezone', 'UTC'):
arch_config.timezone = timezone
Expand Down
8 changes: 5 additions & 3 deletions archinstall/lib/global_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import override

from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu
from archinstall.lib.models.application import ApplicationConfiguration
from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration
from archinstall.lib.models.authentication import AuthenticationConfiguration
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType, EncryptionType, FilesystemType, PartitionModification
from archinstall.lib.packages import list_available_packages
Expand Down Expand Up @@ -80,7 +80,7 @@ def _get_menu_options(self) -> list[MenuItem]:
),
MenuItem(
text=tr('Swap'),
value=True,
value=ZramConfiguration(enabled=True),
action=ask_for_swap,
preview_action=self._prev_swap,
key='swap',
Expand Down Expand Up @@ -372,7 +372,9 @@ def _prev_disk_config(self, item: MenuItem) -> str | None:
def _prev_swap(self, item: MenuItem) -> str | None:
if item.value is not None:
output = f'{tr("Swap on zram")}: '
output += tr('Enabled') if item.value else tr('Disabled')
output += tr('Enabled') if item.value.enabled else tr('Disabled')
if item.value.enabled:
output += f'\n{tr("Compression algorithm")}: {item.value.algorithm.value}'
return output
return None

Expand Down
9 changes: 5 additions & 4 deletions archinstall/lib/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from archinstall.lib.disk.device_handler import device_handler
from archinstall.lib.disk.fido import Fido2
from archinstall.lib.disk.utils import get_lsblk_by_mountpoint, get_lsblk_info
from archinstall.lib.models.application import ZramAlgorithm
from archinstall.lib.models.device import (
DiskEncryption,
DiskLayoutConfiguration,
Expand Down Expand Up @@ -990,7 +991,7 @@ def setup_btrfs_snapshot(
self._configure_grub_btrfsd(snapshot_type)
self.enable_service('grub-btrfsd.service')

def setup_swap(self, kind: str = 'zram') -> None:
def setup_swap(self, kind: str = 'zram', algo: ZramAlgorithm = ZramAlgorithm.ZSTD) -> None:
if kind == 'zram':
info('Setting up swap on zram')
self.pacman.strap('zram-generator')
Expand All @@ -999,12 +1000,12 @@ def setup_swap(self, kind: str = 'zram') -> None:
# Convert KB to MB and divide by 2, with minimum of 4096 MB
size_mb = max(ram_kb // 2048, 4096)
info(f'Zram size: {size_mb} from RAM: {ram_kb}')
# We could use the default example below, but maybe not the best idea: https://github.com/archlinux/archinstall/pull/678#issuecomment-962124813
# zram_example_location = '/usr/share/doc/zram-generator/zram-generator.conf.example'
# shutil.copy2(f"{self.target}{zram_example_location}", f"{self.target}/usr/lib/systemd/zram-generator.conf")
info(f'Zram compression algorithm: {algo.value}')

with open(f'{self.target}/etc/systemd/zram-generator.conf', 'w') as zram_conf:
zram_conf.write('[zram0]\n')
zram_conf.write(f'zram-size = {size_mb}\n')
zram_conf.write(f'compression-algorithm = {algo.value}\n')

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

Expand Down
36 changes: 28 additions & 8 deletions archinstall/lib/interactions/system_conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

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


def ask_for_swap(preset: bool = True) -> bool:
if preset:
default_item = MenuItem.yes()
else:
default_item = MenuItem.no()

def ask_for_swap(preset: ZramConfiguration = ZramConfiguration(enabled=True)) -> ZramConfiguration:
prompt = tr('Would you like to use swap on zram?') + '\n'

group = MenuItemGroup.yes_no()
group.set_focus_by_value(default_item)
group.set_default_by_value(True)
group.set_focus_by_value(preset.enabled)

result = SelectMenu[bool](
group,
Expand All @@ -113,6 +110,29 @@ def ask_for_swap(preset: bool = True) -> bool:
case ResultType.Skip:
return preset
case ResultType.Selection:
return result.item() == MenuItem.yes()
enabled = result.item() == MenuItem.yes()
if not enabled:
return ZramConfiguration(enabled=False)

# Ask for compression algorithm
algo_group = MenuItemGroup.from_enum(ZramAlgorithm, sort_items=False)
algo_group.set_default_by_value(ZramAlgorithm.ZSTD)
algo_group.set_focus_by_value(preset.algorithm)

algo_result = SelectMenu[ZramAlgorithm](
algo_group,
header=tr('Select zram compression algorithm:') + '\n',
alignment=Alignment.CENTER,
allow_skip=True,
).run()

algo: ZramAlgorithm
match algo_result.type_:
case ResultType.Skip:
algo = preset.algorithm
case ResultType.Selection:
algo = algo_result.get_value()

return ZramConfiguration(enabled=True, algorithm=algo)
case ResultType.Reset:
raise ValueError('Unhandled result type')
23 changes: 23 additions & 0 deletions archinstall/lib/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ class PrintServiceConfigSerialization(TypedDict):
enabled: bool


class ZramAlgorithm(StrEnum):
ZSTD = 'zstd'
LZO_RLE = 'lzo-rle'
LZO = 'lzo'
LZ4 = 'lz4'
LZ4HC = 'lz4hc'


class ApplicationSerialization(TypedDict):
bluetooth_config: NotRequired[BluetoothConfigSerialization]
audio_config: NotRequired[AudioConfigSerialization]
Expand Down Expand Up @@ -67,6 +75,21 @@ def parse_arg(arg: dict[str, Any]) -> 'PrintServiceConfiguration':
return PrintServiceConfiguration(arg['enabled'])


@dataclass(frozen=True)
class ZramConfiguration:
enabled: bool
algorithm: ZramAlgorithm = ZramAlgorithm.ZSTD

@staticmethod
def parse_arg(arg: bool | dict[str, Any]) -> 'ZramConfiguration':
if isinstance(arg, bool):
return ZramConfiguration(enabled=arg)

enabled = arg.get('enabled', True)
algo = arg.get('algorithm', arg.get('algo', ZramAlgorithm.ZSTD.value))
return ZramConfiguration(enabled=enabled, algorithm=ZramAlgorithm(algo))


@dataclass
class ApplicationConfiguration:
bluetooth_config: BluetoothConfiguration | None = None
Expand Down
4 changes: 2 additions & 2 deletions archinstall/scripts/guided.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ def perform_installation(mountpoint: Path) -> None:
if mirror_config := config.mirror_config:
installation.set_mirrors(mirror_config, on_target=True)

if config.swap:
installation.setup_swap('zram')
if config.swap and config.swap.enabled:
installation.setup_swap('zram', algo=config.swap.algorithm)

if config.bootloader_config and config.bootloader_config.bootloader != Bootloader.NO_BOOTLOADER:
if config.bootloader_config.bootloader == Bootloader.Grub and SysInfo.has_uefi():
Expand Down
5 changes: 4 additions & 1 deletion examples/config-sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@
},
"script": "guided",
"silent": false,
"swap": true,
"swap": {
"enabled": true,
"algorithm": "zstd"
},
"timezone": "UTC",
"version": "2.8.6"
}
11 changes: 9 additions & 2 deletions tests/test_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
from archinstall.default_profiles.profile import GreeterType
from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments
from archinstall.lib.hardware import GfxDriver
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration
from archinstall.lib.models.application import (
ApplicationConfiguration,
Audio,
AudioConfiguration,
BluetoothConfiguration,
PrintServiceConfiguration,
ZramConfiguration,
)
from archinstall.lib.models.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType
Expand Down Expand Up @@ -225,7 +232,7 @@ def test_config_file_parsing(
ntp=True,
packages=['firefox'],
parallel_downloads=66,
swap=False,
swap=ZramConfiguration(enabled=False),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be test the true case with a proper algorithm

timezone='UTC',
services=['service_1', 'service_2'],
custom_commands=["echo 'Hello, World!'"],
Expand Down