detached 731f456

feat(system): add zram configuration and enable power-profiles-daemon

commit
731f4562b8d3b88f55aa76b28ef19a62f1a1cad4
author
brice · · 2026-02-28 05:22 UTC
parent
01a505a
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +34 -2
M install/extra.packages +1 -1
@@ -17,7 +17,7 @@ wget
1717 unzip
1818
1919 # Power management
20-tlp
20+power-profiles-daemon
2121
2222 # Security
2323 firewalld
@@ -17,7 +17,7 @@ wget
17 unzip17 unzip
18 18
19 # Power management19 # Power management
20-tlp20+power-profiles-daemon
21 21
22 # Security22 # Security
23 firewalld23 firewalld
M internal/application/handlers/configure_system_handler.go +33 -1
@@ -11,6 +11,7 @@ import (
1111
1212 "github.com/bnema/archup/internal/application/commands"
1313 "github.com/bnema/archup/internal/application/dto"
14+ "github.com/bnema/archup/internal/config"
1415 "github.com/bnema/archup/internal/domain/ports"
1516 "github.com/bnema/archup/internal/domain/system"
1617 "github.com/bnema/archup/internal/domain/user"
@@ -174,7 +175,7 @@ func (h *ConfigureSystemHandler) Handle(ctx context.Context, cmd commands.Config
174175 result.ErrorDetail = fmt.Sprintf("Failed to create sudoers.d directory: %v", err)
175176 return result, err
176177 }
177- if err := h.fs.WriteFile(filepath.Join(sudoersDir, "wheel"), []byte("%wheel ALL=(ALL:ALL) ALL\n"), 0440); err != nil {
178+ if err := h.fs.WriteFile(filepath.Join(sudoersDir, "wheel"), []byte(config.SudoersWheelContent), config.SudoersWheelPerms); err != nil {
178179 h.logger.Error("Failed to write sudoers", "error", err)
179180 result.ErrorDetail = fmt.Sprintf("Failed to write sudoers: %v", err)
180181 return result, err
@@ -191,6 +192,14 @@ func (h *ConfigureSystemHandler) Handle(ctx context.Context, cmd commands.Config
191192 h.logger.Warn("Failed to mask NetworkManager-wait-online.service", "error", err)
192193 }
193194
195+ if err := h.chrExec.ChrootSystemctl(ctx, h.logger.LogPath(), cmd.MountPoint, "enable", "power-profiles-daemon"); err != nil {
196+ h.logger.Warn("Failed to enable power-profiles-daemon", "error", err)
197+ }
198+
199+ if err := h.configureZram(cmd.MountPoint); err != nil {
200+ h.logger.Warn("Failed to configure zram", "error", err)
201+ }
202+
194203 // Migrate iwd WiFi credentials from live ISO to NetworkManager profiles in the installed system.
195204 if err := h.migrateIWDProfiles(cmd.MountPoint); err != nil {
196205 // Non-fatal: log and continue. User can configure WiFi manually after boot.
@@ -364,6 +373,29 @@ func hexNibble(c byte) int {
364373 return -1
365374 }
366375
376+// configureZram writes zram-generator.conf and the matching sysctl tuning file.
377+func (h *ConfigureSystemHandler) configureZram(mountPoint string) error {
378+ zramDir := filepath.Join(mountPoint, "etc", "systemd")
379+ if err := h.fs.MkdirAll(zramDir, 0755); err != nil {
380+ return fmt.Errorf("failed to create systemd dir: %w", err)
381+ }
382+ zramConf := filepath.Join(zramDir, config.FileZramGenerator)
383+ if err := h.fs.WriteFile(zramConf, []byte(config.ZramConfigContent), 0644); err != nil {
384+ return fmt.Errorf("failed to write zram-generator.conf: %w", err)
385+ }
386+
387+ sysctlDir := filepath.Join(mountPoint, "etc", "sysctl.d")
388+ if err := h.fs.MkdirAll(sysctlDir, 0755); err != nil {
389+ return fmt.Errorf("failed to create sysctl.d dir: %w", err)
390+ }
391+ sysctlConf := filepath.Join(sysctlDir, config.FileSysctlZramParams)
392+ if err := h.fs.WriteFile(sysctlConf, []byte(config.ZramSysctlContent), 0644); err != nil {
393+ return fmt.Errorf("failed to write zram sysctl params: %w", err)
394+ }
395+
396+ return nil
397+}
398+
367399 // buildNMWiFiProfile generates a NetworkManager keyfile for a WPA-PSK network.
368400 func buildNMWiFiProfile(ssid, psk string) string {
369401 return fmt.Sprintf(`[connection]
@@ -11,6 +11,7 @@ import (
11 11
12 "github.com/bnema/archup/internal/application/commands"12 "github.com/bnema/archup/internal/application/commands"
13 "github.com/bnema/archup/internal/application/dto"13 "github.com/bnema/archup/internal/application/dto"
14+ "github.com/bnema/archup/internal/config"
14 "github.com/bnema/archup/internal/domain/ports"15 "github.com/bnema/archup/internal/domain/ports"
15 "github.com/bnema/archup/internal/domain/system"16 "github.com/bnema/archup/internal/domain/system"
16 "github.com/bnema/archup/internal/domain/user"17 "github.com/bnema/archup/internal/domain/user"
@@ -174,7 +175,7 @@ func (h *ConfigureSystemHandler) Handle(ctx context.Context, cmd commands.Config
174 result.ErrorDetail = fmt.Sprintf("Failed to create sudoers.d directory: %v", err)175 result.ErrorDetail = fmt.Sprintf("Failed to create sudoers.d directory: %v", err)
175 return result, err176 return result, err
176 }177 }
177- if err := h.fs.WriteFile(filepath.Join(sudoersDir, "wheel"), []byte("%wheel ALL=(ALL:ALL) ALL\n"), 0440); err != nil {178+ if err := h.fs.WriteFile(filepath.Join(sudoersDir, "wheel"), []byte(config.SudoersWheelContent), config.SudoersWheelPerms); err != nil {
178 h.logger.Error("Failed to write sudoers", "error", err)179 h.logger.Error("Failed to write sudoers", "error", err)
179 result.ErrorDetail = fmt.Sprintf("Failed to write sudoers: %v", err)180 result.ErrorDetail = fmt.Sprintf("Failed to write sudoers: %v", err)
180 return result, err181 return result, err
@@ -191,6 +192,14 @@ func (h *ConfigureSystemHandler) Handle(ctx context.Context, cmd commands.Config
191 h.logger.Warn("Failed to mask NetworkManager-wait-online.service", "error", err)192 h.logger.Warn("Failed to mask NetworkManager-wait-online.service", "error", err)
192 }193 }
193 194
195+ if err := h.chrExec.ChrootSystemctl(ctx, h.logger.LogPath(), cmd.MountPoint, "enable", "power-profiles-daemon"); err != nil {
196+ h.logger.Warn("Failed to enable power-profiles-daemon", "error", err)
197+ }
198+
199+ if err := h.configureZram(cmd.MountPoint); err != nil {
200+ h.logger.Warn("Failed to configure zram", "error", err)
201+ }
202+
194 // Migrate iwd WiFi credentials from live ISO to NetworkManager profiles in the installed system.203 // Migrate iwd WiFi credentials from live ISO to NetworkManager profiles in the installed system.
195 if err := h.migrateIWDProfiles(cmd.MountPoint); err != nil {204 if err := h.migrateIWDProfiles(cmd.MountPoint); err != nil {
196 // Non-fatal: log and continue. User can configure WiFi manually after boot.205 // Non-fatal: log and continue. User can configure WiFi manually after boot.
@@ -364,6 +373,29 @@ func hexNibble(c byte) int {
364 return -1373 return -1
365 }374 }
366 375
376+// configureZram writes zram-generator.conf and the matching sysctl tuning file.
377+func (h *ConfigureSystemHandler) configureZram(mountPoint string) error {
378+ zramDir := filepath.Join(mountPoint, "etc", "systemd")
379+ if err := h.fs.MkdirAll(zramDir, 0755); err != nil {
380+ return fmt.Errorf("failed to create systemd dir: %w", err)
381+ }
382+ zramConf := filepath.Join(zramDir, config.FileZramGenerator)
383+ if err := h.fs.WriteFile(zramConf, []byte(config.ZramConfigContent), 0644); err != nil {
384+ return fmt.Errorf("failed to write zram-generator.conf: %w", err)
385+ }
386+
387+ sysctlDir := filepath.Join(mountPoint, "etc", "sysctl.d")
388+ if err := h.fs.MkdirAll(sysctlDir, 0755); err != nil {
389+ return fmt.Errorf("failed to create sysctl.d dir: %w", err)
390+ }
391+ sysctlConf := filepath.Join(sysctlDir, config.FileSysctlZramParams)
392+ if err := h.fs.WriteFile(sysctlConf, []byte(config.ZramSysctlContent), 0644); err != nil {
393+ return fmt.Errorf("failed to write zram sysctl params: %w", err)
394+ }
395+
396+ return nil
397+}
398+
367 // buildNMWiFiProfile generates a NetworkManager keyfile for a WPA-PSK network.399 // buildNMWiFiProfile generates a NetworkManager keyfile for a WPA-PSK network.
368 func buildNMWiFiProfile(ssid, psk string) string {400 func buildNMWiFiProfile(ssid, psk string) string {
369 return fmt.Sprintf(`[connection]401 return fmt.Sprintf(`[connection]

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close