detached 28e451b

refactor(codebase): cleanup formatting and fix bootloader handler import

commit
28e451b1705d2afb2142cd83785f07ce185a0a37
author
brice · · 2026-01-24 03:30 UTC
parent
6cba902
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
72 files · +497 -500
M cmd/archup-installer/main.go +1 -1
@@ -5,7 +5,6 @@ import (
55 "fmt"
66 "os"
77
8- tea "github.com/charmbracelet/bubbletea"
98 apphandlers "github.com/bnema/archup/internal/application/handlers"
109 "github.com/bnema/archup/internal/application/services"
1110 "github.com/bnema/archup/internal/cleanup"
@@ -16,6 +15,7 @@ import (
1615 "github.com/bnema/archup/internal/infrastructure/persistence"
1716 "github.com/bnema/archup/internal/interfaces/tui"
1817 "github.com/bnema/archup/internal/logger"
18+ tea "github.com/charmbracelet/bubbletea"
1919 )
2020
2121 // version is set via ldflags at build time
@@ -5,7 +5,6 @@ import (
5 "fmt"5 "fmt"
6 "os"6 "os"
7 7
8- tea "github.com/charmbracelet/bubbletea"
9 apphandlers "github.com/bnema/archup/internal/application/handlers"8 apphandlers "github.com/bnema/archup/internal/application/handlers"
10 "github.com/bnema/archup/internal/application/services"9 "github.com/bnema/archup/internal/application/services"
11 "github.com/bnema/archup/internal/cleanup"10 "github.com/bnema/archup/internal/cleanup"
@@ -16,6 +15,7 @@ import (
16 "github.com/bnema/archup/internal/infrastructure/persistence"15 "github.com/bnema/archup/internal/infrastructure/persistence"
17 "github.com/bnema/archup/internal/interfaces/tui"16 "github.com/bnema/archup/internal/interfaces/tui"
18 "github.com/bnema/archup/internal/logger"17 "github.com/bnema/archup/internal/logger"
18+ tea "github.com/charmbracelet/bubbletea"
19 )19 )
20 20
21 // version is set via ldflags at build time21 // version is set via ldflags at build time
M internal/application/commands/configure_system.go +7 -7
@@ -2,13 +2,13 @@ package commands
22
33 // ConfigureSystemCommand contains data for system configuration
44 type ConfigureSystemCommand struct {
5- MountPoint string // Root mount point where system is installed
6- Hostname string // System hostname
7- Timezone string // IANA timezone (e.g., "UTC", "Europe/Paris")
8- Locale string // System locale (e.g., "en_US.UTF-8")
9- Keymap string // Keyboard layout
10- Username string // Standard user username
11- UserShell string // Shell for user (e.g., "/bin/bash")
5+ MountPoint string // Root mount point where system is installed
6+ Hostname string // System hostname
7+ Timezone string // IANA timezone (e.g., "UTC", "Europe/Paris")
8+ Locale string // System locale (e.g., "en_US.UTF-8")
9+ Keymap string // Keyboard layout
10+ Username string // Standard user username
11+ UserShell string // Shell for user (e.g., "/bin/bash")
1212 UserPassword string // User password
1313 RootPassword string // Root password
1414 }
@@ -2,13 +2,13 @@ package commands
2 2
3 // ConfigureSystemCommand contains data for system configuration3 // ConfigureSystemCommand contains data for system configuration
4 type ConfigureSystemCommand struct {4 type ConfigureSystemCommand struct {
5- MountPoint string // Root mount point where system is installed5+ MountPoint string // Root mount point where system is installed
6- Hostname string // System hostname6+ Hostname string // System hostname
7- Timezone string // IANA timezone (e.g., "UTC", "Europe/Paris")7+ Timezone string // IANA timezone (e.g., "UTC", "Europe/Paris")
8- Locale string // System locale (e.g., "en_US.UTF-8")8+ Locale string // System locale (e.g., "en_US.UTF-8")
9- Keymap string // Keyboard layout9+ Keymap string // Keyboard layout
10- Username string // Standard user username10+ Username string // Standard user username
11- UserShell string // Shell for user (e.g., "/bin/bash")11+ UserShell string // Shell for user (e.g., "/bin/bash")
12 UserPassword string // User password12 UserPassword string // User password
13 RootPassword string // Root password13 RootPassword string // Root password
14 }14 }
M internal/application/commands/install_base.go +4 -4
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/packages"
44
55 // InstallBaseCommand contains data for base system installation
66 type InstallBaseCommand struct {
7- TargetDisk string // Target disk with partitions
8- MountPoint string // Root mount point (usually "/mnt")
9- Packages []string // Additional packages to install (in addition to base)
7+ TargetDisk string // Target disk with partitions
8+ MountPoint string // Root mount point (usually "/mnt")
9+ Packages []string // Additional packages to install (in addition to base)
1010 KernelVariant packages.KernelVariant // KernelStable, KernelZen, KernelLTS, KernelHardened, KernelCachyOS
11- IncludeMicrocode bool // Whether to install CPU microcode
11+ IncludeMicrocode bool // Whether to install CPU microcode
1212 }
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/packages"
4 4
5 // InstallBaseCommand contains data for base system installation5 // InstallBaseCommand contains data for base system installation
6 type InstallBaseCommand struct {6 type InstallBaseCommand struct {
7- TargetDisk string // Target disk with partitions7+ TargetDisk string // Target disk with partitions
8- MountPoint string // Root mount point (usually "/mnt")8+ MountPoint string // Root mount point (usually "/mnt")
9- Packages []string // Additional packages to install (in addition to base)9+ Packages []string // Additional packages to install (in addition to base)
10 KernelVariant packages.KernelVariant // KernelStable, KernelZen, KernelLTS, KernelHardened, KernelCachyOS10 KernelVariant packages.KernelVariant // KernelStable, KernelZen, KernelLTS, KernelHardened, KernelCachyOS
11- IncludeMicrocode bool // Whether to install CPU microcode11+ IncludeMicrocode bool // Whether to install CPU microcode
12 }12 }
M internal/application/commands/install_bootloader.go +3 -3
@@ -4,8 +4,8 @@ import "github.com/bnema/archup/internal/domain/bootloader"
44
55 // InstallBootloaderCommand contains data for bootloader installation
66 type InstallBootloaderCommand struct {
7- MountPoint string // Root mount point
7+ MountPoint string // Root mount point
88 BootloaderType bootloader.BootloaderType // BootloaderTypeLimine or BootloaderTypeSystemdBoot
9- TimeoutSeconds int // Boot menu timeout (0-600 seconds)
10- Branding string // Bootloader display name
9+ TimeoutSeconds int // Boot menu timeout (0-600 seconds)
10+ Branding string // Bootloader display name
1111 }
@@ -4,8 +4,8 @@ import "github.com/bnema/archup/internal/domain/bootloader"
4 4
5 // InstallBootloaderCommand contains data for bootloader installation5 // InstallBootloaderCommand contains data for bootloader installation
6 type InstallBootloaderCommand struct {6 type InstallBootloaderCommand struct {
7- MountPoint string // Root mount point7+ MountPoint string // Root mount point
8 BootloaderType bootloader.BootloaderType // BootloaderTypeLimine or BootloaderTypeSystemdBoot8 BootloaderType bootloader.BootloaderType // BootloaderTypeLimine or BootloaderTypeSystemdBoot
9- TimeoutSeconds int // Boot menu timeout (0-600 seconds)9+ TimeoutSeconds int // Boot menu timeout (0-600 seconds)
10- Branding string // Bootloader display name10+ Branding string // Bootloader display name
11 }11 }
M internal/application/commands/partition.go +3 -3
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/disk"
44
55 // PartitionDiskCommand contains data for disk partitioning
66 type PartitionDiskCommand struct {
7- TargetDisk string // e.g., "/dev/sda"
8- RootSizeGB int64 // Size of root partition in GB
9- BootSizeGB int64 // Size of boot partition in GB (usually 512MB-1GB)
7+ TargetDisk string // e.g., "/dev/sda"
8+ RootSizeGB int64 // Size of root partition in GB
9+ BootSizeGB int64 // Size of boot partition in GB (usually 512MB-1GB)
1010 EncryptionType disk.EncryptionType // EncryptionTypeNone, EncryptionTypeLUKS, EncryptionTypeLUKSLVM
1111 EncryptionPassword string // Password for encrypted partitions (if applicable)
1212 FilesystemType disk.FilesystemType // FilesystemExt4, FilesystemBtrfs, FilesystemFAT32
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/disk"
4 4
5 // PartitionDiskCommand contains data for disk partitioning5 // PartitionDiskCommand contains data for disk partitioning
6 type PartitionDiskCommand struct {6 type PartitionDiskCommand struct {
7- TargetDisk string // e.g., "/dev/sda"7+ TargetDisk string // e.g., "/dev/sda"
8- RootSizeGB int64 // Size of root partition in GB8+ RootSizeGB int64 // Size of root partition in GB
9- BootSizeGB int64 // Size of boot partition in GB (usually 512MB-1GB)9+ BootSizeGB int64 // Size of boot partition in GB (usually 512MB-1GB)
10 EncryptionType disk.EncryptionType // EncryptionTypeNone, EncryptionTypeLUKS, EncryptionTypeLUKSLVM10 EncryptionType disk.EncryptionType // EncryptionTypeNone, EncryptionTypeLUKS, EncryptionTypeLUKSLVM
11 EncryptionPassword string // Password for encrypted partitions (if applicable)11 EncryptionPassword string // Password for encrypted partitions (if applicable)
12 FilesystemType disk.FilesystemType // FilesystemExt4, FilesystemBtrfs, FilesystemFAT3212 FilesystemType disk.FilesystemType // FilesystemExt4, FilesystemBtrfs, FilesystemFAT32
M internal/application/commands/post_install.go +3 -3
@@ -2,8 +2,8 @@ package commands
22
33 // PostInstallCommand contains data for post-installation tasks
44 type PostInstallCommand struct {
5- MountPoint string // Root mount point
6- Username string // Standard user username
5+ MountPoint string // Root mount point
6+ Username string // Standard user username
77 RunPostBootScripts bool // Whether to run post-boot scripts
8- PlymouthTheme string // Plymouth theme to install (optional)
8+ PlymouthTheme string // Plymouth theme to install (optional)
99 }
@@ -2,8 +2,8 @@ package commands
2 2
3 // PostInstallCommand contains data for post-installation tasks3 // PostInstallCommand contains data for post-installation tasks
4 type PostInstallCommand struct {4 type PostInstallCommand struct {
5- MountPoint string // Root mount point5+ MountPoint string // Root mount point
6- Username string // Standard user username6+ Username string // Standard user username
7 RunPostBootScripts bool // Whether to run post-boot scripts7 RunPostBootScripts bool // Whether to run post-boot scripts
8- PlymouthTheme string // Plymouth theme to install (optional)8+ PlymouthTheme string // Plymouth theme to install (optional)
9 }9 }
M internal/application/commands/setup_repos.go +4 -4
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/packages"
44
55 // SetupRepositoriesCommand contains data for repository configuration
66 type SetupRepositoriesCommand struct {
7- MountPoint string // Root mount point
8- EnableMultilib bool // Enable multilib repository
9- EnableChaotic bool // Enable Chaotic-AUR repository
7+ MountPoint string // Root mount point
8+ EnableMultilib bool // Enable multilib repository
9+ EnableChaotic bool // Enable Chaotic-AUR repository
1010 AURHelper packages.AURHelper // AURHelperParu or AURHelperYay
11- AdditionalRepos []string // Additional repository URLs
11+ AdditionalRepos []string // Additional repository URLs
1212 }
@@ -4,9 +4,9 @@ import "github.com/bnema/archup/internal/domain/packages"
4 4
5 // SetupRepositoriesCommand contains data for repository configuration5 // SetupRepositoriesCommand contains data for repository configuration
6 type SetupRepositoriesCommand struct {6 type SetupRepositoriesCommand struct {
7- MountPoint string // Root mount point7+ MountPoint string // Root mount point
8- EnableMultilib bool // Enable multilib repository8+ EnableMultilib bool // Enable multilib repository
9- EnableChaotic bool // Enable Chaotic-AUR repository9+ EnableChaotic bool // Enable Chaotic-AUR repository
10 AURHelper packages.AURHelper // AURHelperParu or AURHelperYay10 AURHelper packages.AURHelper // AURHelperParu or AURHelperYay
11- AdditionalRepos []string // Additional repository URLs11+ AdditionalRepos []string // Additional repository URLs
12 }12 }
M internal/application/dto/installation_status.go +10 -10
@@ -4,16 +4,16 @@ import "time"
44
55 // InstallationStatus represents the overall installation status
66 type InstallationStatus struct {
7- ID string // Installation ID (UUID)
8- State string // Current state (NotStarted, PreflightChecks, etc.)
9- Hostname string // Configured hostname
10- Username string // Configured username
11- TargetDisk string // Target installation disk
12- EncryptionType string // Encryption type (none, LUKS, LUKS-LVM)
13- Progress int // Progress percentage (0-100)
7+ ID string // Installation ID (UUID)
8+ State string // Current state (NotStarted, PreflightChecks, etc.)
9+ Hostname string // Configured hostname
10+ Username string // Configured username
11+ TargetDisk string // Target installation disk
12+ EncryptionType string // Encryption type (none, LUKS, LUKS-LVM)
13+ Progress int // Progress percentage (0-100)
1414 StartedAt *time.Time // When installation started
1515 CompletedAt *time.Time // When installation completed
16- CurrentPhase string // Current phase name
17- LastError string // Last error message (if any)
18- EstimatedRemaining int // Estimated remaining time in seconds
16+ CurrentPhase string // Current phase name
17+ LastError string // Last error message (if any)
18+ EstimatedRemaining int // Estimated remaining time in seconds
1919 }
@@ -4,16 +4,16 @@ import "time"
4 4
5 // InstallationStatus represents the overall installation status5 // InstallationStatus represents the overall installation status
6 type InstallationStatus struct {6 type InstallationStatus struct {
7- ID string // Installation ID (UUID)7+ ID string // Installation ID (UUID)
8- State string // Current state (NotStarted, PreflightChecks, etc.)8+ State string // Current state (NotStarted, PreflightChecks, etc.)
9- Hostname string // Configured hostname9+ Hostname string // Configured hostname
10- Username string // Configured username10+ Username string // Configured username
11- TargetDisk string // Target installation disk11+ TargetDisk string // Target installation disk
12- EncryptionType string // Encryption type (none, LUKS, LUKS-LVM)12+ EncryptionType string // Encryption type (none, LUKS, LUKS-LVM)
13- Progress int // Progress percentage (0-100)13+ Progress int // Progress percentage (0-100)
14 StartedAt *time.Time // When installation started14 StartedAt *time.Time // When installation started
15 CompletedAt *time.Time // When installation completed15 CompletedAt *time.Time // When installation completed
16- CurrentPhase string // Current phase name16+ CurrentPhase string // Current phase name
17- LastError string // Last error message (if any)17+ LastError string // Last error message (if any)
18- EstimatedRemaining int // Estimated remaining time in seconds18+ EstimatedRemaining int // Estimated remaining time in seconds
19 }19 }
M internal/application/dto/preflight_result.go +3 -3
@@ -2,9 +2,9 @@ package dto
22
33 // SystemInfo contains basic system information
44 type SystemInfo struct {
5- Architecture string
6- IsUEFI bool
7- Distribution string
5+ Architecture string
6+ IsUEFI bool
7+ Distribution string
88 SecureBootEnabled bool
99 }
1010
@@ -2,9 +2,9 @@ package dto
2 2
3 // SystemInfo contains basic system information3 // SystemInfo contains basic system information
4 type SystemInfo struct {4 type SystemInfo struct {
5- Architecture string5+ Architecture string
6- IsUEFI bool6+ IsUEFI bool
7- Distribution string7+ Distribution string
8 SecureBootEnabled bool8 SecureBootEnabled bool
9 }9 }
10 10
M internal/application/dto/progress_update.go +7 -7
@@ -4,11 +4,11 @@ import "time"
44
55 // ProgressUpdate represents a progress update during installation
66 type ProgressUpdate struct {
7- Phase string // Current phase name
8- PhaseNumber int // Current phase number (1-8)
9- TotalPhases int // Total phases (8)
10- ProgressPercent int // Overall progress percentage (0-100)
11- Message string // Status message
12- IsError bool // Whether this is an error
13- Timestamp time.Time // When this update occurred
7+ Phase string // Current phase name
8+ PhaseNumber int // Current phase number (1-8)
9+ TotalPhases int // Total phases (8)
10+ ProgressPercent int // Overall progress percentage (0-100)
11+ Message string // Status message
12+ IsError bool // Whether this is an error
13+ Timestamp time.Time // When this update occurred
1414 }
@@ -4,11 +4,11 @@ import "time"
4 4
5 // ProgressUpdate represents a progress update during installation5 // ProgressUpdate represents a progress update during installation
6 type ProgressUpdate struct {6 type ProgressUpdate struct {
7- Phase string // Current phase name7+ Phase string // Current phase name
8- PhaseNumber int // Current phase number (1-8)8+ PhaseNumber int // Current phase number (1-8)
9- TotalPhases int // Total phases (8)9+ TotalPhases int // Total phases (8)
10- ProgressPercent int // Overall progress percentage (0-100)10+ ProgressPercent int // Overall progress percentage (0-100)
11- Message string // Status message11+ Message string // Status message
12- IsError bool // Whether this is an error12+ IsError bool // Whether this is an error
13- Timestamp time.Time // When this update occurred13+ Timestamp time.Time // When this update occurred
14 }14 }
M internal/application/handlers/bootloader_handler.go +5 -3
@@ -28,11 +28,12 @@ func NewBootloaderHandler(chrExec ports.ChrootExecutor, logger ports.Logger) *Bo
2828 func (h *BootloaderHandler) Handle(ctx context.Context, cmd commands.InstallBootloaderCommand) (*dto.BootloaderResult, error) {
2929 h.logger.Info("Starting bootloader installation", "type", cmd.BootloaderType)
3030
31+ h.logger.Info("Validating bootloader configuration...")
3132 result := &dto.BootloaderResult{
32- Success: false,
33+ Success: false,
3334 BootloaderType: "",
34- Timeout: cmd.TimeoutSeconds,
35- ErrorDetail: "",
35+ Timeout: cmd.TimeoutSeconds,
36+ ErrorDetail: "",
3637 }
3738
3839 // Create bootloader domain object
@@ -46,6 +47,7 @@ func (h *BootloaderHandler) Handle(ctx context.Context, cmd commands.InstallBoot
4647 h.logger.Info("Bootloader configuration validated", "type", bl.Type())
4748
4849 // In a real implementation, this would configure and install the bootloader
50+ h.logger.Info("Installing bootloader...", "type", bl.Type())
4951 // For Limine: configure limine.cfg
5052 // For systemd-boot: configure bootctl and entry files
5153
@@ -28,11 +28,12 @@ func NewBootloaderHandler(chrExec ports.ChrootExecutor, logger ports.Logger) *Bo
28 func (h *BootloaderHandler) Handle(ctx context.Context, cmd commands.InstallBootloaderCommand) (*dto.BootloaderResult, error) {28 func (h *BootloaderHandler) Handle(ctx context.Context, cmd commands.InstallBootloaderCommand) (*dto.BootloaderResult, error) {
29 h.logger.Info("Starting bootloader installation", "type", cmd.BootloaderType)29 h.logger.Info("Starting bootloader installation", "type", cmd.BootloaderType)
30 30
31+ h.logger.Info("Validating bootloader configuration...")
31 result := &dto.BootloaderResult{32 result := &dto.BootloaderResult{
32- Success: false,33+ Success: false,
33 BootloaderType: "",34 BootloaderType: "",
34- Timeout: cmd.TimeoutSeconds,35+ Timeout: cmd.TimeoutSeconds,
35- ErrorDetail: "",36+ ErrorDetail: "",
36 }37 }
37 38
38 // Create bootloader domain object39 // Create bootloader domain object
@@ -46,6 +47,7 @@ func (h *BootloaderHandler) Handle(ctx context.Context, cmd commands.InstallBoot
46 h.logger.Info("Bootloader configuration validated", "type", bl.Type())47 h.logger.Info("Bootloader configuration validated", "type", bl.Type())
47 48
48 // In a real implementation, this would configure and install the bootloader49 // In a real implementation, this would configure and install the bootloader
50+ h.logger.Info("Installing bootloader...", "type", bl.Type())
49 // For Limine: configure limine.cfg51 // For Limine: configure limine.cfg
50 // For systemd-boot: configure bootctl and entry files52 // For systemd-boot: configure bootctl and entry files
51 53
M internal/application/handlers/install_base_handler.go +6 -6
@@ -12,10 +12,10 @@ import (
1212
1313 // InstallBaseHandler handles base system installation
1414 type InstallBaseHandler struct {
15- fs ports.FileSystem
16- cmdExec ports.CommandExecutor
17- chrExec ports.ChrootExecutor
18- logger ports.Logger
15+ fs ports.FileSystem
16+ cmdExec ports.CommandExecutor
17+ chrExec ports.ChrootExecutor
18+ logger ports.Logger
1919 }
2020
2121 // NewInstallBaseHandler creates a new base installation handler
@@ -33,9 +33,9 @@ func (h *InstallBaseHandler) Handle(ctx context.Context, cmd commands.InstallBas
3333 h.logger.Info("Starting base system installation", "kernel", cmd.KernelVariant)
3434
3535 result := &dto.InstallBaseResult{
36- Success: false,
36+ Success: false,
3737 PackagesInstalled: []string{},
38- ErrorDetail: "",
38+ ErrorDetail: "",
3939 }
4040
4141 // Validate kernel variant
@@ -12,10 +12,10 @@ import (
12 12
13 // InstallBaseHandler handles base system installation13 // InstallBaseHandler handles base system installation
14 type InstallBaseHandler struct {14 type InstallBaseHandler struct {
15- fs ports.FileSystem15+ fs ports.FileSystem
16- cmdExec ports.CommandExecutor16+ cmdExec ports.CommandExecutor
17- chrExec ports.ChrootExecutor17+ chrExec ports.ChrootExecutor
18- logger ports.Logger18+ logger ports.Logger
19 }19 }
20 20
21 // NewInstallBaseHandler creates a new base installation handler21 // NewInstallBaseHandler creates a new base installation handler
@@ -33,9 +33,9 @@ func (h *InstallBaseHandler) Handle(ctx context.Context, cmd commands.InstallBas
33 h.logger.Info("Starting base system installation", "kernel", cmd.KernelVariant)33 h.logger.Info("Starting base system installation", "kernel", cmd.KernelVariant)
34 34
35 result := &dto.InstallBaseResult{35 result := &dto.InstallBaseResult{
36- Success: false,36+ Success: false,
37 PackagesInstalled: []string{},37 PackagesInstalled: []string{},
38- ErrorDetail: "",38+ ErrorDetail: "",
39 }39 }
40 40
41 // Validate kernel variant41 // Validate kernel variant
M internal/application/handlers/partition_handler_test.go +10 -10
@@ -73,11 +73,11 @@ func TestPartitionHandler_Handle_InvalidDisk(t *testing.T) {
7373 handler := NewPartitionHandler(mockExec, mockLogger)
7474
7575 cmd := commands.PartitionDiskCommand{
76- TargetDisk: "",
77- RootSizeGB: 50,
78- BootSizeGB: 1,
79- EncryptionType: disk.EncryptionTypeNone,
80- FilesystemType: disk.FilesystemExt4,
76+ TargetDisk: "",
77+ RootSizeGB: 50,
78+ BootSizeGB: 1,
79+ EncryptionType: disk.EncryptionTypeNone,
80+ FilesystemType: disk.FilesystemExt4,
8181 }
8282
8383 result, err := handler.Handle(context.Background(), cmd)
@@ -104,11 +104,11 @@ func TestPartitionHandler_Handle_RootPartitionTooSmall(t *testing.T) {
104104 handler := NewPartitionHandler(mockExec, mockLogger)
105105
106106 cmd := commands.PartitionDiskCommand{
107- TargetDisk: "/dev/sda",
108- RootSizeGB: 1, // Too small
109- BootSizeGB: 1,
110- EncryptionType: disk.EncryptionTypeNone,
111- FilesystemType: disk.FilesystemExt4,
107+ TargetDisk: "/dev/sda",
108+ RootSizeGB: 1, // Too small
109+ BootSizeGB: 1,
110+ EncryptionType: disk.EncryptionTypeNone,
111+ FilesystemType: disk.FilesystemExt4,
112112 }
113113
114114 result, err := handler.Handle(context.Background(), cmd)
@@ -73,11 +73,11 @@ func TestPartitionHandler_Handle_InvalidDisk(t *testing.T) {
73 handler := NewPartitionHandler(mockExec, mockLogger)73 handler := NewPartitionHandler(mockExec, mockLogger)
74 74
75 cmd := commands.PartitionDiskCommand{75 cmd := commands.PartitionDiskCommand{
76- TargetDisk: "",76+ TargetDisk: "",
77- RootSizeGB: 50,77+ RootSizeGB: 50,
78- BootSizeGB: 1,78+ BootSizeGB: 1,
79- EncryptionType: disk.EncryptionTypeNone,79+ EncryptionType: disk.EncryptionTypeNone,
80- FilesystemType: disk.FilesystemExt4,80+ FilesystemType: disk.FilesystemExt4,
81 }81 }
82 82
83 result, err := handler.Handle(context.Background(), cmd)83 result, err := handler.Handle(context.Background(), cmd)
@@ -104,11 +104,11 @@ func TestPartitionHandler_Handle_RootPartitionTooSmall(t *testing.T) {
104 handler := NewPartitionHandler(mockExec, mockLogger)104 handler := NewPartitionHandler(mockExec, mockLogger)
105 105
106 cmd := commands.PartitionDiskCommand{106 cmd := commands.PartitionDiskCommand{
107- TargetDisk: "/dev/sda",107+ TargetDisk: "/dev/sda",
108- RootSizeGB: 1, // Too small108+ RootSizeGB: 1, // Too small
109- BootSizeGB: 1,109+ BootSizeGB: 1,
110- EncryptionType: disk.EncryptionTypeNone,110+ EncryptionType: disk.EncryptionTypeNone,
111- FilesystemType: disk.FilesystemExt4,111+ FilesystemType: disk.FilesystemExt4,
112 }112 }
113 113
114 result, err := handler.Handle(context.Background(), cmd)114 result, err := handler.Handle(context.Background(), cmd)
M internal/application/handlers/post_install_handler.go +6 -6
@@ -11,17 +11,17 @@ import (
1111
1212 // PostInstallHandler handles post-installation tasks
1313 type PostInstallHandler struct {
14- chrExec ports.ChrootExecutor
14+ chrExec ports.ChrootExecutor
1515 scriptExec ports.ScriptExecutor
16- logger ports.Logger
16+ logger ports.Logger
1717 }
1818
1919 // NewPostInstallHandler creates a new post-installation handler
2020 func NewPostInstallHandler(chrExec ports.ChrootExecutor, scriptExec ports.ScriptExecutor, logger ports.Logger) *PostInstallHandler {
2121 return &PostInstallHandler{
22- chrExec: chrExec,
22+ chrExec: chrExec,
2323 scriptExec: scriptExec,
24- logger: logger,
24+ logger: logger,
2525 }
2626 }
2727
@@ -30,8 +30,8 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal
3030 h.logger.Info("Starting post-installation tasks", "username", cmd.Username)
3131
3232 result := &dto.PostInstallResult{
33- Success: false,
34- TasksRun: []string{},
33+ Success: false,
34+ TasksRun: []string{},
3535 ErrorDetail: "",
3636 }
3737
@@ -11,17 +11,17 @@ import (
11 11
12 // PostInstallHandler handles post-installation tasks12 // PostInstallHandler handles post-installation tasks
13 type PostInstallHandler struct {13 type PostInstallHandler struct {
14- chrExec ports.ChrootExecutor14+ chrExec ports.ChrootExecutor
15 scriptExec ports.ScriptExecutor15 scriptExec ports.ScriptExecutor
16- logger ports.Logger16+ logger ports.Logger
17 }17 }
18 18
19 // NewPostInstallHandler creates a new post-installation handler19 // NewPostInstallHandler creates a new post-installation handler
20 func NewPostInstallHandler(chrExec ports.ChrootExecutor, scriptExec ports.ScriptExecutor, logger ports.Logger) *PostInstallHandler {20 func NewPostInstallHandler(chrExec ports.ChrootExecutor, scriptExec ports.ScriptExecutor, logger ports.Logger) *PostInstallHandler {
21 return &PostInstallHandler{21 return &PostInstallHandler{
22- chrExec: chrExec,22+ chrExec: chrExec,
23 scriptExec: scriptExec,23 scriptExec: scriptExec,
24- logger: logger,24+ logger: logger,
25 }25 }
26 }26 }
27 27
@@ -30,8 +30,8 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal
30 h.logger.Info("Starting post-installation tasks", "username", cmd.Username)30 h.logger.Info("Starting post-installation tasks", "username", cmd.Username)
31 31
32 result := &dto.PostInstallResult{32 result := &dto.PostInstallResult{
33- Success: false,33+ Success: false,
34- TasksRun: []string{},34+ TasksRun: []string{},
35 ErrorDetail: "",35 ErrorDetail: "",
36 }36 }
37 37
M internal/application/handlers/preflight_handler.go +4 -4
@@ -12,10 +12,10 @@ import (
1212
1313 // PreflightHandler handles preflight checks
1414 type PreflightHandler struct {
15- fs ports.FileSystem
16- cmdExec ports.CommandExecutor
17- logger ports.Logger
18- rules *system.SystemValidationRules
15+ fs ports.FileSystem
16+ cmdExec ports.CommandExecutor
17+ logger ports.Logger
18+ rules *system.SystemValidationRules
1919 }
2020
2121 // NewPreflightHandler creates a new preflight handler
@@ -12,10 +12,10 @@ import (
12 12
13 // PreflightHandler handles preflight checks13 // PreflightHandler handles preflight checks
14 type PreflightHandler struct {14 type PreflightHandler struct {
15- fs ports.FileSystem15+ fs ports.FileSystem
16- cmdExec ports.CommandExecutor16+ cmdExec ports.CommandExecutor
17- logger ports.Logger17+ logger ports.Logger
18- rules *system.SystemValidationRules18+ rules *system.SystemValidationRules
19 }19 }
20 20
21 // NewPreflightHandler creates a new preflight handler21 // NewPreflightHandler creates a new preflight handler
M internal/application/handlers/repos_handler.go +5 -5
@@ -29,11 +29,11 @@ func (h *ReposHandler) Handle(ctx context.Context, cmd commands.SetupRepositorie
2929 h.logger.Info("Starting repository configuration", "multilib", cmd.EnableMultilib, "chaotic", cmd.EnableChaotic)
3030
3131 result := &dto.RepositoriesResult{
32- Success: false,
33- Multilib: cmd.EnableMultilib,
34- Chaotic: cmd.EnableChaotic,
35- AURHelper: "",
36- ErrorDetail: "",
32+ Success: false,
33+ Multilib: cmd.EnableMultilib,
34+ Chaotic: cmd.EnableChaotic,
35+ AURHelper: "",
36+ ErrorDetail: "",
3737 }
3838
3939 // Create repository domain object
@@ -29,11 +29,11 @@ func (h *ReposHandler) Handle(ctx context.Context, cmd commands.SetupRepositorie
29 h.logger.Info("Starting repository configuration", "multilib", cmd.EnableMultilib, "chaotic", cmd.EnableChaotic)29 h.logger.Info("Starting repository configuration", "multilib", cmd.EnableMultilib, "chaotic", cmd.EnableChaotic)
30 30
31 result := &dto.RepositoriesResult{31 result := &dto.RepositoriesResult{
32- Success: false,32+ Success: false,
33- Multilib: cmd.EnableMultilib,33+ Multilib: cmd.EnableMultilib,
34- Chaotic: cmd.EnableChaotic,34+ Chaotic: cmd.EnableChaotic,
35- AURHelper: "",35+ AURHelper: "",
36- ErrorDetail: "",36+ ErrorDetail: "",
37 }37 }
38 38
39 // Create repository domain object39 // Create repository domain object
M internal/application/services/installation_service.go +17 -17
@@ -18,13 +18,13 @@ type InstallationService struct {
1818 installAgg *installation.Installation
1919
2020 // Handlers
21- preflightHandler *handlers.PreflightHandler
22- partitionHandler *handlers.PartitionHandler
23- baseHandler *handlers.InstallBaseHandler
24- configHandler *handlers.ConfigureSystemHandler
25- bootloaderHandler *handlers.BootloaderHandler
26- reposHandler *handlers.ReposHandler
27- postInstallHandler *handlers.PostInstallHandler
21+ preflightHandler *handlers.PreflightHandler
22+ partitionHandler *handlers.PartitionHandler
23+ baseHandler *handlers.InstallBaseHandler
24+ configHandler *handlers.ConfigureSystemHandler
25+ bootloaderHandler *handlers.BootloaderHandler
26+ reposHandler *handlers.ReposHandler
27+ postInstallHandler *handlers.PostInstallHandler
2828
2929 // Ports
3030 repo ports.InstallationRepository
@@ -50,16 +50,16 @@ func NewInstallationService(
5050 postInstallHandler *handlers.PostInstallHandler,
5151 ) *InstallationService {
5252 return &InstallationService{
53- repo: repo,
54- logger: logger,
55- preflightHandler: preflightHandler,
56- partitionHandler: partitionHandler,
57- baseHandler: baseHandler,
58- configHandler: configHandler,
59- bootloaderHandler: bootloaderHandler,
60- reposHandler: reposHandler,
61- postInstallHandler: postInstallHandler,
62- tracker: NewProgressTracker(),
53+ repo: repo,
54+ logger: logger,
55+ preflightHandler: preflightHandler,
56+ partitionHandler: partitionHandler,
57+ baseHandler: baseHandler,
58+ configHandler: configHandler,
59+ bootloaderHandler: bootloaderHandler,
60+ reposHandler: reposHandler,
61+ postInstallHandler: postInstallHandler,
62+ tracker: NewProgressTracker(),
6363 }
6464 }
6565
@@ -18,13 +18,13 @@ type InstallationService struct {
18 installAgg *installation.Installation18 installAgg *installation.Installation
19 19
20 // Handlers20 // Handlers
21- preflightHandler *handlers.PreflightHandler21+ preflightHandler *handlers.PreflightHandler
22- partitionHandler *handlers.PartitionHandler22+ partitionHandler *handlers.PartitionHandler
23- baseHandler *handlers.InstallBaseHandler23+ baseHandler *handlers.InstallBaseHandler
24- configHandler *handlers.ConfigureSystemHandler24+ configHandler *handlers.ConfigureSystemHandler
25- bootloaderHandler *handlers.BootloaderHandler25+ bootloaderHandler *handlers.BootloaderHandler
26- reposHandler *handlers.ReposHandler26+ reposHandler *handlers.ReposHandler
27- postInstallHandler *handlers.PostInstallHandler27+ postInstallHandler *handlers.PostInstallHandler
28 28
29 // Ports29 // Ports
30 repo ports.InstallationRepository30 repo ports.InstallationRepository
@@ -50,16 +50,16 @@ func NewInstallationService(
50 postInstallHandler *handlers.PostInstallHandler,50 postInstallHandler *handlers.PostInstallHandler,
51 ) *InstallationService {51 ) *InstallationService {
52 return &InstallationService{52 return &InstallationService{
53- repo: repo,53+ repo: repo,
54- logger: logger,54+ logger: logger,
55- preflightHandler: preflightHandler,55+ preflightHandler: preflightHandler,
56- partitionHandler: partitionHandler,56+ partitionHandler: partitionHandler,
57- baseHandler: baseHandler,57+ baseHandler: baseHandler,
58- configHandler: configHandler,58+ configHandler: configHandler,
59- bootloaderHandler: bootloaderHandler,59+ bootloaderHandler: bootloaderHandler,
60- reposHandler: reposHandler,60+ reposHandler: reposHandler,
61- postInstallHandler: postInstallHandler,61+ postInstallHandler: postInstallHandler,
62- tracker: NewProgressTracker(),62+ tracker: NewProgressTracker(),
63 }63 }
64 }64 }
65 65
M internal/application/services/installation_service_test.go +5 -5
@@ -180,11 +180,11 @@ func TestInstallationService_RunPartition(t *testing.T) {
180180 service.Start(ctx, "myarch", "testuser", "/dev/sda", "none")
181181
182182 cmd := commands.PartitionDiskCommand{
183- TargetDisk: "/dev/sda",
184- RootSizeGB: 50,
185- BootSizeGB: 1,
186- EncryptionType: disk.EncryptionTypeNone,
187- FilesystemType: disk.FilesystemExt4,
183+ TargetDisk: "/dev/sda",
184+ RootSizeGB: 50,
185+ BootSizeGB: 1,
186+ EncryptionType: disk.EncryptionTypeNone,
187+ FilesystemType: disk.FilesystemExt4,
188188 }
189189
190190 result, err := service.RunPartition(ctx, cmd)
@@ -180,11 +180,11 @@ func TestInstallationService_RunPartition(t *testing.T) {
180 service.Start(ctx, "myarch", "testuser", "/dev/sda", "none")180 service.Start(ctx, "myarch", "testuser", "/dev/sda", "none")
181 181
182 cmd := commands.PartitionDiskCommand{182 cmd := commands.PartitionDiskCommand{
183- TargetDisk: "/dev/sda",183+ TargetDisk: "/dev/sda",
184- RootSizeGB: 50,184+ RootSizeGB: 50,
185- BootSizeGB: 1,185+ BootSizeGB: 1,
186- EncryptionType: disk.EncryptionTypeNone,186+ EncryptionType: disk.EncryptionTypeNone,
187- FilesystemType: disk.FilesystemExt4,187+ FilesystemType: disk.FilesystemExt4,
188 }188 }
189 189
190 result, err := service.RunPartition(ctx, cmd)190 result, err := service.RunPartition(ctx, cmd)
M internal/config/config.go +52 -53
@@ -19,12 +19,12 @@ const (
1919 LimineConfigTemplate = "configs/limine.conf.template"
2020 ChaoticConfigFile = "configs/chaotic-aur.conf"
2121 StarshipConfigTemplate = "configs/shell/starship.toml"
22- ShellConfigTemplate = "configs/shell/shell"
23- ShellInitTemplate = "configs/shell/init"
24- ShellAliasesTemplate = "configs/shell/aliases"
25- ShellEnvsTemplate = "configs/shell/envs"
26- ShellRcTemplate = "configs/shell/rc"
27- BashrcTemplate = "configs/shell/bashrc"
22+ ShellConfigTemplate = "configs/shell/shell"
23+ ShellInitTemplate = "configs/shell/init"
24+ ShellAliasesTemplate = "configs/shell/aliases"
25+ ShellEnvsTemplate = "configs/shell/envs"
26+ ShellRcTemplate = "configs/shell/rc"
27+ BashrcTemplate = "configs/shell/bashrc"
2828 )
2929
3030 // Encryption types
@@ -36,7 +36,7 @@ const (
3636
3737 // Bootloader types
3838 const (
39- BootloaderLimine = "limine"
39+ BootloaderLimine = "limine"
4040 BootloaderSystemdBoot = "systemd-boot"
4141 )
4242
@@ -49,7 +49,6 @@ const (
4949 KernelLinuxCachyOS = "linux-cachyos"
5050 )
5151
52-
5352 // System paths
5453 const (
5554 PathMnt = "/mnt"
@@ -89,10 +88,10 @@ const (
8988
9089 // Locale defaults
9190 const (
92- LocaleDefault = "en_US.UTF-8"
93- LocaleDefaultGen = "en_US.UTF-8 UTF-8"
94- TimezoneDefault = ""
95- KeymapDefault = "us"
91+ LocaleDefault = "en_US.UTF-8"
92+ LocaleDefaultGen = "en_US.UTF-8 UTF-8"
93+ TimezoneDefault = ""
94+ KeymapDefault = "us"
9695 )
9796
9897 // Zram configuration
@@ -116,18 +115,19 @@ const (
116115
117116 // Boot paths
118117 const (
119- PathMntBoot = "/mnt/boot"
120- PathMntBootEFI = "/mnt/boot/EFI"
121- PathMntBootEFILimine = "/mnt/boot/EFI/limine"
122- PathMntEtcMkinitcpio = "/mnt/etc/mkinitcpio.conf"
123- PathUsrShareLimine = "/mnt/usr/share/limine"
124- FileLimineBootloader = "BOOTX64.EFI"
125- FileLimineConfig = "limine.conf"
118+ PathMntBoot = "/mnt/boot"
119+ PathMntBootEFI = "/mnt/boot/EFI"
120+ PathMntBootEFILimine = "/mnt/boot/EFI/limine"
121+ PathMntBootLimineConf = "/mnt/boot/limine.conf"
122+ PathMntEtcMkinitcpio = "/mnt/etc/mkinitcpio.conf"
123+ PathUsrShareLimine = "/mnt/usr/share/limine"
124+ FileLimineBootloader = "BOOTX64.EFI"
125+ FileLimineConfig = "limine.conf"
126126 )
127127
128128 // Mkinitcpio hooks
129129 const (
130- MkinitcpioHooksPlymouth = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth filesystems fsck)"
130+ MkinitcpioHooksPlymouth = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth filesystems fsck)"
131131 MkinitcpioHooksEncrypted = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth encrypt filesystems fsck)"
132132 )
133133
@@ -155,16 +155,15 @@ const (
155155 PathMntEtcPacmanConf = "/mnt/etc/pacman.conf"
156156 )
157157
158-
159158 // PostInstall paths
160159 const (
161- PathMntBootLogo = "/mnt/boot/arch-logo.png"
162- PathMntPlymouthThemes = "/mnt/usr/share/plymouth/themes"
163- PathMntEtcDefaultLimine = "/mnt/etc/default/limine"
164- PathMntEtcPacmanDHooks = "/mnt/etc/pacman.d/hooks"
165- PathBootEFILimineConf = "/boot/EFI/limine/limine.conf"
166- ArchLogoURL = "assets/Arch_Linux__Crystal__icon.png"
167- PlymouthThemeName = "archup"
160+ PathMntBootLogo = "/mnt/boot/arch-logo.png"
161+ PathMntPlymouthThemes = "/mnt/usr/share/plymouth/themes"
162+ PathMntEtcDefaultLimine = "/mnt/etc/default/limine"
163+ PathMntEtcPacmanDHooks = "/mnt/etc/pacman.d/hooks"
164+ PathBootLimineConf = "/boot/limine.conf"
165+ ArchLogoURL = "assets/Arch_Linux__Crystal__icon.png"
166+ PlymouthThemeName = "archup"
168167 )
169168
170169 // Plymouth files
@@ -203,16 +202,16 @@ const PostBootServiceTemplate = "install/mandatory/post-boot/archup-first-boot.s
203202 // This mirrors the shell script's config format for compatibility
204203 type Config struct {
205204 // Preflight
206- Hostname string
207- Username string
208- UserPassword string
209- RootPassword string
210- Email string // Optional, for git and SSH configuration
211- Keymap string
212- Timezone string
213- Locale string
214- Bootloader string // "limine" or "systemd-boot"
215- EncryptionType string // "none", "luks", or "luks-lvm"
205+ Hostname string
206+ Username string
207+ UserPassword string
208+ RootPassword string
209+ Email string // Optional, for git and SSH configuration
210+ Keymap string
211+ Timezone string
212+ Locale string
213+ Bootloader string // "limine" or "systemd-boot"
214+ EncryptionType string // "none", "luks", or "luks-lvm"
216215 EncryptPassword string // Separate encryption password if different from user password
217216
218217 // Form-only fields (not persisted)
@@ -220,18 +219,18 @@ type Config struct {
220219 UseSamePasswordForEncryption bool // Checkbox state for using same password for encryption
221220
222221 // Partitioning
223- TargetDisk string
224- BootPartition string
225- RootPartition string
226- SwapPartition string
227- EFIPartition string
228- CryptDevice string // /dev/mapper/cryptroot if encrypted
222+ TargetDisk string
223+ BootPartition string
224+ RootPartition string
225+ SwapPartition string
226+ EFIPartition string
227+ CryptDevice string // /dev/mapper/cryptroot if encrypted
229228
230229 // Base
231- KernelChoice string // "linux", "linux-zen", "linux-lts", "linux-hardened"
232- Microcode string // "intel-ucode" or "amd-ucode"
233- CPUVendor string // "Intel", "AMD", or "Unknown"
234- AMDPState string // "active", "passive", "guided", or empty
230+ KernelChoice string // "linux", "linux-zen", "linux-lts", "linux-hardened"
231+ Microcode string // "intel-ucode" or "amd-ucode"
232+ CPUVendor string // "Intel", "AMD", or "Unknown"
233+ AMDPState string // "active", "passive", "guided", or empty
235234
236235 // Config
237236 NetworkManager string // "NetworkManager" by default
@@ -242,11 +241,11 @@ type Config struct {
242241 EnableChaotic bool
243242
244243 // Paths
245- ConfigPath string
246- LogPath string
247- InstallPath string // ~/.local/share/archup/install
248- RepoURL string
249- RawURL string
244+ ConfigPath string
245+ LogPath string
246+ InstallPath string // ~/.local/share/archup/install
247+ RepoURL string
248+ RawURL string
250249 }
251250
252251 // NewConfig creates a new Config with sensible defaults
@@ -19,12 +19,12 @@ const (
19 LimineConfigTemplate = "configs/limine.conf.template"19 LimineConfigTemplate = "configs/limine.conf.template"
20 ChaoticConfigFile = "configs/chaotic-aur.conf"20 ChaoticConfigFile = "configs/chaotic-aur.conf"
21 StarshipConfigTemplate = "configs/shell/starship.toml"21 StarshipConfigTemplate = "configs/shell/starship.toml"
22- ShellConfigTemplate = "configs/shell/shell"22+ ShellConfigTemplate = "configs/shell/shell"
23- ShellInitTemplate = "configs/shell/init"23+ ShellInitTemplate = "configs/shell/init"
24- ShellAliasesTemplate = "configs/shell/aliases"24+ ShellAliasesTemplate = "configs/shell/aliases"
25- ShellEnvsTemplate = "configs/shell/envs"25+ ShellEnvsTemplate = "configs/shell/envs"
26- ShellRcTemplate = "configs/shell/rc"26+ ShellRcTemplate = "configs/shell/rc"
27- BashrcTemplate = "configs/shell/bashrc"27+ BashrcTemplate = "configs/shell/bashrc"
28 )28 )
29 29
30 // Encryption types30 // Encryption types
@@ -36,7 +36,7 @@ const (
36 36
37 // Bootloader types37 // Bootloader types
38 const (38 const (
39- BootloaderLimine = "limine"39+ BootloaderLimine = "limine"
40 BootloaderSystemdBoot = "systemd-boot"40 BootloaderSystemdBoot = "systemd-boot"
41 )41 )
42 42
@@ -49,7 +49,6 @@ const (
49 KernelLinuxCachyOS = "linux-cachyos"49 KernelLinuxCachyOS = "linux-cachyos"
50 )50 )
51 51
52-
53 // System paths52 // System paths
54 const (53 const (
55 PathMnt = "/mnt"54 PathMnt = "/mnt"
@@ -89,10 +88,10 @@ const (
89 88
90 // Locale defaults89 // Locale defaults
91 const (90 const (
92- LocaleDefault = "en_US.UTF-8"91+ LocaleDefault = "en_US.UTF-8"
93- LocaleDefaultGen = "en_US.UTF-8 UTF-8"92+ LocaleDefaultGen = "en_US.UTF-8 UTF-8"
94- TimezoneDefault = ""93+ TimezoneDefault = ""
95- KeymapDefault = "us"94+ KeymapDefault = "us"
96 )95 )
97 96
98 // Zram configuration97 // Zram configuration
@@ -116,18 +115,19 @@ const (
116 115
117 // Boot paths116 // Boot paths
118 const (117 const (
119- PathMntBoot = "/mnt/boot"118+ PathMntBoot = "/mnt/boot"
120- PathMntBootEFI = "/mnt/boot/EFI"119+ PathMntBootEFI = "/mnt/boot/EFI"
121- PathMntBootEFILimine = "/mnt/boot/EFI/limine"120+ PathMntBootEFILimine = "/mnt/boot/EFI/limine"
122- PathMntEtcMkinitcpio = "/mnt/etc/mkinitcpio.conf"121+ PathMntBootLimineConf = "/mnt/boot/limine.conf"
123- PathUsrShareLimine = "/mnt/usr/share/limine"122+ PathMntEtcMkinitcpio = "/mnt/etc/mkinitcpio.conf"
124- FileLimineBootloader = "BOOTX64.EFI"123+ PathUsrShareLimine = "/mnt/usr/share/limine"
125- FileLimineConfig = "limine.conf"124+ FileLimineBootloader = "BOOTX64.EFI"
125+ FileLimineConfig = "limine.conf"
126 )126 )
127 127
128 // Mkinitcpio hooks128 // Mkinitcpio hooks
129 const (129 const (
130- MkinitcpioHooksPlymouth = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth filesystems fsck)"130+ MkinitcpioHooksPlymouth = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth filesystems fsck)"
131 MkinitcpioHooksEncrypted = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth encrypt filesystems fsck)"131 MkinitcpioHooksEncrypted = "HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block plymouth encrypt filesystems fsck)"
132 )132 )
133 133
@@ -155,16 +155,15 @@ const (
155 PathMntEtcPacmanConf = "/mnt/etc/pacman.conf"155 PathMntEtcPacmanConf = "/mnt/etc/pacman.conf"
156 )156 )
157 157
158-
159 // PostInstall paths158 // PostInstall paths
160 const (159 const (
161- PathMntBootLogo = "/mnt/boot/arch-logo.png"160+ PathMntBootLogo = "/mnt/boot/arch-logo.png"
162- PathMntPlymouthThemes = "/mnt/usr/share/plymouth/themes"161+ PathMntPlymouthThemes = "/mnt/usr/share/plymouth/themes"
163- PathMntEtcDefaultLimine = "/mnt/etc/default/limine"162+ PathMntEtcDefaultLimine = "/mnt/etc/default/limine"
164- PathMntEtcPacmanDHooks = "/mnt/etc/pacman.d/hooks"163+ PathMntEtcPacmanDHooks = "/mnt/etc/pacman.d/hooks"
165- PathBootEFILimineConf = "/boot/EFI/limine/limine.conf"164+ PathBootLimineConf = "/boot/limine.conf"
166- ArchLogoURL = "assets/Arch_Linux__Crystal__icon.png"165+ ArchLogoURL = "assets/Arch_Linux__Crystal__icon.png"
167- PlymouthThemeName = "archup"166+ PlymouthThemeName = "archup"
168 )167 )
169 168
170 // Plymouth files169 // Plymouth files
@@ -203,16 +202,16 @@ const PostBootServiceTemplate = "install/mandatory/post-boot/archup-first-boot.s
203 // This mirrors the shell script's config format for compatibility202 // This mirrors the shell script's config format for compatibility
204 type Config struct {203 type Config struct {
205 // Preflight204 // Preflight
206- Hostname string205+ Hostname string
207- Username string206+ Username string
208- UserPassword string207+ UserPassword string
209- RootPassword string208+ RootPassword string
210- Email string // Optional, for git and SSH configuration209+ Email string // Optional, for git and SSH configuration
211- Keymap string210+ Keymap string
212- Timezone string211+ Timezone string
213- Locale string212+ Locale string
214- Bootloader string // "limine" or "systemd-boot"213+ Bootloader string // "limine" or "systemd-boot"
215- EncryptionType string // "none", "luks", or "luks-lvm"214+ EncryptionType string // "none", "luks", or "luks-lvm"
216 EncryptPassword string // Separate encryption password if different from user password215 EncryptPassword string // Separate encryption password if different from user password
217 216
218 // Form-only fields (not persisted)217 // Form-only fields (not persisted)
@@ -220,18 +219,18 @@ type Config struct {
220 UseSamePasswordForEncryption bool // Checkbox state for using same password for encryption219 UseSamePasswordForEncryption bool // Checkbox state for using same password for encryption
221 220
222 // Partitioning221 // Partitioning
223- TargetDisk string222+ TargetDisk string
224- BootPartition string223+ BootPartition string
225- RootPartition string224+ RootPartition string
226- SwapPartition string225+ SwapPartition string
227- EFIPartition string226+ EFIPartition string
228- CryptDevice string // /dev/mapper/cryptroot if encrypted227+ CryptDevice string // /dev/mapper/cryptroot if encrypted
229 228
230 // Base229 // Base
231- KernelChoice string // "linux", "linux-zen", "linux-lts", "linux-hardened"230+ KernelChoice string // "linux", "linux-zen", "linux-lts", "linux-hardened"
232- Microcode string // "intel-ucode" or "amd-ucode"231+ Microcode string // "intel-ucode" or "amd-ucode"
233- CPUVendor string // "Intel", "AMD", or "Unknown"232+ CPUVendor string // "Intel", "AMD", or "Unknown"
234- AMDPState string // "active", "passive", "guided", or empty233+ AMDPState string // "active", "passive", "guided", or empty
235 234
236 // Config235 // Config
237 NetworkManager string // "NetworkManager" by default236 NetworkManager string // "NetworkManager" by default
@@ -242,11 +241,11 @@ type Config struct {
242 EnableChaotic bool241 EnableChaotic bool
243 242
244 // Paths243 // Paths
245- ConfigPath string244+ ConfigPath string
246- LogPath string245+ LogPath string
247- InstallPath string // ~/.local/share/archup/install246+ InstallPath string // ~/.local/share/archup/install
248- RepoURL string247+ RepoURL string
249- RawURL string248+ RawURL string
250 }249 }
251 250
252 // NewConfig creates a new Config with sensible defaults251 // NewConfig creates a new Config with sensible defaults
M internal/domain/bootloader/bootloader.go +4 -4
@@ -25,10 +25,10 @@ func (b BootloaderType) String() string {
2525
2626 // Bootloader is an immutable value object representing bootloader configuration
2727 type Bootloader struct {
28- bootType BootloaderType
29- timeout int // seconds
30- branding string
31- efiPath string
28+ bootType BootloaderType
29+ timeout int // seconds
30+ branding string
31+ efiPath string
3232 }
3333
3434 // NewBootloader creates a new Bootloader value object with validation
@@ -25,10 +25,10 @@ func (b BootloaderType) String() string {
25 25
26 // Bootloader is an immutable value object representing bootloader configuration26 // Bootloader is an immutable value object representing bootloader configuration
27 type Bootloader struct {27 type Bootloader struct {
28- bootType BootloaderType28+ bootType BootloaderType
29- timeout int // seconds29+ timeout int // seconds
30- branding string30+ branding string
31- efiPath string31+ efiPath string
32 }32 }
33 33
34 // NewBootloader creates a new Bootloader value object with validation34 // NewBootloader creates a new Bootloader value object with validation
M internal/domain/bootloader/bootloader_test.go +2 -2
@@ -26,8 +26,8 @@ func TestNewBootloader_Valid(t *testing.T) {
2626
2727 func TestNewBootloader_InvalidTimeout(t *testing.T) {
2828 tests := []struct {
29- name string
30- timeout int
29+ name string
30+ timeout int
3131 shouldErr bool
3232 }{
3333 {"negative timeout", -1, true},
@@ -26,8 +26,8 @@ func TestNewBootloader_Valid(t *testing.T) {
26 26
27 func TestNewBootloader_InvalidTimeout(t *testing.T) {27 func TestNewBootloader_InvalidTimeout(t *testing.T) {
28 tests := []struct {28 tests := []struct {
29- name string29+ name string
30- timeout int30+ timeout int
31 shouldErr bool31 shouldErr bool
32 }{32 }{
33 {"negative timeout", -1, true},33 {"negative timeout", -1, true},
M internal/domain/disk/disk_test.go +7 -7
@@ -124,9 +124,9 @@ func TestNewPartition_FAT32NotForRoot(t *testing.T) {
124124
125125 func TestPartition_IsBootPartition(t *testing.T) {
126126 tests := []struct {
127- name string
128- mount string
129- isBoot bool
127+ name string
128+ mount string
129+ isBoot bool
130130 }{
131131 {"boot partition", "/boot", true},
132132 {"efi boot partition", "/boot/efi", true},
@@ -146,10 +146,10 @@ func TestPartition_IsBootPartition(t *testing.T) {
146146
147147 func TestPartition_IsEFI(t *testing.T) {
148148 tests := []struct {
149- name string
150- fs FilesystemType
151- mount string
152- isEFI bool
149+ name string
150+ fs FilesystemType
151+ mount string
152+ isEFI bool
153153 shouldErr bool
154154 }{
155155 {"EFI partition", FilesystemFAT32, "/boot/efi", true, false},
@@ -124,9 +124,9 @@ func TestNewPartition_FAT32NotForRoot(t *testing.T) {
124 124
125 func TestPartition_IsBootPartition(t *testing.T) {125 func TestPartition_IsBootPartition(t *testing.T) {
126 tests := []struct {126 tests := []struct {
127- name string127+ name string
128- mount string128+ mount string
129- isBoot bool129+ isBoot bool
130 }{130 }{
131 {"boot partition", "/boot", true},131 {"boot partition", "/boot", true},
132 {"efi boot partition", "/boot/efi", true},132 {"efi boot partition", "/boot/efi", true},
@@ -146,10 +146,10 @@ func TestPartition_IsBootPartition(t *testing.T) {
146 146
147 func TestPartition_IsEFI(t *testing.T) {147 func TestPartition_IsEFI(t *testing.T) {
148 tests := []struct {148 tests := []struct {
149- name string149+ name string
150- fs FilesystemType150+ fs FilesystemType
151- mount string151+ mount string
152- isEFI bool152+ isEFI bool
153 shouldErr bool153 shouldErr bool
154 }{154 }{
155 {"EFI partition", FilesystemFAT32, "/boot/efi", true, false},155 {"EFI partition", FilesystemFAT32, "/boot/efi", true, false},
M internal/domain/disk/partition.go +3 -3
@@ -33,10 +33,10 @@ func (f FilesystemType) String() string {
3333
3434 // Partition is an immutable value object representing a disk partition
3535 type Partition struct {
36- device string // e.g., /dev/sda1
37- size int64 // Size in megabytes
36+ device string // e.g., /dev/sda1
37+ size int64 // Size in megabytes
3838 filesystem FilesystemType
39- mountPoint string // e.g., /, /boot, /home
39+ mountPoint string // e.g., /, /boot, /home
4040 encrypted bool
4141 }
4242
@@ -33,10 +33,10 @@ func (f FilesystemType) String() string {
33 33
34 // Partition is an immutable value object representing a disk partition34 // Partition is an immutable value object representing a disk partition
35 type Partition struct {35 type Partition struct {
36- device string // e.g., /dev/sda136+ device string // e.g., /dev/sda1
37- size int64 // Size in megabytes37+ size int64 // Size in megabytes
38 filesystem FilesystemType38 filesystem FilesystemType
39- mountPoint string // e.g., /, /boot, /home39+ mountPoint string // e.g., /, /boot, /home
40 encrypted bool40 encrypted bool
41 }41 }
42 42
M internal/domain/installation/events.go +2 -2
@@ -105,9 +105,9 @@ func (e *PhaseCompletedEvent) EventType() string {
105105 // PhaseFailedEvent represents failure of a phase
106106 type PhaseFailedEvent struct {
107107 BaseDomainEvent
108- Phase State
108+ Phase State
109109 ErrorMessage string
110- Recoverable bool
110+ Recoverable bool
111111 }
112112
113113 func NewPhaseFailedEvent(aggregateID string, phase State, errorMessage string, recoverable bool) *PhaseFailedEvent {
@@ -105,9 +105,9 @@ func (e *PhaseCompletedEvent) EventType() string {
105 // PhaseFailedEvent represents failure of a phase105 // PhaseFailedEvent represents failure of a phase
106 type PhaseFailedEvent struct {106 type PhaseFailedEvent struct {
107 BaseDomainEvent107 BaseDomainEvent
108- Phase State108+ Phase State
109 ErrorMessage string109 ErrorMessage string
110- Recoverable bool110+ Recoverable bool
111 }111 }
112 112
113 func NewPhaseFailedEvent(aggregateID string, phase State, errorMessage string, recoverable bool) *PhaseFailedEvent {113 func NewPhaseFailedEvent(aggregateID string, phase State, errorMessage string, recoverable bool) *PhaseFailedEvent {
M internal/domain/installation/installation.go +5 -5
@@ -26,8 +26,8 @@ type Installation struct {
2626 encryptionType string
2727
2828 // Installation metadata
29- createdAt time.Time
30- startedAt *time.Time
29+ createdAt time.Time
30+ startedAt *time.Time
3131 completedAt *time.Time
3232
3333 // Domain events that have occurred during this installation
@@ -65,9 +65,9 @@ func NewInstallation(
6565
6666 // Validate encryptionType
6767 validEncryption := map[string]bool{
68- "none": true,
69- "luks": true,
70- "luks-lvm": true,
68+ "none": true,
69+ "luks": true,
70+ "luks-lvm": true,
7171 }
7272 if !validEncryption[encryptionType] {
7373 return nil, fmt.Errorf("invalid encryption type: %s", encryptionType)
@@ -26,8 +26,8 @@ type Installation struct {
26 encryptionType string26 encryptionType string
27 27
28 // Installation metadata28 // Installation metadata
29- createdAt time.Time29+ createdAt time.Time
30- startedAt *time.Time30+ startedAt *time.Time
31 completedAt *time.Time31 completedAt *time.Time
32 32
33 // Domain events that have occurred during this installation33 // Domain events that have occurred during this installation
@@ -65,9 +65,9 @@ func NewInstallation(
65 65
66 // Validate encryptionType66 // Validate encryptionType
67 validEncryption := map[string]bool{67 validEncryption := map[string]bool{
68- "none": true,68+ "none": true,
69- "luks": true,69+ "luks": true,
70- "luks-lvm": true,70+ "luks-lvm": true,
71 }71 }
72 if !validEncryption[encryptionType] {72 if !validEncryption[encryptionType] {
73 return nil, fmt.Errorf("invalid encryption type: %s", encryptionType)73 return nil, fmt.Errorf("invalid encryption type: %s", encryptionType)
M internal/domain/packages/packages_test.go +4 -4
@@ -159,10 +159,10 @@ func TestNewRepository_Valid(t *testing.T) {
159159
160160 func TestNewRepository_AllCombinations(t *testing.T) {
161161 tests := []struct {
162- name string
163- multilib bool
164- chaotic bool
165- helper AURHelper
162+ name string
163+ multilib bool
164+ chaotic bool
165+ helper AURHelper
166166 }{
167167 {"minimal", false, false, AURHelperParu},
168168 {"chaotic only", false, true, AURHelperParu},
@@ -159,10 +159,10 @@ func TestNewRepository_Valid(t *testing.T) {
159 159
160 func TestNewRepository_AllCombinations(t *testing.T) {160 func TestNewRepository_AllCombinations(t *testing.T) {
161 tests := []struct {161 tests := []struct {
162- name string162+ name string
163- multilib bool163+ multilib bool
164- chaotic bool164+ chaotic bool
165- helper AURHelper165+ helper AURHelper
166 }{166 }{
167 {"minimal", false, false, AURHelperParu},167 {"minimal", false, false, AURHelperParu},
168 {"chaotic only", false, true, AURHelperParu},168 {"chaotic only", false, true, AURHelperParu},
M internal/domain/system/system_test.go +4 -4
@@ -453,9 +453,9 @@ func TestValidateArchLinux(t *testing.T) {
453453 ctx := context.Background()
454454
455455 tests := []struct {
456- name string
456+ name string
457457 fileExists bool
458- shouldErr bool
458+ shouldErr bool
459459 }{
460460 {"arch-release exists", true, false},
461461 {"arch-release missing", false, true},
@@ -592,9 +592,9 @@ func TestValidateUEFIBoot(t *testing.T) {
592592 ctx := context.Background()
593593
594594 tests := []struct {
595- name string
595+ name string
596596 efivarsExists bool
597- shouldErr bool
597+ shouldErr bool
598598 }{
599599 {"efivars exists", true, false},
600600 {"efivars missing", false, true},
@@ -453,9 +453,9 @@ func TestValidateArchLinux(t *testing.T) {
453 ctx := context.Background()453 ctx := context.Background()
454 454
455 tests := []struct {455 tests := []struct {
456- name string456+ name string
457 fileExists bool457 fileExists bool
458- shouldErr bool458+ shouldErr bool
459 }{459 }{
460 {"arch-release exists", true, false},460 {"arch-release exists", true, false},
461 {"arch-release missing", false, true},461 {"arch-release missing", false, true},
@@ -592,9 +592,9 @@ func TestValidateUEFIBoot(t *testing.T) {
592 ctx := context.Background()592 ctx := context.Background()
593 593
594 tests := []struct {594 tests := []struct {
595- name string595+ name string
596 efivarsExists bool596 efivarsExists bool
597- shouldErr bool597+ shouldErr bool
598 }{598 }{
599 {"efivars exists", true, false},599 {"efivars exists", true, false},
600 {"efivars missing", false, true},600 {"efivars missing", false, true},
M internal/domain/system/validation.go +15 -15
@@ -82,17 +82,17 @@ func (r *SystemValidationRules) SanitizeHostname(hostname string) string {
8282 func (r *SystemValidationRules) SuggestedLocaleForTimezone(timezone string) string {
8383 // Common timezone -> locale pairings (not enforced, just suggestions)
8484 suggestions := map[string]string{
85- "America/New_York": "en_US.UTF-8",
86- "America/Chicago": "en_US.UTF-8",
87- "America/Denver": "en_US.UTF-8",
88- "America/Los_Angeles": "en_US.UTF-8",
89- "Europe/London": "en_GB.UTF-8",
90- "Europe/Paris": "fr_FR.UTF-8",
91- "Europe/Berlin": "de_DE.UTF-8",
92- "Europe/Madrid": "es_ES.UTF-8",
93- "Asia/Tokyo": "ja_JP.UTF-8",
94- "Australia/Sydney": "en_AU.UTF-8",
95- "UTC": "en_US.UTF-8",
85+ "America/New_York": "en_US.UTF-8",
86+ "America/Chicago": "en_US.UTF-8",
87+ "America/Denver": "en_US.UTF-8",
88+ "America/Los_Angeles": "en_US.UTF-8",
89+ "Europe/London": "en_GB.UTF-8",
90+ "Europe/Paris": "fr_FR.UTF-8",
91+ "Europe/Berlin": "de_DE.UTF-8",
92+ "Europe/Madrid": "es_ES.UTF-8",
93+ "Asia/Tokyo": "ja_JP.UTF-8",
94+ "Australia/Sydney": "en_AU.UTF-8",
95+ "UTC": "en_US.UTF-8",
9696 }
9797
9898 if locale, exists := suggestions[timezone]; exists {
@@ -127,10 +127,10 @@ func (r *SystemValidationRules) SuggestedKeymapForLocale(locale string) string {
127127 func (r *SystemValidationRules) IsValidLocaleVariant(locale string) bool {
128128 // Common valid variants
129129 validVariants := map[string]bool{
130- "UTF-8": true,
131- "utf8": true,
132- "UTF8": true,
133- "ISO8859-1": true,
130+ "UTF-8": true,
131+ "utf8": true,
132+ "UTF8": true,
133+ "ISO8859-1": true,
134134 "ISO-8859-1": true,
135135 }
136136
@@ -82,17 +82,17 @@ func (r *SystemValidationRules) SanitizeHostname(hostname string) string {
82 func (r *SystemValidationRules) SuggestedLocaleForTimezone(timezone string) string {82 func (r *SystemValidationRules) SuggestedLocaleForTimezone(timezone string) string {
83 // Common timezone -> locale pairings (not enforced, just suggestions)83 // Common timezone -> locale pairings (not enforced, just suggestions)
84 suggestions := map[string]string{84 suggestions := map[string]string{
85- "America/New_York": "en_US.UTF-8",85+ "America/New_York": "en_US.UTF-8",
86- "America/Chicago": "en_US.UTF-8",86+ "America/Chicago": "en_US.UTF-8",
87- "America/Denver": "en_US.UTF-8",87+ "America/Denver": "en_US.UTF-8",
88- "America/Los_Angeles": "en_US.UTF-8",88+ "America/Los_Angeles": "en_US.UTF-8",
89- "Europe/London": "en_GB.UTF-8",89+ "Europe/London": "en_GB.UTF-8",
90- "Europe/Paris": "fr_FR.UTF-8",90+ "Europe/Paris": "fr_FR.UTF-8",
91- "Europe/Berlin": "de_DE.UTF-8",91+ "Europe/Berlin": "de_DE.UTF-8",
92- "Europe/Madrid": "es_ES.UTF-8",92+ "Europe/Madrid": "es_ES.UTF-8",
93- "Asia/Tokyo": "ja_JP.UTF-8",93+ "Asia/Tokyo": "ja_JP.UTF-8",
94- "Australia/Sydney": "en_AU.UTF-8",94+ "Australia/Sydney": "en_AU.UTF-8",
95- "UTC": "en_US.UTF-8",95+ "UTC": "en_US.UTF-8",
96 }96 }
97 97
98 if locale, exists := suggestions[timezone]; exists {98 if locale, exists := suggestions[timezone]; exists {
@@ -127,10 +127,10 @@ func (r *SystemValidationRules) SuggestedKeymapForLocale(locale string) string {
127 func (r *SystemValidationRules) IsValidLocaleVariant(locale string) bool {127 func (r *SystemValidationRules) IsValidLocaleVariant(locale string) bool {
128 // Common valid variants128 // Common valid variants
129 validVariants := map[string]bool{129 validVariants := map[string]bool{
130- "UTF-8": true,130+ "UTF-8": true,
131- "utf8": true,131+ "utf8": true,
132- "UTF8": true,132+ "UTF8": true,
133- "ISO8859-1": true,133+ "ISO8859-1": true,
134 "ISO-8859-1": true,134 "ISO-8859-1": true,
135 }135 }
136 136
M internal/domain/user/user.go +5 -5
@@ -133,11 +133,11 @@ func ValidateShell(shell string) error {
133133
134134 // Common valid shells
135135 validShells := map[string]bool{
136- "/bin/bash": true,
137- "/bin/sh": true,
138- "/bin/zsh": true,
139- "/bin/fish": true,
140- "/usr/bin/zsh": true,
136+ "/bin/bash": true,
137+ "/bin/sh": true,
138+ "/bin/zsh": true,
139+ "/bin/fish": true,
140+ "/usr/bin/zsh": true,
141141 "/usr/bin/fish": true,
142142 }
143143
@@ -133,11 +133,11 @@ func ValidateShell(shell string) error {
133 133
134 // Common valid shells134 // Common valid shells
135 validShells := map[string]bool{135 validShells := map[string]bool{
136- "/bin/bash": true,136+ "/bin/bash": true,
137- "/bin/sh": true,137+ "/bin/sh": true,
138- "/bin/zsh": true,138+ "/bin/zsh": true,
139- "/bin/fish": true,139+ "/bin/fish": true,
140- "/usr/bin/zsh": true,140+ "/usr/bin/zsh": true,
141 "/usr/bin/fish": true,141 "/usr/bin/fish": true,
142 }142 }
143 143
M internal/infrastructure/executor/script.go +2 -2
@@ -12,8 +12,8 @@ import (
1212
1313 // ScriptExecutor implements the ScriptExecutor port for shell scripts
1414 type ScriptExecutor struct {
15- fs ports.FileSystem
16- cmdExec ports.CommandExecutor
15+ fs ports.FileSystem
16+ cmdExec ports.CommandExecutor
1717 scriptDir string
1818 }
1919
@@ -12,8 +12,8 @@ import (
12 12
13 // ScriptExecutor implements the ScriptExecutor port for shell scripts13 // ScriptExecutor implements the ScriptExecutor port for shell scripts
14 type ScriptExecutor struct {14 type ScriptExecutor struct {
15- fs ports.FileSystem15+ fs ports.FileSystem
16- cmdExec ports.CommandExecutor16+ cmdExec ports.CommandExecutor
17 scriptDir string17 scriptDir string
18 }18 }
19 19
M internal/interfaces/tui/app.go +6 -6
@@ -3,12 +3,12 @@ package tui
33 import (
44 "context"
55
6- tea "github.com/charmbracelet/bubbletea"
76 "github.com/bnema/archup/internal/application/services"
87 "github.com/bnema/archup/internal/domain/ports"
98 "github.com/bnema/archup/internal/interfaces/tui/handlers"
109 "github.com/bnema/archup/internal/interfaces/tui/models"
1110 "github.com/bnema/archup/internal/interfaces/tui/views"
11+ tea "github.com/charmbracelet/bubbletea"
1212 )
1313
1414 // App is the main TUI application coordinator
@@ -37,11 +37,11 @@ type App struct {
3737 type Screen string
3838
3939 const (
40- ScreenForm Screen = "form"
41- ScreenInstalling Screen = "installing"
42- ScreenProgress Screen = "progress"
43- ScreenSummary Screen = "summary"
44- ScreenError Screen = "error"
40+ ScreenForm Screen = "form"
41+ ScreenInstalling Screen = "installing"
42+ ScreenProgress Screen = "progress"
43+ ScreenSummary Screen = "summary"
44+ ScreenError Screen = "error"
4545 )
4646
4747 // NewApp creates a new TUI application
@@ -3,12 +3,12 @@ package tui
3 import (3 import (
4 "context"4 "context"
5 5
6- tea "github.com/charmbracelet/bubbletea"
7 "github.com/bnema/archup/internal/application/services"6 "github.com/bnema/archup/internal/application/services"
8 "github.com/bnema/archup/internal/domain/ports"7 "github.com/bnema/archup/internal/domain/ports"
9 "github.com/bnema/archup/internal/interfaces/tui/handlers"8 "github.com/bnema/archup/internal/interfaces/tui/handlers"
10 "github.com/bnema/archup/internal/interfaces/tui/models"9 "github.com/bnema/archup/internal/interfaces/tui/models"
11 "github.com/bnema/archup/internal/interfaces/tui/views"10 "github.com/bnema/archup/internal/interfaces/tui/views"
11+ tea "github.com/charmbracelet/bubbletea"
12 )12 )
13 13
14 // App is the main TUI application coordinator14 // App is the main TUI application coordinator
@@ -37,11 +37,11 @@ type App struct {
37 type Screen string37 type Screen string
38 38
39 const (39 const (
40- ScreenForm Screen = "form"40+ ScreenForm Screen = "form"
41- ScreenInstalling Screen = "installing"41+ ScreenInstalling Screen = "installing"
42- ScreenProgress Screen = "progress"42+ ScreenProgress Screen = "progress"
43- ScreenSummary Screen = "summary"43+ ScreenSummary Screen = "summary"
44- ScreenError Screen = "error"44+ ScreenError Screen = "error"
45 )45 )
46 46
47 // NewApp creates a new TUI application47 // NewApp creates a new TUI application
M internal/interfaces/tui/factory.go +0 -1
@@ -16,4 +16,3 @@ func NewInstallationModel() InstallationModel {
1616 func NewProgressModel() ProgressModel {
1717 return models.NewProgressModel()
1818 }
19-
@@ -16,4 +16,3 @@ func NewInstallationModel() InstallationModel {
16 func NewProgressModel() ProgressModel {16 func NewProgressModel() ProgressModel {
17 return models.NewProgressModel()17 return models.NewProgressModel()
18 }18 }
19-
M internal/interfaces/tui/handlers/form_handler.go +1 -1
@@ -1,8 +1,8 @@
11 package handlers
22
33 import (
4- tea "github.com/charmbracelet/bubbletea"
54 "github.com/bnema/archup/internal/interfaces/tui/models"
5+ tea "github.com/charmbracelet/bubbletea"
66 )
77
88 // HandleFormUpdate processes form input and updates the form model
@@ -1,8 +1,8 @@
1 package handlers1 package handlers
2 2
3 import (3 import (
4- tea "github.com/charmbracelet/bubbletea"
5 "github.com/bnema/archup/internal/interfaces/tui/models"4 "github.com/bnema/archup/internal/interfaces/tui/models"
5+ tea "github.com/charmbracelet/bubbletea"
6 )6 )
7 7
8 // HandleFormUpdate processes form input and updates the form model8 // HandleFormUpdate processes form input and updates the form model
M internal/interfaces/tui/handlers/form_handler_test.go +1 -1
@@ -3,8 +3,8 @@ package handlers
33 import (
44 "testing"
55
6- tea "github.com/charmbracelet/bubbletea"
76 "github.com/bnema/archup/internal/interfaces/tui/models"
7+ tea "github.com/charmbracelet/bubbletea"
88 )
99
1010 func TestHandleFormUpdate_Navigation(t *testing.T) {
@@ -3,8 +3,8 @@ package handlers
3 import (3 import (
4 "testing"4 "testing"
5 5
6- tea "github.com/charmbracelet/bubbletea"
7 "github.com/bnema/archup/internal/interfaces/tui/models"6 "github.com/bnema/archup/internal/interfaces/tui/models"
7+ tea "github.com/charmbracelet/bubbletea"
8 )8 )
9 9
10 func TestHandleFormUpdate_Navigation(t *testing.T) {10 func TestHandleFormUpdate_Navigation(t *testing.T) {
M internal/interfaces/tui/handlers/install_handler.go +1 -1
@@ -1,9 +1,9 @@
11 package handlers
22
33 import (
4- tea "github.com/charmbracelet/bubbletea"
54 "github.com/bnema/archup/internal/application/dto"
65 "github.com/bnema/archup/internal/interfaces/tui/models"
6+ tea "github.com/charmbracelet/bubbletea"
77 )
88
99 // NOTE: This package uses AppContext interface to avoid importing parent tui package
@@ -1,9 +1,9 @@
1 package handlers1 package handlers
2 2
3 import (3 import (
4- tea "github.com/charmbracelet/bubbletea"
5 "github.com/bnema/archup/internal/application/dto"4 "github.com/bnema/archup/internal/application/dto"
6 "github.com/bnema/archup/internal/interfaces/tui/models"5 "github.com/bnema/archup/internal/interfaces/tui/models"
6+ tea "github.com/charmbracelet/bubbletea"
7 )7 )
8 8
9 // NOTE: This package uses AppContext interface to avoid importing parent tui package9 // NOTE: This package uses AppContext interface to avoid importing parent tui package
M internal/interfaces/tui/interfaces.go +1 -1
@@ -1,9 +1,9 @@
11 package tui
22
33 import (
4- tea "github.com/charmbracelet/bubbletea"
54 "github.com/bnema/archup/internal/application/dto"
65 "github.com/bnema/archup/internal/interfaces/tui/models"
6+ tea "github.com/charmbracelet/bubbletea"
77 )
88
99 // FormModel manages form state for user input
@@ -1,9 +1,9 @@
1 package tui1 package tui
2 2
3 import (3 import (
4- tea "github.com/charmbracelet/bubbletea"
5 "github.com/bnema/archup/internal/application/dto"4 "github.com/bnema/archup/internal/application/dto"
6 "github.com/bnema/archup/internal/interfaces/tui/models"5 "github.com/bnema/archup/internal/interfaces/tui/models"
6+ tea "github.com/charmbracelet/bubbletea"
7 )7 )
8 8
9 // FormModel manages form state for user input9 // FormModel manages form state for user input
M internal/interfaces/tui/models/form.go +8 -8
@@ -41,14 +41,14 @@ type FormModelImpl struct {
4141 BaseModel
4242
4343 // Form fields
44- hostname textinput.Model
45- username textinput.Model
46- userPassword textinput.Model
47- rootPassword textinput.Model
48- targetDisk textinput.Model
49- timezone textinput.Model
50- locale textinput.Model
51- keymap textinput.Model
44+ hostname textinput.Model
45+ username textinput.Model
46+ userPassword textinput.Model
47+ rootPassword textinput.Model
48+ targetDisk textinput.Model
49+ timezone textinput.Model
50+ locale textinput.Model
51+ keymap textinput.Model
5252
5353 // UI state
5454 focusIndex int
@@ -41,14 +41,14 @@ type FormModelImpl struct {
41 BaseModel41 BaseModel
42 42
43 // Form fields43 // Form fields
44- hostname textinput.Model44+ hostname textinput.Model
45- username textinput.Model45+ username textinput.Model
46- userPassword textinput.Model46+ userPassword textinput.Model
47- rootPassword textinput.Model47+ rootPassword textinput.Model
48- targetDisk textinput.Model48+ targetDisk textinput.Model
49- timezone textinput.Model49+ timezone textinput.Model
50- locale textinput.Model50+ locale textinput.Model
51- keymap textinput.Model51+ keymap textinput.Model
52 52
53 // UI state53 // UI state
54 focusIndex int54 focusIndex int
M internal/interfaces/tui/models/installation.go +3 -3
@@ -5,17 +5,17 @@ import (
55 "strings"
66 "time"
77
8+ "github.com/bnema/archup/internal/application/dto"
89 tea "github.com/charmbracelet/bubbletea"
910 "github.com/charmbracelet/lipgloss"
10- "github.com/bnema/archup/internal/application/dto"
1111 )
1212
1313 // InstallationModelImpl implements InstallationModel interface
1414 type InstallationModelImpl struct {
1515 BaseModel
1616
17- status *dto.InstallationStatus
18- err string
17+ status *dto.InstallationStatus
18+ err string
1919 complete bool
2020 }
2121
@@ -5,17 +5,17 @@ import (
5 "strings"5 "strings"
6 "time"6 "time"
7 7
8+ "github.com/bnema/archup/internal/application/dto"
8 tea "github.com/charmbracelet/bubbletea"9 tea "github.com/charmbracelet/bubbletea"
9 "github.com/charmbracelet/lipgloss"10 "github.com/charmbracelet/lipgloss"
10- "github.com/bnema/archup/internal/application/dto"
11 )11 )
12 12
13 // InstallationModelImpl implements InstallationModel interface13 // InstallationModelImpl implements InstallationModel interface
14 type InstallationModelImpl struct {14 type InstallationModelImpl struct {
15 BaseModel15 BaseModel
16 16
17- status *dto.InstallationStatus17+ status *dto.InstallationStatus
18- err string18+ err string
19 complete bool19 complete bool
20 }20 }
21 21
M internal/interfaces/tui/models/progress.go +1 -1
@@ -4,9 +4,9 @@ import (
44 "fmt"
55 "strings"
66
7+ "github.com/bnema/archup/internal/application/dto"
78 tea "github.com/charmbracelet/bubbletea"
89 "github.com/charmbracelet/lipgloss"
9- "github.com/bnema/archup/internal/application/dto"
1010 )
1111
1212 // ProgressModelImpl implements ProgressModel interface
@@ -4,9 +4,9 @@ import (
4 "fmt"4 "fmt"
5 "strings"5 "strings"
6 6
7+ "github.com/bnema/archup/internal/application/dto"
7 tea "github.com/charmbracelet/bubbletea"8 tea "github.com/charmbracelet/bubbletea"
8 "github.com/charmbracelet/lipgloss"9 "github.com/charmbracelet/lipgloss"
9- "github.com/bnema/archup/internal/application/dto"
10 )10 )
11 11
12 // ProgressModelImpl implements ProgressModel interface12 // ProgressModelImpl implements ProgressModel interface
M internal/interfaces/tui/views/form_view.go +1 -1
@@ -3,8 +3,8 @@ package views
33 import (
44 "strings"
55
6- "github.com/charmbracelet/lipgloss"
76 "github.com/bnema/archup/internal/interfaces/tui/models"
7+ "github.com/charmbracelet/lipgloss"
88 )
99
1010 // RenderForm renders the form model to a styled string
@@ -3,8 +3,8 @@ package views
3 import (3 import (
4 "strings"4 "strings"
5 5
6- "github.com/charmbracelet/lipgloss"
7 "github.com/bnema/archup/internal/interfaces/tui/models"6 "github.com/bnema/archup/internal/interfaces/tui/models"
7+ "github.com/charmbracelet/lipgloss"
8 )8 )
9 9
10 // RenderForm renders the form model to a styled string10 // RenderForm renders the form model to a styled string
M internal/interfaces/tui/views/form_view_test.go +5 -5
@@ -18,9 +18,9 @@ func TestRenderForm(t *testing.T) {
1818 // Verify key content is present
1919 checks := []string{
2020 "ArchUp Installer Configuration", // Title
21- "Hostname:", // Field labels
21+ "Hostname:", // Field labels
2222 "Username:",
23- "↑↓ Navigate", // Instructions
23+ "↑↓ Navigate", // Instructions
2424 }
2525
2626 for _, check := range checks {
@@ -123,9 +123,9 @@ func TestFormFieldInteraction(t *testing.T) {
123123
124124 // Set data
125125 testData := models.FormData{
126- Hostname: "test-host",
127- Username: "testuser",
128- TargetDisk: "/dev/sda",
126+ Hostname: "test-host",
127+ Username: "testuser",
128+ TargetDisk: "/dev/sda",
129129 EncryptionType: "LUKS",
130130 }
131131 fm.SetData(testData)
@@ -18,9 +18,9 @@ func TestRenderForm(t *testing.T) {
18 // Verify key content is present18 // Verify key content is present
19 checks := []string{19 checks := []string{
20 "ArchUp Installer Configuration", // Title20 "ArchUp Installer Configuration", // Title
21- "Hostname:", // Field labels21+ "Hostname:", // Field labels
22 "Username:",22 "Username:",
23- "↑↓ Navigate", // Instructions23+ "↑↓ Navigate", // Instructions
24 }24 }
25 25
26 for _, check := range checks {26 for _, check := range checks {
@@ -123,9 +123,9 @@ func TestFormFieldInteraction(t *testing.T) {
123 123
124 // Set data124 // Set data
125 testData := models.FormData{125 testData := models.FormData{
126- Hostname: "test-host",126+ Hostname: "test-host",
127- Username: "testuser",127+ Username: "testuser",
128- TargetDisk: "/dev/sda",128+ TargetDisk: "/dev/sda",
129 EncryptionType: "LUKS",129 EncryptionType: "LUKS",
130 }130 }
131 fm.SetData(testData)131 fm.SetData(testData)
M internal/interfaces/tui/views/progress_view.go +1 -1
@@ -4,8 +4,8 @@ import (
44 "fmt"
55 "strings"
66
7- "github.com/charmbracelet/lipgloss"
87 "github.com/bnema/archup/internal/interfaces/tui/models"
8+ "github.com/charmbracelet/lipgloss"
99 )
1010
1111 // RenderProgress renders the progress model to a styled string
@@ -4,8 +4,8 @@ import (
4 "fmt"4 "fmt"
5 "strings"5 "strings"
6 6
7- "github.com/charmbracelet/lipgloss"
8 "github.com/bnema/archup/internal/interfaces/tui/models"7 "github.com/bnema/archup/internal/interfaces/tui/models"
8+ "github.com/charmbracelet/lipgloss"
9 )9 )
10 10
11 // RenderProgress renders the progress model to a styled string11 // RenderProgress renders the progress model to a styled string
M internal/interfaces/tui/views/progress_view_test.go +7 -7
@@ -27,13 +27,13 @@ func TestRenderProgress(t *testing.T) {
2727
2828 // Verify key content is present
2929 checks := []string{
30- "Installation Progress", // Title
31- "Phase 2/7", // Phase info
32- "Partitioning", // Phase name
33- "Partitioning disk...", // Message
34- "[", // Progress bar start
35- "]", // Progress bar end
36- "25%", // Progress percentage
30+ "Installation Progress", // Title
31+ "Phase 2/7", // Phase info
32+ "Partitioning", // Phase name
33+ "Partitioning disk...", // Message
34+ "[", // Progress bar start
35+ "]", // Progress bar end
36+ "25%", // Progress percentage
3737 }
3838
3939 for _, check := range checks {
@@ -27,13 +27,13 @@ func TestRenderProgress(t *testing.T) {
27 27
28 // Verify key content is present28 // Verify key content is present
29 checks := []string{29 checks := []string{
30- "Installation Progress", // Title30+ "Installation Progress", // Title
31- "Phase 2/7", // Phase info31+ "Phase 2/7", // Phase info
32- "Partitioning", // Phase name32+ "Partitioning", // Phase name
33- "Partitioning disk...", // Message33+ "Partitioning disk...", // Message
34- "[", // Progress bar start34+ "[", // Progress bar start
35- "]", // Progress bar end35+ "]", // Progress bar end
36- "25%", // Progress percentage36+ "25%", // Progress percentage
37 }37 }
38 38
39 for _, check := range checks {39 for _, check := range checks {
M internal/interfaces/tui/views/summary_view.go +1 -1
@@ -5,8 +5,8 @@ import (
55 "strings"
66 "time"
77
8- "github.com/charmbracelet/lipgloss"
98 "github.com/bnema/archup/internal/interfaces/tui/models"
9+ "github.com/charmbracelet/lipgloss"
1010 )
1111
1212 // RenderSummary renders the installation summary (success case)
@@ -5,8 +5,8 @@ import (
5 "strings"5 "strings"
6 "time"6 "time"
7 7
8- "github.com/charmbracelet/lipgloss"
9 "github.com/bnema/archup/internal/interfaces/tui/models"8 "github.com/bnema/archup/internal/interfaces/tui/models"
9+ "github.com/charmbracelet/lipgloss"
10 )10 )
11 11
12 // RenderSummary renders the installation summary (success case)12 // RenderSummary renders the installation summary (success case)
M internal/interfaces/tui/views/summary_view_test.go +18 -18
@@ -16,14 +16,14 @@ func TestRenderSummary(t *testing.T) {
1616 now := time.Now()
1717 completedAt := now.Add(1 * time.Hour)
1818 status := &dto.InstallationStatus{
19- Hostname: "test-host",
20- Username: "testuser",
21- TargetDisk: "/dev/sda",
22- Progress: 100,
23- State: "Complete",
19+ Hostname: "test-host",
20+ Username: "testuser",
21+ TargetDisk: "/dev/sda",
22+ Progress: 100,
23+ State: "Complete",
2424 CurrentPhase: "PostInstallation",
25- StartedAt: &now,
26- CompletedAt: &completedAt,
25+ StartedAt: &now,
26+ CompletedAt: &completedAt,
2727 }
2828
2929 im.SetStatus(status)
@@ -34,11 +34,11 @@ func TestRenderSummary(t *testing.T) {
3434
3535 // Verify key content is present
3636 checks := []string{
37- "Installation Complete!", // Title
38- "test-host", // Hostname
39- "testuser", // Username
40- "/dev/sda", // Disk
41- "Press 'q' to exit", // Instructions
37+ "Installation Complete!", // Title
38+ "test-host", // Hostname
39+ "testuser", // Username
40+ "/dev/sda", // Disk
41+ "Press 'q' to exit", // Instructions
4242 }
4343
4444 for _, check := range checks {
@@ -63,9 +63,9 @@ func TestRenderError(t *testing.T) {
6363
6464 // Verify key content is present
6565 checks := []string{
66- "Installation Failed", // Title
67- errorMsg, // Error message
68- "Press 'q' or Ctrl+C to exit", // Instructions
66+ "Installation Failed", // Title
67+ errorMsg, // Error message
68+ "Press 'q' or Ctrl+C to exit", // Instructions
6969 }
7070
7171 for _, check := range checks {
@@ -84,10 +84,10 @@ func TestRenderStatus(t *testing.T) {
8484
8585 // Create status data
8686 status := &dto.InstallationStatus{
87- Hostname: "test-host",
87+ Hostname: "test-host",
8888 CurrentPhase: "Partitioning",
89- Progress: 35,
90- State: "Running",
89+ Progress: 35,
90+ State: "Running",
9191 }
9292
9393 im.SetStatus(status)
@@ -16,14 +16,14 @@ func TestRenderSummary(t *testing.T) {
16 now := time.Now()16 now := time.Now()
17 completedAt := now.Add(1 * time.Hour)17 completedAt := now.Add(1 * time.Hour)
18 status := &dto.InstallationStatus{18 status := &dto.InstallationStatus{
19- Hostname: "test-host",19+ Hostname: "test-host",
20- Username: "testuser",20+ Username: "testuser",
21- TargetDisk: "/dev/sda",21+ TargetDisk: "/dev/sda",
22- Progress: 100,22+ Progress: 100,
23- State: "Complete",23+ State: "Complete",
24 CurrentPhase: "PostInstallation",24 CurrentPhase: "PostInstallation",
25- StartedAt: &now,25+ StartedAt: &now,
26- CompletedAt: &completedAt,26+ CompletedAt: &completedAt,
27 }27 }
28 28
29 im.SetStatus(status)29 im.SetStatus(status)
@@ -34,11 +34,11 @@ func TestRenderSummary(t *testing.T) {
34 34
35 // Verify key content is present35 // Verify key content is present
36 checks := []string{36 checks := []string{
37- "Installation Complete!", // Title37+ "Installation Complete!", // Title
38- "test-host", // Hostname38+ "test-host", // Hostname
39- "testuser", // Username39+ "testuser", // Username
40- "/dev/sda", // Disk40+ "/dev/sda", // Disk
41- "Press 'q' to exit", // Instructions41+ "Press 'q' to exit", // Instructions
42 }42 }
43 43
44 for _, check := range checks {44 for _, check := range checks {
@@ -63,9 +63,9 @@ func TestRenderError(t *testing.T) {
63 63
64 // Verify key content is present64 // Verify key content is present
65 checks := []string{65 checks := []string{
66- "Installation Failed", // Title66+ "Installation Failed", // Title
67- errorMsg, // Error message67+ errorMsg, // Error message
68- "Press 'q' or Ctrl+C to exit", // Instructions68+ "Press 'q' or Ctrl+C to exit", // Instructions
69 }69 }
70 70
71 for _, check := range checks {71 for _, check := range checks {
@@ -84,10 +84,10 @@ func TestRenderStatus(t *testing.T) {
84 84
85 // Create status data85 // Create status data
86 status := &dto.InstallationStatus{86 status := &dto.InstallationStatus{
87- Hostname: "test-host",87+ Hostname: "test-host",
88 CurrentPhase: "Partitioning",88 CurrentPhase: "Partitioning",
89- Progress: 35,89+ Progress: 35,
90- State: "Running",90+ State: "Running",
91 }91 }
92 92
93 im.SetStatus(status)93 im.SetStatus(status)
M internal/logger/logger.go +4 -4
@@ -13,10 +13,10 @@ import (
1313
1414 // Logger wraps slog.Logger and adds dry-run mode support
1515 type Logger struct {
16- slog *slog.Logger
17- logPath string
18- dryRun bool
19- logFile *os.File
16+ slog *slog.Logger
17+ logPath string
18+ dryRun bool
19+ logFile *os.File
2020 }
2121
2222 // syncWriter wraps an io.Writer to sync after every write
@@ -13,10 +13,10 @@ import (
13 13
14 // Logger wraps slog.Logger and adds dry-run mode support14 // Logger wraps slog.Logger and adds dry-run mode support
15 type Logger struct {15 type Logger struct {
16- slog *slog.Logger16+ slog *slog.Logger
17- logPath string17+ logPath string
18- dryRun bool18+ dryRun bool
19- logFile *os.File19+ logFile *os.File
20 }20 }
21 21
22 // syncWriter wraps an io.Writer to sync after every write22 // syncWriter wraps an io.Writer to sync after every write
M internal/phases/base.go +2 -2
@@ -13,8 +13,8 @@ import (
1313 // BaseInstallPhase handles base system installation
1414 type BaseInstallPhase struct {
1515 *BasePhase
16- fs interfaces.FileSystem
17- sysExec interfaces.SystemExecutor
16+ fs interfaces.FileSystem
17+ sysExec interfaces.SystemExecutor
1818 packages []string
1919 }
2020
@@ -13,8 +13,8 @@ import (
13 // BaseInstallPhase handles base system installation13 // BaseInstallPhase handles base system installation
14 type BaseInstallPhase struct {14 type BaseInstallPhase struct {
15 *BasePhase15 *BasePhase
16- fs interfaces.FileSystem16+ fs interfaces.FileSystem
17- sysExec interfaces.SystemExecutor17+ sysExec interfaces.SystemExecutor
18 packages []string18 packages []string
19 }19 }
20 20
M internal/phases/base_test.go +50 -50
@@ -73,39 +73,39 @@ func TestBaseInstallPhasePreCheck(t *testing.T) {
7373 // TestBaseInstallPhaseDetectCPU tests CPU vendor detection
7474 func TestBaseInstallPhaseDetectCPU(t *testing.T) {
7575 tests := []struct {
76- name string
77- cpuinfoContent string
78- expectedVendor string
76+ name string
77+ cpuinfoContent string
78+ expectedVendor string
7979 expectedMicrocode string
80- wantErr bool
80+ wantErr bool
8181 }{
8282 {
83- name: "Intel CPU detected",
84- cpuinfoContent: "processor\t: 0\nvendor_id\t: GenuineIntel\nflags\t: fpu\n",
85- expectedVendor: "Intel",
83+ name: "Intel CPU detected",
84+ cpuinfoContent: "processor\t: 0\nvendor_id\t: GenuineIntel\nflags\t: fpu\n",
85+ expectedVendor: "Intel",
8686 expectedMicrocode: "intel-ucode",
87- wantErr: false,
87+ wantErr: false,
8888 },
8989 {
90- name: "AMD CPU detected",
91- cpuinfoContent: "processor\t: 0\nvendor_id\t: AuthenticAMD\nflags\t: fpu\n",
92- expectedVendor: "AMD",
90+ name: "AMD CPU detected",
91+ cpuinfoContent: "processor\t: 0\nvendor_id\t: AuthenticAMD\nflags\t: fpu\n",
92+ expectedVendor: "AMD",
9393 expectedMicrocode: "amd-ucode",
94- wantErr: false,
94+ wantErr: false,
9595 },
9696 {
97- name: "Unknown CPU vendor",
98- cpuinfoContent: "processor\t: 0\nvendor_id\t: UnknownVendor\nflags\t: fpu\n",
99- expectedVendor: "Unknown",
97+ name: "Unknown CPU vendor",
98+ cpuinfoContent: "processor\t: 0\nvendor_id\t: UnknownVendor\nflags\t: fpu\n",
99+ expectedVendor: "Unknown",
100100 expectedMicrocode: "",
101- wantErr: false,
101+ wantErr: false,
102102 },
103103 {
104- name: "Empty cpuinfo",
105- cpuinfoContent: "",
106- expectedVendor: "Unknown",
104+ name: "Empty cpuinfo",
105+ cpuinfoContent: "",
106+ expectedVendor: "Unknown",
107107 expectedMicrocode: "",
108- wantErr: false,
108+ wantErr: false,
109109 },
110110 }
111111
@@ -237,21 +237,21 @@ func TestBaseInstallPhaseLoadBasePackages(t *testing.T) {
237237 // TestBaseInstallPhaseGenerateFstab tests fstab generation
238238 func TestBaseInstallPhaseGenerateFstab(t *testing.T) {
239239 tests := []struct {
240- name string
241- genfstabResult system.CommandResult
242- wantErr bool
243- errContains string
240+ name string
241+ genfstabResult system.CommandResult
242+ wantErr bool
243+ errContains string
244244 }{
245245 {
246- name: "Fstab generation success",
247- genfstabResult: system.CommandResult{ExitCode: 0},
248- wantErr: false,
246+ name: "Fstab generation success",
247+ genfstabResult: system.CommandResult{ExitCode: 0},
248+ wantErr: false,
249249 },
250250 {
251- name: "Genfstab command failed",
252- genfstabResult: system.CommandResult{ExitCode: 1, Error: fmt.Errorf("permission denied")},
253- wantErr: true,
254- errContains: "genfstab failed",
251+ name: "Genfstab command failed",
252+ genfstabResult: system.CommandResult{ExitCode: 1, Error: fmt.Errorf("permission denied")},
253+ wantErr: true,
254+ errContains: "genfstab failed",
255255 },
256256 }
257257
@@ -295,31 +295,31 @@ func TestBaseInstallPhaseGenerateFstab(t *testing.T) {
295295 // TestBaseInstallPhasePostCheck tests installation validation
296296 func TestBaseInstallPhasePostCheck(t *testing.T) {
297297 tests := []struct {
298- name string
299- usrDirExists bool
300- fstabFileExists bool
301- wantErr bool
302- errContains string
298+ name string
299+ usrDirExists bool
300+ fstabFileExists bool
301+ wantErr bool
302+ errContains string
303303 }{
304304 {
305- name: "Both /mnt/usr and /mnt/etc/fstab exist",
306- usrDirExists: true,
307- fstabFileExists: true,
308- wantErr: false,
305+ name: "Both /mnt/usr and /mnt/etc/fstab exist",
306+ usrDirExists: true,
307+ fstabFileExists: true,
308+ wantErr: false,
309309 },
310310 {
311- name: "/mnt/usr does not exist",
312- usrDirExists: false,
313- fstabFileExists: true,
314- wantErr: true,
315- errContains: "/mnt/usr does not exist",
311+ name: "/mnt/usr does not exist",
312+ usrDirExists: false,
313+ fstabFileExists: true,
314+ wantErr: true,
315+ errContains: "/mnt/usr does not exist",
316316 },
317317 {
318- name: "/mnt/etc/fstab does not exist",
319- usrDirExists: true,
320- fstabFileExists: false,
321- wantErr: true,
322- errContains: "fstab was not created",
318+ name: "/mnt/etc/fstab does not exist",
319+ usrDirExists: true,
320+ fstabFileExists: false,
321+ wantErr: true,
322+ errContains: "fstab was not created",
323323 },
324324 }
325325
@@ -73,39 +73,39 @@ func TestBaseInstallPhasePreCheck(t *testing.T) {
73 // TestBaseInstallPhaseDetectCPU tests CPU vendor detection73 // TestBaseInstallPhaseDetectCPU tests CPU vendor detection
74 func TestBaseInstallPhaseDetectCPU(t *testing.T) {74 func TestBaseInstallPhaseDetectCPU(t *testing.T) {
75 tests := []struct {75 tests := []struct {
76- name string76+ name string
77- cpuinfoContent string77+ cpuinfoContent string
78- expectedVendor string78+ expectedVendor string
79 expectedMicrocode string79 expectedMicrocode string
80- wantErr bool80+ wantErr bool
81 }{81 }{
82 {82 {
83- name: "Intel CPU detected",83+ name: "Intel CPU detected",
84- cpuinfoContent: "processor\t: 0\nvendor_id\t: GenuineIntel\nflags\t: fpu\n",84+ cpuinfoContent: "processor\t: 0\nvendor_id\t: GenuineIntel\nflags\t: fpu\n",
85- expectedVendor: "Intel",85+ expectedVendor: "Intel",
86 expectedMicrocode: "intel-ucode",86 expectedMicrocode: "intel-ucode",
87- wantErr: false,87+ wantErr: false,
88 },88 },
89 {89 {
90- name: "AMD CPU detected",90+ name: "AMD CPU detected",
91- cpuinfoContent: "processor\t: 0\nvendor_id\t: AuthenticAMD\nflags\t: fpu\n",91+ cpuinfoContent: "processor\t: 0\nvendor_id\t: AuthenticAMD\nflags\t: fpu\n",
92- expectedVendor: "AMD",92+ expectedVendor: "AMD",
93 expectedMicrocode: "amd-ucode",93 expectedMicrocode: "amd-ucode",
94- wantErr: false,94+ wantErr: false,
95 },95 },
96 {96 {
97- name: "Unknown CPU vendor",97+ name: "Unknown CPU vendor",
98- cpuinfoContent: "processor\t: 0\nvendor_id\t: UnknownVendor\nflags\t: fpu\n",98+ cpuinfoContent: "processor\t: 0\nvendor_id\t: UnknownVendor\nflags\t: fpu\n",
99- expectedVendor: "Unknown",99+ expectedVendor: "Unknown",
100 expectedMicrocode: "",100 expectedMicrocode: "",
101- wantErr: false,101+ wantErr: false,
102 },102 },
103 {103 {
104- name: "Empty cpuinfo",104+ name: "Empty cpuinfo",
105- cpuinfoContent: "",105+ cpuinfoContent: "",
106- expectedVendor: "Unknown",106+ expectedVendor: "Unknown",
107 expectedMicrocode: "",107 expectedMicrocode: "",
108- wantErr: false,108+ wantErr: false,
109 },109 },
110 }110 }
111 111
@@ -237,21 +237,21 @@ func TestBaseInstallPhaseLoadBasePackages(t *testing.T) {
237 // TestBaseInstallPhaseGenerateFstab tests fstab generation237 // TestBaseInstallPhaseGenerateFstab tests fstab generation
238 func TestBaseInstallPhaseGenerateFstab(t *testing.T) {238 func TestBaseInstallPhaseGenerateFstab(t *testing.T) {
239 tests := []struct {239 tests := []struct {
240- name string240+ name string
241- genfstabResult system.CommandResult241+ genfstabResult system.CommandResult
242- wantErr bool242+ wantErr bool
243- errContains string243+ errContains string
244 }{244 }{
245 {245 {
246- name: "Fstab generation success",246+ name: "Fstab generation success",
247- genfstabResult: system.CommandResult{ExitCode: 0},247+ genfstabResult: system.CommandResult{ExitCode: 0},
248- wantErr: false,248+ wantErr: false,
249 },249 },
250 {250 {
251- name: "Genfstab command failed",251+ name: "Genfstab command failed",
252- genfstabResult: system.CommandResult{ExitCode: 1, Error: fmt.Errorf("permission denied")},252+ genfstabResult: system.CommandResult{ExitCode: 1, Error: fmt.Errorf("permission denied")},
253- wantErr: true,253+ wantErr: true,
254- errContains: "genfstab failed",254+ errContains: "genfstab failed",
255 },255 },
256 }256 }
257 257
@@ -295,31 +295,31 @@ func TestBaseInstallPhaseGenerateFstab(t *testing.T) {
295 // TestBaseInstallPhasePostCheck tests installation validation295 // TestBaseInstallPhasePostCheck tests installation validation
296 func TestBaseInstallPhasePostCheck(t *testing.T) {296 func TestBaseInstallPhasePostCheck(t *testing.T) {
297 tests := []struct {297 tests := []struct {
298- name string298+ name string
299- usrDirExists bool299+ usrDirExists bool
300- fstabFileExists bool300+ fstabFileExists bool
301- wantErr bool301+ wantErr bool
302- errContains string302+ errContains string
303 }{303 }{
304 {304 {
305- name: "Both /mnt/usr and /mnt/etc/fstab exist",305+ name: "Both /mnt/usr and /mnt/etc/fstab exist",
306- usrDirExists: true,306+ usrDirExists: true,
307- fstabFileExists: true,307+ fstabFileExists: true,
308- wantErr: false,308+ wantErr: false,
309 },309 },
310 {310 {
311- name: "/mnt/usr does not exist",311+ name: "/mnt/usr does not exist",
312- usrDirExists: false,312+ usrDirExists: false,
313- fstabFileExists: true,313+ fstabFileExists: true,
314- wantErr: true,314+ wantErr: true,
315- errContains: "/mnt/usr does not exist",315+ errContains: "/mnt/usr does not exist",
316 },316 },
317 {317 {
318- name: "/mnt/etc/fstab does not exist",318+ name: "/mnt/etc/fstab does not exist",
319- usrDirExists: true,319+ usrDirExists: true,
320- fstabFileExists: false,320+ fstabFileExists: false,
321- wantErr: true,321+ wantErr: true,
322- errContains: "fstab was not created",322+ errContains: "fstab was not created",
323 },323 },
324 }324 }
325 325
M internal/phases/boot.go +9 -9
@@ -15,9 +15,9 @@ import (
1515 // BootPhase handles bootloader installation
1616 type BootPhase struct {
1717 *BasePhase
18- fs interfaces.FileSystem
19- sysExec interfaces.SystemExecutor
20- chrExec interfaces.ChrootExecutor
18+ fs interfaces.FileSystem
19+ sysExec interfaces.SystemExecutor
20+ chrExec interfaces.ChrootExecutor
2121 }
2222
2323 // NewBootPhase creates a new boot phase
@@ -119,7 +119,7 @@ func (p *BootPhase) configureMkinitcpio(progressChan chan<- ProgressUpdate) erro
119119
120120 // Regenerate initramfs
121121 p.SendOutput(progressChan, "Regenerating initramfs...")
122- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "mkinitcpio -P"); err != nil {
122+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "mkinitcpio -P"); err != nil {
123123 return fmt.Errorf("failed to regenerate initramfs: %w", err)
124124 }
125125
@@ -134,7 +134,7 @@ func (p *BootPhase) installLimine(progressChan chan<- ProgressUpdate) error {
134134
135135 // Install Limine to disk (BIOS - optional, may fail on UEFI-only)
136136 biosCmd := fmt.Sprintf("limine bios-install %s", p.config.TargetDisk)
137- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, biosCmd); {
137+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, biosCmd); {
138138 case err != nil:
139139 p.SendOutput(progressChan, "[WARN] BIOS installation skipped (UEFI-only system)")
140140 default:
@@ -224,8 +224,8 @@ func (p *BootPhase) configureLimine(progressChan chan<- ProgressUpdate) error {
224224 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL}}", p.config.KernelChoice)
225225 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL_PARAMS}}", kernelParams)
226226
227- // Write Limine configuration
228- limineConfigPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
227+ // Write Limine configuration to /boot/limine.conf (standard Limine search path)
228+ limineConfigPath := config.PathMntBootLimineConf
229229 if err := p.fs.WriteFile(limineConfigPath, []byte(limineConfig), 0644); err != nil {
230230 return fmt.Errorf("failed to write Limine config: %w", err)
231231 }
@@ -253,7 +253,7 @@ func (p *BootPhase) createUEFIEntry(progressChan chan<- ProgressUpdate) error {
253253 config.UEFIBootLoader,
254254 )
255255
256- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, efiCmd); err != nil {
256+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, efiCmd); err != nil {
257257 return fmt.Errorf("failed to create UEFI boot entry: %w", err)
258258 }
259259
@@ -287,7 +287,7 @@ func (p *BootPhase) PostCheck() error {
287287 }
288288
289289 // Verify Limine config exists
290- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
290+ configPath := config.PathMntBootLimineConf
291291 if _, err := p.fs.Stat(configPath); p.fs.IsNotExist(err) {
292292 return fmt.Errorf("Limine config was not created")
293293 }
@@ -15,9 +15,9 @@ import (
15 // BootPhase handles bootloader installation15 // BootPhase handles bootloader installation
16 type BootPhase struct {16 type BootPhase struct {
17 *BasePhase17 *BasePhase
18- fs interfaces.FileSystem18+ fs interfaces.FileSystem
19- sysExec interfaces.SystemExecutor19+ sysExec interfaces.SystemExecutor
20- chrExec interfaces.ChrootExecutor20+ chrExec interfaces.ChrootExecutor
21 }21 }
22 22
23 // NewBootPhase creates a new boot phase23 // NewBootPhase creates a new boot phase
@@ -119,7 +119,7 @@ func (p *BootPhase) configureMkinitcpio(progressChan chan<- ProgressUpdate) erro
119 119
120 // Regenerate initramfs120 // Regenerate initramfs
121 p.SendOutput(progressChan, "Regenerating initramfs...")121 p.SendOutput(progressChan, "Regenerating initramfs...")
122- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "mkinitcpio -P"); err != nil {122+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "mkinitcpio -P"); err != nil {
123 return fmt.Errorf("failed to regenerate initramfs: %w", err)123 return fmt.Errorf("failed to regenerate initramfs: %w", err)
124 }124 }
125 125
@@ -134,7 +134,7 @@ func (p *BootPhase) installLimine(progressChan chan<- ProgressUpdate) error {
134 134
135 // Install Limine to disk (BIOS - optional, may fail on UEFI-only)135 // Install Limine to disk (BIOS - optional, may fail on UEFI-only)
136 biosCmd := fmt.Sprintf("limine bios-install %s", p.config.TargetDisk)136 biosCmd := fmt.Sprintf("limine bios-install %s", p.config.TargetDisk)
137- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, biosCmd); {137+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, biosCmd); {
138 case err != nil:138 case err != nil:
139 p.SendOutput(progressChan, "[WARN] BIOS installation skipped (UEFI-only system)")139 p.SendOutput(progressChan, "[WARN] BIOS installation skipped (UEFI-only system)")
140 default:140 default:
@@ -224,8 +224,8 @@ func (p *BootPhase) configureLimine(progressChan chan<- ProgressUpdate) error {
224 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL}}", p.config.KernelChoice)224 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL}}", p.config.KernelChoice)
225 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL_PARAMS}}", kernelParams)225 limineConfig = strings.ReplaceAll(limineConfig, "{{KERNEL_PARAMS}}", kernelParams)
226 226
227- // Write Limine configuration227+ // Write Limine configuration to /boot/limine.conf (standard Limine search path)
228- limineConfigPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)228+ limineConfigPath := config.PathMntBootLimineConf
229 if err := p.fs.WriteFile(limineConfigPath, []byte(limineConfig), 0644); err != nil {229 if err := p.fs.WriteFile(limineConfigPath, []byte(limineConfig), 0644); err != nil {
230 return fmt.Errorf("failed to write Limine config: %w", err)230 return fmt.Errorf("failed to write Limine config: %w", err)
231 }231 }
@@ -253,7 +253,7 @@ func (p *BootPhase) createUEFIEntry(progressChan chan<- ProgressUpdate) error {
253 config.UEFIBootLoader,253 config.UEFIBootLoader,
254 )254 )
255 255
256- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, efiCmd); err != nil {256+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, efiCmd); err != nil {
257 return fmt.Errorf("failed to create UEFI boot entry: %w", err)257 return fmt.Errorf("failed to create UEFI boot entry: %w", err)
258 }258 }
259 259
@@ -287,7 +287,7 @@ func (p *BootPhase) PostCheck() error {
287 }287 }
288 288
289 // Verify Limine config exists289 // Verify Limine config exists
290- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)290+ configPath := config.PathMntBootLimineConf
291 if _, err := p.fs.Stat(configPath); p.fs.IsNotExist(err) {291 if _, err := p.fs.Stat(configPath); p.fs.IsNotExist(err) {
292 return fmt.Errorf("Limine config was not created")292 return fmt.Errorf("Limine config was not created")
293 }293 }
M internal/phases/boot_test.go +17 -17
@@ -15,10 +15,10 @@ import (
1515 // TestBootPhasePreCheck tests boot prerequisites
1616 func TestBootPhasePreCheck(t *testing.T) {
1717 tests := []struct {
18- name string
19- setupMocks func(*mocks.MockSystemExecutor)
20- wantErr bool
21- errContains string
18+ name string
19+ setupMocks func(*mocks.MockSystemExecutor)
20+ wantErr bool
21+ errContains string
2222 }{
2323 {
2424 name: "Both /mnt and /mnt/boot mounted",
@@ -86,9 +86,9 @@ func TestBootPhasePreCheck(t *testing.T) {
8686 // TestBootPhaseExtractPartitionNumber tests partition number extraction
8787 func TestBootPhaseExtractPartitionNumber(t *testing.T) {
8888 tests := []struct {
89- name string
90- devicePath string
91- expectedNum string
89+ name string
90+ devicePath string
91+ expectedNum string
9292 }{
9393 {
9494 name: "SATA partition /dev/sda1",
@@ -167,7 +167,7 @@ func TestBootPhasePostCheck(t *testing.T) {
167167 name: "Both bootloader and config exist",
168168 setupMocks: func(mockFS *mocks.MockFileSystem) {
169169 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)
170- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
170+ configPath := config.PathMntBootLimineConf
171171
172172 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)
173173 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)
@@ -191,7 +191,7 @@ func TestBootPhasePostCheck(t *testing.T) {
191191 name: "Config missing",
192192 setupMocks: func(mockFS *mocks.MockFileSystem) {
193193 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)
194- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
194+ configPath := config.PathMntBootLimineConf
195195
196196 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)
197197 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)
@@ -244,9 +244,9 @@ func TestBootPhasePostCheck(t *testing.T) {
244244 // TestBootPhaseRollback tests boot phase rollback
245245 func TestBootPhaseRollback(t *testing.T) {
246246 tests := []struct {
247- name string
248- setupMocks func(*mocks.MockFileSystem)
249- wantErr bool
247+ name string
248+ setupMocks func(*mocks.MockFileSystem)
249+ wantErr bool
250250 }{
251251 {
252252 name: "Rollback success",
@@ -423,9 +423,9 @@ func TestBootPhaseKernelParameterConstruction(t *testing.T) {
423423 // TestBootPhaseInstallPathConstruction tests install path building
424424 func TestBootPhaseInstallPathConstruction(t *testing.T) {
425425 tests := []struct {
426- name string
427- filename string
428- expected string
426+ name string
427+ filename string
428+ expected string
429429 }{
430430 {
431431 name: "Limine config template",
@@ -470,8 +470,8 @@ func TestBootPhaseInstallPathConstruction(t *testing.T) {
470470 // TestBootPhaseFileSystemOperations tests file system interaction patterns
471471 func TestBootPhaseFileSystemOperations(t *testing.T) {
472472 tests := []struct {
473- name string
474- operation string // "read", "write", "mkdir"
473+ name string
474+ operation string // "read", "write", "mkdir"
475475 }{
476476 {
477477 name: "Mkinitcpio config read",
@@ -15,10 +15,10 @@ import (
15 // TestBootPhasePreCheck tests boot prerequisites15 // TestBootPhasePreCheck tests boot prerequisites
16 func TestBootPhasePreCheck(t *testing.T) {16 func TestBootPhasePreCheck(t *testing.T) {
17 tests := []struct {17 tests := []struct {
18- name string18+ name string
19- setupMocks func(*mocks.MockSystemExecutor)19+ setupMocks func(*mocks.MockSystemExecutor)
20- wantErr bool20+ wantErr bool
21- errContains string21+ errContains string
22 }{22 }{
23 {23 {
24 name: "Both /mnt and /mnt/boot mounted",24 name: "Both /mnt and /mnt/boot mounted",
@@ -86,9 +86,9 @@ func TestBootPhasePreCheck(t *testing.T) {
86 // TestBootPhaseExtractPartitionNumber tests partition number extraction86 // TestBootPhaseExtractPartitionNumber tests partition number extraction
87 func TestBootPhaseExtractPartitionNumber(t *testing.T) {87 func TestBootPhaseExtractPartitionNumber(t *testing.T) {
88 tests := []struct {88 tests := []struct {
89- name string89+ name string
90- devicePath string90+ devicePath string
91- expectedNum string91+ expectedNum string
92 }{92 }{
93 {93 {
94 name: "SATA partition /dev/sda1",94 name: "SATA partition /dev/sda1",
@@ -167,7 +167,7 @@ func TestBootPhasePostCheck(t *testing.T) {
167 name: "Both bootloader and config exist",167 name: "Both bootloader and config exist",
168 setupMocks: func(mockFS *mocks.MockFileSystem) {168 setupMocks: func(mockFS *mocks.MockFileSystem) {
169 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)169 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)
170- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)170+ configPath := config.PathMntBootLimineConf
171 171
172 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)172 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)
173 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)173 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)
@@ -191,7 +191,7 @@ func TestBootPhasePostCheck(t *testing.T) {
191 name: "Config missing",191 name: "Config missing",
192 setupMocks: func(mockFS *mocks.MockFileSystem) {192 setupMocks: func(mockFS *mocks.MockFileSystem) {
193 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)193 bootloaderPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineBootloader)
194- configPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)194+ configPath := config.PathMntBootLimineConf
195 195
196 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)196 mockFS.EXPECT().Stat(bootloaderPath).Return(mockFileInfo{}, nil).Times(1)
197 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)197 mockFS.EXPECT().IsNotExist(gomock.Any()).Return(false).Times(1)
@@ -244,9 +244,9 @@ func TestBootPhasePostCheck(t *testing.T) {
244 // TestBootPhaseRollback tests boot phase rollback244 // TestBootPhaseRollback tests boot phase rollback
245 func TestBootPhaseRollback(t *testing.T) {245 func TestBootPhaseRollback(t *testing.T) {
246 tests := []struct {246 tests := []struct {
247- name string247+ name string
248- setupMocks func(*mocks.MockFileSystem)248+ setupMocks func(*mocks.MockFileSystem)
249- wantErr bool249+ wantErr bool
250 }{250 }{
251 {251 {
252 name: "Rollback success",252 name: "Rollback success",
@@ -423,9 +423,9 @@ func TestBootPhaseKernelParameterConstruction(t *testing.T) {
423 // TestBootPhaseInstallPathConstruction tests install path building423 // TestBootPhaseInstallPathConstruction tests install path building
424 func TestBootPhaseInstallPathConstruction(t *testing.T) {424 func TestBootPhaseInstallPathConstruction(t *testing.T) {
425 tests := []struct {425 tests := []struct {
426- name string426+ name string
427- filename string427+ filename string
428- expected string428+ expected string
429 }{429 }{
430 {430 {
431 name: "Limine config template",431 name: "Limine config template",
@@ -470,8 +470,8 @@ func TestBootPhaseInstallPathConstruction(t *testing.T) {
470 // TestBootPhaseFileSystemOperations tests file system interaction patterns470 // TestBootPhaseFileSystemOperations tests file system interaction patterns
471 func TestBootPhaseFileSystemOperations(t *testing.T) {471 func TestBootPhaseFileSystemOperations(t *testing.T) {
472 tests := []struct {472 tests := []struct {
473- name string473+ name string
474- operation string // "read", "write", "mkdir"474+ operation string // "read", "write", "mkdir"
475 }{475 }{
476 {476 {
477 name: "Mkinitcpio config read",477 name: "Mkinitcpio config read",
M internal/phases/bootstrap_test.go +3 -3
@@ -17,9 +17,9 @@ import (
1717 // TestBootstrapPhasePreCheck tests internet connectivity validation
1818 func TestBootstrapPhasePreCheck(t *testing.T) {
1919 tests := []struct {
20- name string
21- setupMocks func(*mocks.MockHTTPClient)
22- wantErr bool
20+ name string
21+ setupMocks func(*mocks.MockHTTPClient)
22+ wantErr bool
2323 errContains string
2424 }{
2525 {
@@ -17,9 +17,9 @@ import (
17 // TestBootstrapPhasePreCheck tests internet connectivity validation17 // TestBootstrapPhasePreCheck tests internet connectivity validation
18 func TestBootstrapPhasePreCheck(t *testing.T) {18 func TestBootstrapPhasePreCheck(t *testing.T) {
19 tests := []struct {19 tests := []struct {
20- name string20+ name string
21- setupMocks func(*mocks.MockHTTPClient)21+ setupMocks func(*mocks.MockHTTPClient)
22- wantErr bool22+ wantErr bool
23 errContains string23 errContains string
24 }{24 }{
25 {25 {
M internal/phases/partitioning_test.go +12 -12
@@ -16,10 +16,10 @@ import (
1616 // TestPartitioningPhasePreCheck tests partitioning prerequisites
1717 func TestPartitioningPhasePreCheck(t *testing.T) {
1818 tests := []struct {
19- name string
20- targetDisk string
21- wantErr bool
22- errContains string
19+ name string
20+ targetDisk string
21+ wantErr bool
22+ errContains string
2323 }{
2424 {
2525 name: "Valid target disk",
@@ -78,10 +78,10 @@ func TestPartitioningPhasePreCheck(t *testing.T) {
7878 // TestPartitioningPhasePartitionNaming tests partition naming logic
7979 func TestPartitioningPhasePartitionNaming(t *testing.T) {
8080 tests := []struct {
81- name string
82- targetDisk string
83- expectedEFI string
84- expectedRoot string
81+ name string
82+ targetDisk string
83+ expectedEFI string
84+ expectedRoot string
8585 }{
8686 {
8787 name: "NVMe disk naming",
@@ -262,10 +262,10 @@ func TestPartitioningPhaseEncryptionValidation(t *testing.T) {
262262 // TestPartitioningPhasePostCheck tests mount point validation
263263 func TestPartitioningPhasePostCheck(t *testing.T) {
264264 tests := []struct {
265- name string
266- setupMocks func(*mocks.MockSystemExecutor)
267- wantErr bool
268- errContains string
265+ name string
266+ setupMocks func(*mocks.MockSystemExecutor)
267+ wantErr bool
268+ errContains string
269269 }{
270270 {
271271 name: "/mnt is mounted - postcheck passes",
@@ -16,10 +16,10 @@ import (
16 // TestPartitioningPhasePreCheck tests partitioning prerequisites16 // TestPartitioningPhasePreCheck tests partitioning prerequisites
17 func TestPartitioningPhasePreCheck(t *testing.T) {17 func TestPartitioningPhasePreCheck(t *testing.T) {
18 tests := []struct {18 tests := []struct {
19- name string19+ name string
20- targetDisk string20+ targetDisk string
21- wantErr bool21+ wantErr bool
22- errContains string22+ errContains string
23 }{23 }{
24 {24 {
25 name: "Valid target disk",25 name: "Valid target disk",
@@ -78,10 +78,10 @@ func TestPartitioningPhasePreCheck(t *testing.T) {
78 // TestPartitioningPhasePartitionNaming tests partition naming logic78 // TestPartitioningPhasePartitionNaming tests partition naming logic
79 func TestPartitioningPhasePartitionNaming(t *testing.T) {79 func TestPartitioningPhasePartitionNaming(t *testing.T) {
80 tests := []struct {80 tests := []struct {
81- name string81+ name string
82- targetDisk string82+ targetDisk string
83- expectedEFI string83+ expectedEFI string
84- expectedRoot string84+ expectedRoot string
85 }{85 }{
86 {86 {
87 name: "NVMe disk naming",87 name: "NVMe disk naming",
@@ -262,10 +262,10 @@ func TestPartitioningPhaseEncryptionValidation(t *testing.T) {
262 // TestPartitioningPhasePostCheck tests mount point validation262 // TestPartitioningPhasePostCheck tests mount point validation
263 func TestPartitioningPhasePostCheck(t *testing.T) {263 func TestPartitioningPhasePostCheck(t *testing.T) {
264 tests := []struct {264 tests := []struct {
265- name string265+ name string
266- setupMocks func(*mocks.MockSystemExecutor)266+ setupMocks func(*mocks.MockSystemExecutor)
267- wantErr bool267+ wantErr bool
268- errContains string268+ errContains string
269 }{269 }{
270 {270 {
271 name: "/mnt is mounted - postcheck passes",271 name: "/mnt is mounted - postcheck passes",
M internal/phases/phase.go +8 -8
@@ -44,14 +44,14 @@ type PhaseResult struct {
4444
4545 // ProgressUpdate represents a progress update from a phase
4646 type ProgressUpdate struct {
47- PhaseName string
48- Step string
49- OutputLine string
50- Current int
51- Total int
52- IsComplete bool
53- IsError bool
54- ErrorMsg string
47+ PhaseName string
48+ Step string
49+ OutputLine string
50+ Current int
51+ Total int
52+ IsComplete bool
53+ IsError bool
54+ ErrorMsg string
5555 }
5656
5757 // Phase represents a single installation phase
@@ -44,14 +44,14 @@ type PhaseResult struct {
44 44
45 // ProgressUpdate represents a progress update from a phase45 // ProgressUpdate represents a progress update from a phase
46 type ProgressUpdate struct {46 type ProgressUpdate struct {
47- PhaseName string47+ PhaseName string
48- Step string48+ Step string
49- OutputLine string49+ OutputLine string
50- Current int50+ Current int
51- Total int51+ Total int
52- IsComplete bool52+ IsComplete bool
53- IsError bool53+ IsError bool
54- ErrorMsg string54+ ErrorMsg string
55 }55 }
56 56
57 // Phase represents a single installation phase57 // Phase represents a single installation phase
M internal/phases/postinstall.go +8 -8
@@ -178,7 +178,7 @@ func (p *PostInstallPhase) installBootLogo(progressChan chan<- ProgressUpdate) e
178178 p.SendOutput(progressChan, "[OK] Logo downloaded")
179179
180180 // Update Limine config
181- limineConf := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
181+ limineConf := config.PathMntBootLimineConf
182182 content, err := p.fs.ReadFile(limineConf)
183183 switch {
184184 case err != nil:
@@ -264,7 +264,7 @@ func (p *PostInstallPhase) configurePlymouth(progressChan chan<- ProgressUpdate)
264264
265265 // Set as default theme
266266 setThemeCmd := fmt.Sprintf("plymouth-set-default-theme %s", config.PlymouthThemeName)
267- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, setThemeCmd); {
267+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, setThemeCmd); {
268268 case err != nil:
269269 return fmt.Errorf("failed to set Plymouth theme: %w", err)
270270 }
@@ -273,7 +273,7 @@ func (p *PostInstallPhase) configurePlymouth(progressChan chan<- ProgressUpdate)
273273
274274 // Regenerate initramfs
275275 p.SendOutput(progressChan, "Regenerating initramfs with Plymouth...")
276- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "mkinitcpio -P"); {
276+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "mkinitcpio -P"); {
277277 case err != nil:
278278 return fmt.Errorf("failed to regenerate initramfs: %w", err)
279279 }
@@ -287,7 +287,7 @@ func (p *PostInstallPhase) configureSnapper(progressChan chan<- ProgressUpdate)
287287 p.SendOutput(progressChan, "Installing limine-snapper-sync...")
288288
289289 // Install limine-snapper-sync
290- switch err := p.chrExec.ChrootPacman(p.logger.LogPath(),config.PathMnt, "-S", "--needed", "limine-snapper-sync"); {
290+ switch err := p.chrExec.ChrootPacman(p.logger.LogPath(), config.PathMnt, "-S", "--needed", "limine-snapper-sync"); {
291291 case err != nil:
292292 return fmt.Errorf("failed to install limine-snapper-sync: %w", err)
293293 }
@@ -295,7 +295,7 @@ func (p *PostInstallPhase) configureSnapper(progressChan chan<- ProgressUpdate)
295295 p.SendOutput(progressChan, "[OK] Package installed")
296296
297297 // Get kernel cmdline from existing Limine config
298- limineConf := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
298+ limineConf := config.PathMntBootLimineConf
299299 content, err := p.fs.ReadFile(limineConf)
300300 switch {
301301 case err != nil:
@@ -511,7 +511,7 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er
511511 }
512512
513513 for _, gitCmd := range gitCommands {
514- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, gitCmd); {
514+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, gitCmd); {
515515 case err != nil:
516516 // Non-fatal
517517 p.SendOutput(progressChan, "[WARN] Failed to configure git delta")
@@ -563,7 +563,7 @@ func (p *PostInstallPhase) setShellOwnership(userHome, username string) error {
563563 relativeHome := strings.TrimPrefix(userHome, config.PathMnt)
564564 chownCmd := fmt.Sprintf("chown -R %s:%s %s/.local %s/.bashrc",
565565 username, username, relativeHome, relativeHome)
566- return p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, chownCmd)
566+ return p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, chownCmd)
567567 }
568568
569569 // applyThemes applies bleu-theme to CLI tools
@@ -664,7 +664,7 @@ func (p *PostInstallPhase) verifyInstallation(progressChan chan<- ProgressUpdate
664664 }
665665
666666 // Verify Limine config
667- limineConfPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)
667+ limineConfPath := config.PathMntBootLimineConf
668668 switch content, err := p.fs.ReadFile(limineConfPath); {
669669 case err != nil:
670670 p.SendOutput(progressChan, "[ERROR] Limine config missing")
@@ -178,7 +178,7 @@ func (p *PostInstallPhase) installBootLogo(progressChan chan<- ProgressUpdate) e
178 p.SendOutput(progressChan, "[OK] Logo downloaded")178 p.SendOutput(progressChan, "[OK] Logo downloaded")
179 179
180 // Update Limine config180 // Update Limine config
181- limineConf := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)181+ limineConf := config.PathMntBootLimineConf
182 content, err := p.fs.ReadFile(limineConf)182 content, err := p.fs.ReadFile(limineConf)
183 switch {183 switch {
184 case err != nil:184 case err != nil:
@@ -264,7 +264,7 @@ func (p *PostInstallPhase) configurePlymouth(progressChan chan<- ProgressUpdate)
264 264
265 // Set as default theme265 // Set as default theme
266 setThemeCmd := fmt.Sprintf("plymouth-set-default-theme %s", config.PlymouthThemeName)266 setThemeCmd := fmt.Sprintf("plymouth-set-default-theme %s", config.PlymouthThemeName)
267- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, setThemeCmd); {267+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, setThemeCmd); {
268 case err != nil:268 case err != nil:
269 return fmt.Errorf("failed to set Plymouth theme: %w", err)269 return fmt.Errorf("failed to set Plymouth theme: %w", err)
270 }270 }
@@ -273,7 +273,7 @@ func (p *PostInstallPhase) configurePlymouth(progressChan chan<- ProgressUpdate)
273 273
274 // Regenerate initramfs274 // Regenerate initramfs
275 p.SendOutput(progressChan, "Regenerating initramfs with Plymouth...")275 p.SendOutput(progressChan, "Regenerating initramfs with Plymouth...")
276- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "mkinitcpio -P"); {276+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "mkinitcpio -P"); {
277 case err != nil:277 case err != nil:
278 return fmt.Errorf("failed to regenerate initramfs: %w", err)278 return fmt.Errorf("failed to regenerate initramfs: %w", err)
279 }279 }
@@ -287,7 +287,7 @@ func (p *PostInstallPhase) configureSnapper(progressChan chan<- ProgressUpdate)
287 p.SendOutput(progressChan, "Installing limine-snapper-sync...")287 p.SendOutput(progressChan, "Installing limine-snapper-sync...")
288 288
289 // Install limine-snapper-sync289 // Install limine-snapper-sync
290- switch err := p.chrExec.ChrootPacman(p.logger.LogPath(),config.PathMnt, "-S", "--needed", "limine-snapper-sync"); {290+ switch err := p.chrExec.ChrootPacman(p.logger.LogPath(), config.PathMnt, "-S", "--needed", "limine-snapper-sync"); {
291 case err != nil:291 case err != nil:
292 return fmt.Errorf("failed to install limine-snapper-sync: %w", err)292 return fmt.Errorf("failed to install limine-snapper-sync: %w", err)
293 }293 }
@@ -295,7 +295,7 @@ func (p *PostInstallPhase) configureSnapper(progressChan chan<- ProgressUpdate)
295 p.SendOutput(progressChan, "[OK] Package installed")295 p.SendOutput(progressChan, "[OK] Package installed")
296 296
297 // Get kernel cmdline from existing Limine config297 // Get kernel cmdline from existing Limine config
298- limineConf := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)298+ limineConf := config.PathMntBootLimineConf
299 content, err := p.fs.ReadFile(limineConf)299 content, err := p.fs.ReadFile(limineConf)
300 switch {300 switch {
301 case err != nil:301 case err != nil:
@@ -511,7 +511,7 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er
511 }511 }
512 512
513 for _, gitCmd := range gitCommands {513 for _, gitCmd := range gitCommands {
514- switch err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, gitCmd); {514+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, gitCmd); {
515 case err != nil:515 case err != nil:
516 // Non-fatal516 // Non-fatal
517 p.SendOutput(progressChan, "[WARN] Failed to configure git delta")517 p.SendOutput(progressChan, "[WARN] Failed to configure git delta")
@@ -563,7 +563,7 @@ func (p *PostInstallPhase) setShellOwnership(userHome, username string) error {
563 relativeHome := strings.TrimPrefix(userHome, config.PathMnt)563 relativeHome := strings.TrimPrefix(userHome, config.PathMnt)
564 chownCmd := fmt.Sprintf("chown -R %s:%s %s/.local %s/.bashrc",564 chownCmd := fmt.Sprintf("chown -R %s:%s %s/.local %s/.bashrc",
565 username, username, relativeHome, relativeHome)565 username, username, relativeHome, relativeHome)
566- return p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, chownCmd)566+ return p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, chownCmd)
567 }567 }
568 568
569 // applyThemes applies bleu-theme to CLI tools569 // applyThemes applies bleu-theme to CLI tools
@@ -664,7 +664,7 @@ func (p *PostInstallPhase) verifyInstallation(progressChan chan<- ProgressUpdate
664 }664 }
665 665
666 // Verify Limine config666 // Verify Limine config
667- limineConfPath := filepath.Join(config.PathMntBootEFILimine, config.FileLimineConfig)667+ limineConfPath := config.PathMntBootLimineConf
668 switch content, err := p.fs.ReadFile(limineConfPath); {668 switch content, err := p.fs.ReadFile(limineConfPath); {
669 case err != nil:669 case err != nil:
670 p.SendOutput(progressChan, "[ERROR] Limine config missing")670 p.SendOutput(progressChan, "[ERROR] Limine config missing")
M internal/phases/postinstall_test.go +8 -8
@@ -15,10 +15,10 @@ import (
1515 // TestPostInstallPhasePreCheck tests post-install prerequisites
1616 func TestPostInstallPhasePreCheck(t *testing.T) {
1717 tests := []struct {
18- name string
19- setupMocks func(*mocks.MockFileSystem, *mocks.MockSystemExecutor)
20- wantErr bool
21- errContains string
18+ name string
19+ setupMocks func(*mocks.MockFileSystem, *mocks.MockSystemExecutor)
20+ wantErr bool
21+ errContains string
2222 }{
2323 {
2424 name: "/mnt mounted and boot directory exists",
@@ -270,8 +270,8 @@ func TestPostInstallPhaseExecute(t *testing.T) {
270270 // TestPostInstallPhaseEncryptionHandling tests encryption-aware operations
271271 func TestPostInstallPhaseEncryptionHandling(t *testing.T) {
272272 tests := []struct {
273- name string
274- encryptionType string
273+ name string
274+ encryptionType string
275275 expectedClosing bool
276276 }{
277277 {
@@ -331,8 +331,8 @@ func TestPostInstallPhaseEncryptionHandling(t *testing.T) {
331331 // TestPostInstallPhaseFileSystemOperations tests file system interaction patterns
332332 func TestPostInstallPhaseFileSystemOperations(t *testing.T) {
333333 tests := []struct {
334- name string
335- operation string // "read", "write", "mkdir", "create"
334+ name string
335+ operation string // "read", "write", "mkdir", "create"
336336 }{
337337 {
338338 name: "Read pacman.conf",
@@ -15,10 +15,10 @@ import (
15 // TestPostInstallPhasePreCheck tests post-install prerequisites15 // TestPostInstallPhasePreCheck tests post-install prerequisites
16 func TestPostInstallPhasePreCheck(t *testing.T) {16 func TestPostInstallPhasePreCheck(t *testing.T) {
17 tests := []struct {17 tests := []struct {
18- name string18+ name string
19- setupMocks func(*mocks.MockFileSystem, *mocks.MockSystemExecutor)19+ setupMocks func(*mocks.MockFileSystem, *mocks.MockSystemExecutor)
20- wantErr bool20+ wantErr bool
21- errContains string21+ errContains string
22 }{22 }{
23 {23 {
24 name: "/mnt mounted and boot directory exists",24 name: "/mnt mounted and boot directory exists",
@@ -270,8 +270,8 @@ func TestPostInstallPhaseExecute(t *testing.T) {
270 // TestPostInstallPhaseEncryptionHandling tests encryption-aware operations270 // TestPostInstallPhaseEncryptionHandling tests encryption-aware operations
271 func TestPostInstallPhaseEncryptionHandling(t *testing.T) {271 func TestPostInstallPhaseEncryptionHandling(t *testing.T) {
272 tests := []struct {272 tests := []struct {
273- name string273+ name string
274- encryptionType string274+ encryptionType string
275 expectedClosing bool275 expectedClosing bool
276 }{276 }{
277 {277 {
@@ -331,8 +331,8 @@ func TestPostInstallPhaseEncryptionHandling(t *testing.T) {
331 // TestPostInstallPhaseFileSystemOperations tests file system interaction patterns331 // TestPostInstallPhaseFileSystemOperations tests file system interaction patterns
332 func TestPostInstallPhaseFileSystemOperations(t *testing.T) {332 func TestPostInstallPhaseFileSystemOperations(t *testing.T) {
333 tests := []struct {333 tests := []struct {
334- name string334+ name string
335- operation string // "read", "write", "mkdir", "create"335+ operation string // "read", "write", "mkdir", "create"
336 }{336 }{
337 {337 {
338 name: "Read pacman.conf",338 name: "Read pacman.conf",
M internal/phases/preflight_test.go +4 -4
@@ -14,10 +14,10 @@ import (
1414 // TestPreflightPhasePreCheck tests the PreCheck validation
1515 func TestPreflightPhasePreCheck(t *testing.T) {
1616 tests := []struct {
17- name string
18- setupMocks func(*mocks.MockFileSystem, *mocks.MockCommandExecutor)
19- wantErr bool
20- errContains string
17+ name string
18+ setupMocks func(*mocks.MockFileSystem, *mocks.MockCommandExecutor)
19+ wantErr bool
20+ errContains string
2121 }{
2222 {
2323 name: "Arch Linux detection - file not found",
@@ -14,10 +14,10 @@ import (
14 // TestPreflightPhasePreCheck tests the PreCheck validation14 // TestPreflightPhasePreCheck tests the PreCheck validation
15 func TestPreflightPhasePreCheck(t *testing.T) {15 func TestPreflightPhasePreCheck(t *testing.T) {
16 tests := []struct {16 tests := []struct {
17- name string17+ name string
18- setupMocks func(*mocks.MockFileSystem, *mocks.MockCommandExecutor)18+ setupMocks func(*mocks.MockFileSystem, *mocks.MockCommandExecutor)
19- wantErr bool19+ wantErr bool
20- errContains string20+ errContains string
21 }{21 }{
22 {22 {
23 name: "Arch Linux detection - file not found",23 name: "Arch Linux detection - file not found",
M internal/phases/repos.go +5 -5
@@ -46,11 +46,11 @@ func IsValidAURHelper(helper string) bool {
4646 // ReposPhase handles repository configuration
4747 type ReposPhase struct {
4848 *BasePhase
49- fs interfaces.FileSystem
50- sysExec interfaces.SystemExecutor
51- chrExec interfaces.ChrootExecutor
52- chaoticConfig map[string]string
53- chaoticAUREnabled bool
49+ fs interfaces.FileSystem
50+ sysExec interfaces.SystemExecutor
51+ chrExec interfaces.ChrootExecutor
52+ chaoticConfig map[string]string
53+ chaoticAUREnabled bool
5454 }
5555
5656 // NewReposPhase creates a new repos phase
@@ -46,11 +46,11 @@ func IsValidAURHelper(helper string) bool {
46 // ReposPhase handles repository configuration46 // ReposPhase handles repository configuration
47 type ReposPhase struct {47 type ReposPhase struct {
48 *BasePhase48 *BasePhase
49- fs interfaces.FileSystem49+ fs interfaces.FileSystem
50- sysExec interfaces.SystemExecutor50+ sysExec interfaces.SystemExecutor
51- chrExec interfaces.ChrootExecutor51+ chrExec interfaces.ChrootExecutor
52- chaoticConfig map[string]string52+ chaoticConfig map[string]string
53- chaoticAUREnabled bool53+ chaoticAUREnabled bool
54 }54 }
55 55
56 // NewReposPhase creates a new repos phase56 // NewReposPhase creates a new repos phase
M internal/phases/repos_test.go +6 -6
@@ -127,8 +127,8 @@ func TestMultilibEdgeCases(t *testing.T) {
127127 checkFunc func(string) bool
128128 }{
129129 {
130- name: "Empty file",
131- input: "",
130+ name: "Empty file",
131+ input: "",
132132 expectError: false,
133133 checkFunc: func(s string) bool {
134134 return s == ""
@@ -652,8 +652,8 @@ func TestPackageFiltering(t *testing.T) {
652652 wantError: false,
653653 },
654654 {
655- name: "only debug package (should filter all)",
656- output: `/tmp/yay/yay-debug-12.5.2-2-x86_64.pkg.tar.zst`,
655+ name: "only debug package (should filter all)",
656+ output: `/tmp/yay/yay-debug-12.5.2-2-x86_64.pkg.tar.zst`,
657657 wantPackage: "",
658658 wantError: true,
659659 },
@@ -664,8 +664,8 @@ func TestPackageFiltering(t *testing.T) {
664664 wantError: true,
665665 },
666666 {
667- name: "single main package without debug",
668- output: `/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst`,
667+ name: "single main package without debug",
668+ output: `/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst`,
669669 wantPackage: "/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst",
670670 wantError: false,
671671 },
@@ -127,8 +127,8 @@ func TestMultilibEdgeCases(t *testing.T) {
127 checkFunc func(string) bool127 checkFunc func(string) bool
128 }{128 }{
129 {129 {
130- name: "Empty file",130+ name: "Empty file",
131- input: "",131+ input: "",
132 expectError: false,132 expectError: false,
133 checkFunc: func(s string) bool {133 checkFunc: func(s string) bool {
134 return s == ""134 return s == ""
@@ -652,8 +652,8 @@ func TestPackageFiltering(t *testing.T) {
652 wantError: false,652 wantError: false,
653 },653 },
654 {654 {
655- name: "only debug package (should filter all)",655+ name: "only debug package (should filter all)",
656- output: `/tmp/yay/yay-debug-12.5.2-2-x86_64.pkg.tar.zst`,656+ output: `/tmp/yay/yay-debug-12.5.2-2-x86_64.pkg.tar.zst`,
657 wantPackage: "",657 wantPackage: "",
658 wantError: true,658 wantError: true,
659 },659 },
@@ -664,8 +664,8 @@ func TestPackageFiltering(t *testing.T) {
664 wantError: true,664 wantError: true,
665 },665 },
666 {666 {
667- name: "single main package without debug",667+ name: "single main package without debug",
668- output: `/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst`,668+ output: `/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst`,
669 wantPackage: "/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst",669 wantPackage: "/tmp/yay/yay-12.5.2-2-x86_64.pkg.tar.zst",
670 wantError: false,670 wantError: false,
671 },671 },
M internal/phases/systemconfig.go +5 -5
@@ -97,12 +97,12 @@ func (p *ConfigPhase) configureSystem(progressChan chan<- ProgressUpdate) error
9797 // Set timezone
9898 timezonePath := filepath.Join(config.PathUsrShareZoneinfo, p.config.Timezone)
9999 tzCmd := fmt.Sprintf("ln -sf %s %s", timezonePath, config.PathEtcLocaltime)
100- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, tzCmd); err != nil {
100+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, tzCmd); err != nil {
101101 return fmt.Errorf("failed to set timezone: %w", err)
102102 }
103103
104104 // Set hardware clock
105- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "hwclock --systohc"); err != nil {
105+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "hwclock --systohc"); err != nil {
106106 return fmt.Errorf("failed to set hardware clock: %w", err)
107107 }
108108
@@ -114,7 +114,7 @@ func (p *ConfigPhase) configureSystem(progressChan chan<- ProgressUpdate) error
114114 return fmt.Errorf("failed to write locale.gen: %w", err)
115115 }
116116
117- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "locale-gen"); err != nil {
117+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "locale-gen"); err != nil {
118118 return fmt.Errorf("failed to generate locale: %w", err)
119119 }
120120
@@ -159,7 +159,7 @@ func (p *ConfigPhase) configureNetwork(progressChan chan<- ProgressUpdate) error
159159 p.SendOutput(progressChan, "Configuring network...")
160160
161161 // Enable NetworkManager service
162- if err := p.chrExec.ChrootSystemctl(p.logger.LogPath(),config.PathMnt, "enable", config.ServiceNetworkManager); err != nil {
162+ if err := p.chrExec.ChrootSystemctl(p.logger.LogPath(), config.PathMnt, "enable", config.ServiceNetworkManager); err != nil {
163163 return fmt.Errorf("failed to enable NetworkManager: %w", err)
164164 }
165165
@@ -174,7 +174,7 @@ func (p *ConfigPhase) createUser(progressChan chan<- ProgressUpdate) error {
174174
175175 // Create user with home directory
176176 userAddCmd := fmt.Sprintf("useradd -m -G %s -s %s %s", config.GroupWheel, config.ShellBash, p.config.Username)
177- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, userAddCmd); err != nil {
177+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, userAddCmd); err != nil {
178178 return fmt.Errorf("failed to create user: %w", err)
179179 }
180180
@@ -97,12 +97,12 @@ func (p *ConfigPhase) configureSystem(progressChan chan<- ProgressUpdate) error
97 // Set timezone97 // Set timezone
98 timezonePath := filepath.Join(config.PathUsrShareZoneinfo, p.config.Timezone)98 timezonePath := filepath.Join(config.PathUsrShareZoneinfo, p.config.Timezone)
99 tzCmd := fmt.Sprintf("ln -sf %s %s", timezonePath, config.PathEtcLocaltime)99 tzCmd := fmt.Sprintf("ln -sf %s %s", timezonePath, config.PathEtcLocaltime)
100- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, tzCmd); err != nil {100+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, tzCmd); err != nil {
101 return fmt.Errorf("failed to set timezone: %w", err)101 return fmt.Errorf("failed to set timezone: %w", err)
102 }102 }
103 103
104 // Set hardware clock104 // Set hardware clock
105- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "hwclock --systohc"); err != nil {105+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "hwclock --systohc"); err != nil {
106 return fmt.Errorf("failed to set hardware clock: %w", err)106 return fmt.Errorf("failed to set hardware clock: %w", err)
107 }107 }
108 108
@@ -114,7 +114,7 @@ func (p *ConfigPhase) configureSystem(progressChan chan<- ProgressUpdate) error
114 return fmt.Errorf("failed to write locale.gen: %w", err)114 return fmt.Errorf("failed to write locale.gen: %w", err)
115 }115 }
116 116
117- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, "locale-gen"); err != nil {117+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, "locale-gen"); err != nil {
118 return fmt.Errorf("failed to generate locale: %w", err)118 return fmt.Errorf("failed to generate locale: %w", err)
119 }119 }
120 120
@@ -159,7 +159,7 @@ func (p *ConfigPhase) configureNetwork(progressChan chan<- ProgressUpdate) error
159 p.SendOutput(progressChan, "Configuring network...")159 p.SendOutput(progressChan, "Configuring network...")
160 160
161 // Enable NetworkManager service161 // Enable NetworkManager service
162- if err := p.chrExec.ChrootSystemctl(p.logger.LogPath(),config.PathMnt, "enable", config.ServiceNetworkManager); err != nil {162+ if err := p.chrExec.ChrootSystemctl(p.logger.LogPath(), config.PathMnt, "enable", config.ServiceNetworkManager); err != nil {
163 return fmt.Errorf("failed to enable NetworkManager: %w", err)163 return fmt.Errorf("failed to enable NetworkManager: %w", err)
164 }164 }
165 165
@@ -174,7 +174,7 @@ func (p *ConfigPhase) createUser(progressChan chan<- ProgressUpdate) error {
174 174
175 // Create user with home directory175 // Create user with home directory
176 userAddCmd := fmt.Sprintf("useradd -m -G %s -s %s %s", config.GroupWheel, config.ShellBash, p.config.Username)176 userAddCmd := fmt.Sprintf("useradd -m -G %s -s %s %s", config.GroupWheel, config.ShellBash, p.config.Username)
177- if err := p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, userAddCmd); err != nil {177+ if err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, userAddCmd); err != nil {
178 return fmt.Errorf("failed to create user: %w", err)178 return fmt.Errorf("failed to create user: %w", err)
179 }179 }
180 180
M internal/phases/systemconfig_test.go +4 -4
@@ -129,10 +129,10 @@ func TestConfigPhasePreCheck(t *testing.T) {
129129 // TestConfigPhasePostCheck tests configuration validation
130130 func TestConfigPhasePostCheck(t *testing.T) {
131131 tests := []struct {
132- name string
133- setupMocks func(*mocks.MockFileSystem)
134- wantErr bool
135- errContains string
132+ name string
133+ setupMocks func(*mocks.MockFileSystem)
134+ wantErr bool
135+ errContains string
136136 }{
137137 {
138138 name: "All configuration files exist - postcheck passes",
@@ -129,10 +129,10 @@ func TestConfigPhasePreCheck(t *testing.T) {
129 // TestConfigPhasePostCheck tests configuration validation129 // TestConfigPhasePostCheck tests configuration validation
130 func TestConfigPhasePostCheck(t *testing.T) {130 func TestConfigPhasePostCheck(t *testing.T) {
131 tests := []struct {131 tests := []struct {
132- name string132+ name string
133- setupMocks func(*mocks.MockFileSystem)133+ setupMocks func(*mocks.MockFileSystem)
134- wantErr bool134+ wantErr bool
135- errContains string135+ errContains string
136 }{136 }{
137 {137 {
138 name: "All configuration files exist - postcheck passes",138 name: "All configuration files exist - postcheck passes",
M internal/postboot/setup.go +0 -2
@@ -113,7 +113,6 @@ func (s *Setup) Configure() (SetupResult, error) {
113113 }
114114 }
115115
116-
117116 // Download service template
118117 serviceURL := fmt.Sprintf("%s/%s", s.config.RawURL, config.PostBootServiceTemplate)
119118 resp, err = s.http.Get(serviceURL)
@@ -140,7 +139,6 @@ func (s *Setup) Configure() (SetupResult, error) {
140139 return result, fmt.Errorf("failed to write service file: %w", err)
141140 }
142141
143-
144142 if err := s.chrExec.ChrootSystemctl(s.logger.LogPath(), config.PathMnt, "enable", config.PostBootServiceName); err != nil {
145143 return result, fmt.Errorf("failed to enable service: %w", err)
146144 }
@@ -113,7 +113,6 @@ func (s *Setup) Configure() (SetupResult, error) {
113 }113 }
114 }114 }
115 115
116-
117 // Download service template116 // Download service template
118 serviceURL := fmt.Sprintf("%s/%s", s.config.RawURL, config.PostBootServiceTemplate)117 serviceURL := fmt.Sprintf("%s/%s", s.config.RawURL, config.PostBootServiceTemplate)
119 resp, err = s.http.Get(serviceURL)118 resp, err = s.http.Get(serviceURL)
@@ -140,7 +139,6 @@ func (s *Setup) Configure() (SetupResult, error) {
140 return result, fmt.Errorf("failed to write service file: %w", err)139 return result, fmt.Errorf("failed to write service file: %w", err)
141 }140 }
142 141
143-
144 if err := s.chrExec.ChrootSystemctl(s.logger.LogPath(), config.PathMnt, "enable", config.PostBootServiceName); err != nil {142 if err := s.chrExec.ChrootSystemctl(s.logger.LogPath(), config.PathMnt, "enable", config.PostBootServiceName); err != nil {
145 return result, fmt.Errorf("failed to enable service: %w", err)143 return result, fmt.Errorf("failed to enable service: %w", err)
146 }144 }
M internal/shell/configurator.go +0 -1
@@ -165,4 +165,3 @@ func (c *Configurator) setShellOwnership(userHome, username string) error {
165165 username, username, relativeHome, relativeHome)
166166 return c.chrExec.ChrootExec(c.logger.LogPath(), config.PathMnt, chownCmd)
167167 }
168-
@@ -165,4 +165,3 @@ func (c *Configurator) setShellOwnership(userHome, username string) error {
165 username, username, relativeHome, relativeHome)165 username, username, relativeHome, relativeHome)
166 return c.chrExec.ChrootExec(c.logger.LogPath(), config.PathMnt, chownCmd)166 return c.chrExec.ChrootExec(c.logger.LogPath(), config.PathMnt, chownCmd)
167 }167 }
168-
M internal/system/chroot.go +12 -12
@@ -199,18 +199,18 @@ func Genfstab(logPath, mountPoint, fstabPath string) error {
199199
200200 // DefaultChrootSession represents a persistent chroot session
201201 type DefaultChrootSession struct {
202- cmd *exec.Cmd
203- stdin *os.File
204- stdoutPipe *os.File
205- stderrPipe *os.File
206- logFile *os.File
207- logPath string
208- mountPoint string
209- ctx context.Context
210- cancel context.CancelFunc
211- outputChan chan string
212- errorChan chan error
213- closed bool
202+ cmd *exec.Cmd
203+ stdin *os.File
204+ stdoutPipe *os.File
205+ stderrPipe *os.File
206+ logFile *os.File
207+ logPath string
208+ mountPoint string
209+ ctx context.Context
210+ cancel context.CancelFunc
211+ outputChan chan string
212+ errorChan chan error
213+ closed bool
214214 }
215215
216216 // BeginSession starts a persistent chroot session
@@ -199,18 +199,18 @@ func Genfstab(logPath, mountPoint, fstabPath string) error {
199 199
200 // DefaultChrootSession represents a persistent chroot session200 // DefaultChrootSession represents a persistent chroot session
201 type DefaultChrootSession struct {201 type DefaultChrootSession struct {
202- cmd *exec.Cmd202+ cmd *exec.Cmd
203- stdin *os.File203+ stdin *os.File
204- stdoutPipe *os.File204+ stdoutPipe *os.File
205- stderrPipe *os.File205+ stderrPipe *os.File
206- logFile *os.File206+ logFile *os.File
207- logPath string207+ logPath string
208- mountPoint string208+ mountPoint string
209- ctx context.Context209+ ctx context.Context
210- cancel context.CancelFunc210+ cancel context.CancelFunc
211- outputChan chan string211+ outputChan chan string
212- errorChan chan error212+ errorChan chan error
213- closed bool213+ closed bool
214 }214 }
215 215
216 // BeginSession starts a persistent chroot session216 // BeginSession starts a persistent chroot session
M internal/system/cpu.go +5 -5
@@ -34,11 +34,11 @@ type AMDZenGen struct {
3434
3535 // CPUInfo holds detected CPU information
3636 type CPUInfo struct {
37- Vendor CPUVendor
38- ModelName string // Full CPU model name
39- Microcode string
40- AMDZenGen *AMDZenGen // AMD Zen generation (nil for non-AMD)
41- AMDPStateModes []AMDPStateMode
37+ Vendor CPUVendor
38+ ModelName string // Full CPU model name
39+ Microcode string
40+ AMDZenGen *AMDZenGen // AMD Zen generation (nil for non-AMD)
41+ AMDPStateModes []AMDPStateMode
4242 RecommendedPStateMode AMDPStateMode // Recommended mode for this CPU
4343 }
4444
@@ -34,11 +34,11 @@ type AMDZenGen struct {
34 34
35 // CPUInfo holds detected CPU information35 // CPUInfo holds detected CPU information
36 type CPUInfo struct {36 type CPUInfo struct {
37- Vendor CPUVendor37+ Vendor CPUVendor
38- ModelName string // Full CPU model name38+ ModelName string // Full CPU model name
39- Microcode string39+ Microcode string
40- AMDZenGen *AMDZenGen // AMD Zen generation (nil for non-AMD)40+ AMDZenGen *AMDZenGen // AMD Zen generation (nil for non-AMD)
41- AMDPStateModes []AMDPStateMode41+ AMDPStateModes []AMDPStateMode
42 RecommendedPStateMode AMDPStateMode // Recommended mode for this CPU42 RecommendedPStateMode AMDPStateMode // Recommended mode for this CPU
43 }43 }
44 44
M internal/system/mirrorlist_test.go +12 -12
@@ -95,13 +95,13 @@ Server = https://tabs.com/$repo/$arch `,
9595
9696 func TestBuildPackageURLs(t *testing.T) {
9797 tests := []struct {
98- name string
99- mirrors []MirrorlistEntry
100- packageName string
101- preferEnabled bool
102- wantCount int
103- wantURLContains []string
104- shouldStartWith string
98+ name string
99+ mirrors []MirrorlistEntry
100+ packageName string
101+ preferEnabled bool
102+ wantCount int
103+ wantURLContains []string
104+ shouldStartWith string
105105 }{
106106 {
107107 name: "Basic URL building with enabled mirrors preferred",
@@ -126,9 +126,9 @@ func TestBuildPackageURLs(t *testing.T) {
126126 {URL: "https://enabled1.com/$repo/$arch", Enabled: true},
127127 {URL: "https://enabled2.com/$repo/$arch", Enabled: true},
128128 },
129- packageName: "pkg.tar.zst",
130- preferEnabled: true,
131- wantCount: 3,
129+ packageName: "pkg.tar.zst",
130+ preferEnabled: true,
131+ wantCount: 3,
132132 shouldStartWith: "https://enabled1.com/chaotic-aur/x86_64/pkg.tar.zst",
133133 },
134134 {
@@ -142,8 +142,8 @@ func TestBuildPackageURLs(t *testing.T) {
142142 wantCount: 2,
143143 },
144144 {
145- name: "Empty mirrors list",
146- mirrors: []MirrorlistEntry{},
145+ name: "Empty mirrors list",
146+ mirrors: []MirrorlistEntry{},
147147 packageName: "test.pkg.tar.zst",
148148 preferEnabled: true,
149149 wantCount: 0,
@@ -95,13 +95,13 @@ Server = https://tabs.com/$repo/$arch `,
95 95
96 func TestBuildPackageURLs(t *testing.T) {96 func TestBuildPackageURLs(t *testing.T) {
97 tests := []struct {97 tests := []struct {
98- name string98+ name string
99- mirrors []MirrorlistEntry99+ mirrors []MirrorlistEntry
100- packageName string100+ packageName string
101- preferEnabled bool101+ preferEnabled bool
102- wantCount int102+ wantCount int
103- wantURLContains []string103+ wantURLContains []string
104- shouldStartWith string104+ shouldStartWith string
105 }{105 }{
106 {106 {
107 name: "Basic URL building with enabled mirrors preferred",107 name: "Basic URL building with enabled mirrors preferred",
@@ -126,9 +126,9 @@ func TestBuildPackageURLs(t *testing.T) {
126 {URL: "https://enabled1.com/$repo/$arch", Enabled: true},126 {URL: "https://enabled1.com/$repo/$arch", Enabled: true},
127 {URL: "https://enabled2.com/$repo/$arch", Enabled: true},127 {URL: "https://enabled2.com/$repo/$arch", Enabled: true},
128 },128 },
129- packageName: "pkg.tar.zst",129+ packageName: "pkg.tar.zst",
130- preferEnabled: true,130+ preferEnabled: true,
131- wantCount: 3,131+ wantCount: 3,
132 shouldStartWith: "https://enabled1.com/chaotic-aur/x86_64/pkg.tar.zst",132 shouldStartWith: "https://enabled1.com/chaotic-aur/x86_64/pkg.tar.zst",
133 },133 },
134 {134 {
@@ -142,8 +142,8 @@ func TestBuildPackageURLs(t *testing.T) {
142 wantCount: 2,142 wantCount: 2,
143 },143 },
144 {144 {
145- name: "Empty mirrors list",145+ name: "Empty mirrors list",
146- mirrors: []MirrorlistEntry{},146+ mirrors: []MirrorlistEntry{},
147 packageName: "test.pkg.tar.zst",147 packageName: "test.pkg.tar.zst",
148 preferEnabled: true,148 preferEnabled: true,
149 wantCount: 0,149 wantCount: 0,
M internal/ui/components/forms.go +1 -1
@@ -1,9 +1,9 @@
11 package components
22
33 import (
4+ "github.com/bnema/archup/internal/ui/styles"
45 "github.com/charmbracelet/huh"
56 "github.com/charmbracelet/lipgloss"
6- "github.com/bnema/archup/internal/ui/styles"
77 )
88
99 // FormBuilder provides reusable form components
@@ -1,9 +1,9 @@
1 package components1 package components
2 2
3 import (3 import (
4+ "github.com/bnema/archup/internal/ui/styles"
4 "github.com/charmbracelet/huh"5 "github.com/charmbracelet/huh"
5 "github.com/charmbracelet/lipgloss"6 "github.com/charmbracelet/lipgloss"
6- "github.com/bnema/archup/internal/ui/styles"
7 )7 )
8 8
9 // FormBuilder provides reusable form components9 // FormBuilder provides reusable form components
M internal/ui/components/output.go +1 -1
@@ -3,9 +3,9 @@ package components
33 import (
44 "strings"
55
6+ "github.com/bnema/archup/internal/ui/styles"
67 "github.com/charmbracelet/bubbles/viewport"
78 tea "github.com/charmbracelet/bubbletea"
8- "github.com/bnema/archup/internal/ui/styles"
99 )
1010
1111 // OutputViewer displays scrolling command output (last N lines)
@@ -3,9 +3,9 @@ package components
3 import (3 import (
4 "strings"4 "strings"
5 5
6+ "github.com/bnema/archup/internal/ui/styles"
6 "github.com/charmbracelet/bubbles/viewport"7 "github.com/charmbracelet/bubbles/viewport"
7 tea "github.com/charmbracelet/bubbletea"8 tea "github.com/charmbracelet/bubbletea"
8- "github.com/bnema/archup/internal/ui/styles"
9 )9 )
10 10
11 // OutputViewer displays scrolling command output (last N lines)11 // OutputViewer displays scrolling command output (last N lines)
M internal/ui/model.go +8 -8
@@ -342,15 +342,15 @@ func (m *Model) handleFormComplete() tea.Cmd {
342342 }
343343
344344 // Getter methods for views package
345-func (m *Model) Width() int { return m.width }
346-func (m *Model) Version() string { return m.version }
347-func (m *Model) Config() *config.Config { return m.config }
348-func (m *Model) CurrentForm() *huh.Form { return m.currentForm }
349-func (m *Model) Spinner() spinner.Model { return m.spinner }
345+func (m *Model) Width() int { return m.width }
346+func (m *Model) Version() string { return m.version }
347+func (m *Model) Config() *config.Config { return m.config }
348+func (m *Model) CurrentForm() *huh.Form { return m.currentForm }
349+func (m *Model) Spinner() spinner.Model { return m.spinner }
350350 func (m *Model) Output() *components.OutputViewer { return m.output }
351-func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }
352-func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }
353-func (m *Model) NetworkErr() error { return m.networkErr }
351+func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }
352+func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }
353+func (m *Model) NetworkErr() error { return m.networkErr }
354354
355355 // executeNextPhase executes the next pending phase
356356 func (m *Model) executeNextPhase() tea.Cmd {
@@ -342,15 +342,15 @@ func (m *Model) handleFormComplete() tea.Cmd {
342 }342 }
343 343
344 // Getter methods for views package344 // Getter methods for views package
345-func (m *Model) Width() int { return m.width }345+func (m *Model) Width() int { return m.width }
346-func (m *Model) Version() string { return m.version }346+func (m *Model) Version() string { return m.version }
347-func (m *Model) Config() *config.Config { return m.config }347+func (m *Model) Config() *config.Config { return m.config }
348-func (m *Model) CurrentForm() *huh.Form { return m.currentForm }348+func (m *Model) CurrentForm() *huh.Form { return m.currentForm }
349-func (m *Model) Spinner() spinner.Model { return m.spinner }349+func (m *Model) Spinner() spinner.Model { return m.spinner }
350 func (m *Model) Output() *components.OutputViewer { return m.output }350 func (m *Model) Output() *components.OutputViewer { return m.output }
351-func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }351+func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }
352-func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }352+func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }
353-func (m *Model) NetworkErr() error { return m.networkErr }353+func (m *Model) NetworkErr() error { return m.networkErr }
354 354
355 // executeNextPhase executes the next pending phase355 // executeNextPhase executes the next pending phase
356 func (m *Model) executeNextPhase() tea.Cmd {356 func (m *Model) executeNextPhase() tea.Cmd {
M internal/ui/sections.go +12 -12
@@ -27,27 +27,27 @@ const (
2727 WarnDiskErase = "WARNING: This will delete all data on the selected disk!"
2828
2929 // Encryption
30- SectionDiskEncryption = "Disk Encryption"
31- DescEncryption = "LUKS encryption protects your data with Argon2id (2000ms iteration)"
32- DescEncryptionPassword = "Leave empty to use the same password as your user account"
33- DescEncryptionSamePass = "Use the same password for disk encryption as your user account?"
30+ SectionDiskEncryption = "Disk Encryption"
31+ DescEncryption = "LUKS encryption protects your data with Argon2id (2000ms iteration)"
32+ DescEncryptionPassword = "Leave empty to use the same password as your user account"
33+ DescEncryptionSamePass = "Use the same password for disk encryption as your user account?"
3434
3535 // Kernel
36- SectionKernel = "Kernel Selection"
37- DescKernelLinux = "Stable mainline kernel (recommended)"
38- DescKernelLTS = "Long-term support (maximum stability)"
39- DescKernelZen = "Performance-optimized for general use"
36+ SectionKernel = "Kernel Selection"
37+ DescKernelLinux = "Stable mainline kernel (recommended)"
38+ DescKernelLTS = "Long-term support (maximum stability)"
39+ DescKernelZen = "Performance-optimized for general use"
4040 DescKernelHardened = "Security-focused kernel"
41- DescKernelCachyOS = "Gaming-optimized (requires CachyOS repo)"
41+ DescKernelCachyOS = "Gaming-optimized (requires CachyOS repo)"
4242
4343 // AMD P-State
4444 SectionAMDTuning = "AMD CPU Tuning"
4545 DescAMDPState = "Select AMD P-State driver mode for CPU frequency scaling"
4646
4747 // Repository options
48- DescMultilib = "Required for 32-bit applications and Wine"
49- DescChaoticAUR = "Community repository with pre-built AUR packages"
50- DescAURHelper = "Tool for installing packages from Arch User Repository"
48+ DescMultilib = "Required for 32-bit applications and Wine"
49+ DescChaoticAUR = "Community repository with pre-built AUR packages"
50+ DescAURHelper = "Tool for installing packages from Arch User Repository"
5151 DescAURHelperParu = "Rust-based AUR helper"
5252 DescAURHelperYay = "Go-based AUR helper"
5353 )
@@ -27,27 +27,27 @@ const (
27 WarnDiskErase = "WARNING: This will delete all data on the selected disk!"27 WarnDiskErase = "WARNING: This will delete all data on the selected disk!"
28 28
29 // Encryption29 // Encryption
30- SectionDiskEncryption = "Disk Encryption"30+ SectionDiskEncryption = "Disk Encryption"
31- DescEncryption = "LUKS encryption protects your data with Argon2id (2000ms iteration)"31+ DescEncryption = "LUKS encryption protects your data with Argon2id (2000ms iteration)"
32- DescEncryptionPassword = "Leave empty to use the same password as your user account"32+ DescEncryptionPassword = "Leave empty to use the same password as your user account"
33- DescEncryptionSamePass = "Use the same password for disk encryption as your user account?"33+ DescEncryptionSamePass = "Use the same password for disk encryption as your user account?"
34 34
35 // Kernel35 // Kernel
36- SectionKernel = "Kernel Selection"36+ SectionKernel = "Kernel Selection"
37- DescKernelLinux = "Stable mainline kernel (recommended)"37+ DescKernelLinux = "Stable mainline kernel (recommended)"
38- DescKernelLTS = "Long-term support (maximum stability)"38+ DescKernelLTS = "Long-term support (maximum stability)"
39- DescKernelZen = "Performance-optimized for general use"39+ DescKernelZen = "Performance-optimized for general use"
40 DescKernelHardened = "Security-focused kernel"40 DescKernelHardened = "Security-focused kernel"
41- DescKernelCachyOS = "Gaming-optimized (requires CachyOS repo)"41+ DescKernelCachyOS = "Gaming-optimized (requires CachyOS repo)"
42 42
43 // AMD P-State43 // AMD P-State
44 SectionAMDTuning = "AMD CPU Tuning"44 SectionAMDTuning = "AMD CPU Tuning"
45 DescAMDPState = "Select AMD P-State driver mode for CPU frequency scaling"45 DescAMDPState = "Select AMD P-State driver mode for CPU frequency scaling"
46 46
47 // Repository options47 // Repository options
48- DescMultilib = "Required for 32-bit applications and Wine"48+ DescMultilib = "Required for 32-bit applications and Wine"
49- DescChaoticAUR = "Community repository with pre-built AUR packages"49+ DescChaoticAUR = "Community repository with pre-built AUR packages"
50- DescAURHelper = "Tool for installing packages from Arch User Repository"50+ DescAURHelper = "Tool for installing packages from Arch User Repository"
51 DescAURHelperParu = "Rust-based AUR helper"51 DescAURHelperParu = "Rust-based AUR helper"
52 DescAURHelperYay = "Go-based AUR helper"52 DescAURHelperYay = "Go-based AUR helper"
53 )53 )
M internal/ui/styles/containers.go +5 -5
@@ -18,12 +18,12 @@ const (
1818 var (
1919 // CenteredContainerStyle - Used for welcome, complete, error screens
2020 CenteredContainerStyle = lipgloss.NewStyle().
21- MaxWidth(MaxContentWidth).
22- Padding(0, 2).
23- AlignHorizontal(lipgloss.Center)
21+ MaxWidth(MaxContentWidth).
22+ Padding(0, 2).
23+ AlignHorizontal(lipgloss.Center)
2424
2525 // FormContainerStyle - Used for all forms (content left-aligned)
2626 FormContainerStyle = lipgloss.NewStyle().
27- Padding(0, 2).
28- AlignHorizontal(lipgloss.Left)
27+ Padding(0, 2).
28+ AlignHorizontal(lipgloss.Left)
2929 )
@@ -18,12 +18,12 @@ const (
18 var (18 var (
19 // CenteredContainerStyle - Used for welcome, complete, error screens19 // CenteredContainerStyle - Used for welcome, complete, error screens
20 CenteredContainerStyle = lipgloss.NewStyle().20 CenteredContainerStyle = lipgloss.NewStyle().
21- MaxWidth(MaxContentWidth).21+ MaxWidth(MaxContentWidth).
22- Padding(0, 2).22+ Padding(0, 2).
23- AlignHorizontal(lipgloss.Center)23+ AlignHorizontal(lipgloss.Center)
24 24
25 // FormContainerStyle - Used for all forms (content left-aligned)25 // FormContainerStyle - Used for all forms (content left-aligned)
26 FormContainerStyle = lipgloss.NewStyle().26 FormContainerStyle = lipgloss.NewStyle().
27- Padding(0, 2).27+ Padding(0, 2).
28- AlignHorizontal(lipgloss.Left)28+ AlignHorizontal(lipgloss.Left)
29 )29 )
M internal/ui/styles/theme.go +28 -28
@@ -14,8 +14,8 @@ var (
1414 // Background Colors
1515 ColorDeepNavy = lipgloss.CompleteColor{
1616 TrueColor: "#050a14",
17- ANSI256: "16", // Pure black
18- ANSI: "0", // Black
17+ ANSI256: "16", // Pure black
18+ ANSI: "0", // Black
1919 }
2020
2121 ColorDarkBlue = lipgloss.CompleteColor{
@@ -38,8 +38,8 @@ var (
3838
3939 ColorOceanBlue = lipgloss.CompleteColor{
4040 TrueColor: "#2d4a6b",
41- ANSI256: "24", // Deep blue
42- ANSI: "4", // Blue
41+ ANSI256: "24", // Deep blue
42+ ANSI: "4", // Blue
4343 }
4444
4545 // Text Colors
@@ -64,14 +64,14 @@ var (
6464 // Accent Colors
6565 ColorBrightCyan = lipgloss.CompleteColor{
6666 TrueColor: "#00d4ff",
67- ANSI256: "45", // Bright cyan
68- ANSI: "14", // Bright cyan
67+ ANSI256: "45", // Bright cyan
68+ ANSI: "14", // Bright cyan
6969 }
7070
7171 ColorPureBlue = lipgloss.CompleteColor{
7272 TrueColor: "#5588cc",
73- ANSI256: "69", // Steel blue
74- ANSI: "12", // Bright blue
73+ ANSI256: "69", // Steel blue
74+ ANSI: "12", // Bright blue
7575 }
7676
7777 ColorLightSkyBlue = lipgloss.CompleteColor{
@@ -82,8 +82,8 @@ var (
8282
8383 ColorSkyBlue = lipgloss.CompleteColor{
8484 TrueColor: "#4a7ba7",
85- ANSI256: "67", // Steel blue
86- ANSI: "4", // Blue
85+ ANSI256: "67", // Steel blue
86+ ANSI: "4", // Blue
8787 }
8888
8989 // Status Colors
@@ -273,52 +273,52 @@ func HuhTheme() *huh.Theme {
273273 // 0=black, 4=blue, 6=cyan, 7=white, 8=grey, 10=bright green, 12=bright blue, 14=bright cyan, 15=bright white
274274
275275 // Form and Group styles
276- theme.Group.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
277- theme.Group.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
276+ theme.Group.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
277+ theme.Group.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
278278
279279 // Focused field styles
280- theme.Focused.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
281- theme.Focused.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
280+ theme.Focused.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
281+ theme.Focused.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
282282 theme.Focused.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
283- theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
283+ theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
284284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
285- theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
285+ theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
286286 theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("[OK] ") // Bright green
287- theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
288- theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey
287+ theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
288+ theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey
289289
290290 // Button styles with explicit background colors for TTY compatibility
291291 // Active/focused button (currently selected - e.g., "Yes" when on Yes)
292292 theme.Focused.FocusedButton = lipgloss.NewStyle().
293- Foreground(lipgloss.Color("15")). // Bright white text
294- Background(lipgloss.Color("4")). // Blue background
293+ Foreground(lipgloss.Color("15")). // Bright white text
294+ Background(lipgloss.Color("4")). // Blue background
295295 Padding(0, 2).
296296 Bold(true)
297297
298298 // Inactive/blurred button (not selected - e.g., "No" when on Yes)
299299 theme.Focused.BlurredButton = lipgloss.NewStyle().
300- Foreground(lipgloss.Color("7")). // White text
301- Background(lipgloss.Color("0")). // Black background
300+ Foreground(lipgloss.Color("7")). // White text
301+ Background(lipgloss.Color("0")). // Black background
302302 Padding(0, 2)
303303
304304 // Blurred field styles (when entire field loses focus)
305- theme.Blurred.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
306- theme.Blurred.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
305+ theme.Blurred.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
306+ theme.Blurred.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
307307 theme.Blurred.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("> ")
308- theme.Blurred.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
308+ theme.Blurred.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
309309
310310 // Override buttons in Blurred state too (inherited from Focused in Base16)
311311 theme.Blurred.FocusedButton = theme.Focused.FocusedButton
312312 theme.Blurred.BlurredButton = theme.Focused.BlurredButton
313313
314314 // Text input styles
315- theme.Focused.TextInput.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
316- theme.Focused.TextInput.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
315+ theme.Focused.TextInput.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
316+ theme.Focused.TextInput.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
317317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
318318
319319 // Error styles
320320 theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("[KO] ") // Bright red
321- theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red
321+ theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red
322322
323323 return theme
324324 }
@@ -14,8 +14,8 @@ var (
14 // Background Colors14 // Background Colors
15 ColorDeepNavy = lipgloss.CompleteColor{15 ColorDeepNavy = lipgloss.CompleteColor{
16 TrueColor: "#050a14",16 TrueColor: "#050a14",
17- ANSI256: "16", // Pure black17+ ANSI256: "16", // Pure black
18- ANSI: "0", // Black18+ ANSI: "0", // Black
19 }19 }
20 20
21 ColorDarkBlue = lipgloss.CompleteColor{21 ColorDarkBlue = lipgloss.CompleteColor{
@@ -38,8 +38,8 @@ var (
38 38
39 ColorOceanBlue = lipgloss.CompleteColor{39 ColorOceanBlue = lipgloss.CompleteColor{
40 TrueColor: "#2d4a6b",40 TrueColor: "#2d4a6b",
41- ANSI256: "24", // Deep blue41+ ANSI256: "24", // Deep blue
42- ANSI: "4", // Blue42+ ANSI: "4", // Blue
43 }43 }
44 44
45 // Text Colors45 // Text Colors
@@ -64,14 +64,14 @@ var (
64 // Accent Colors64 // Accent Colors
65 ColorBrightCyan = lipgloss.CompleteColor{65 ColorBrightCyan = lipgloss.CompleteColor{
66 TrueColor: "#00d4ff",66 TrueColor: "#00d4ff",
67- ANSI256: "45", // Bright cyan67+ ANSI256: "45", // Bright cyan
68- ANSI: "14", // Bright cyan68+ ANSI: "14", // Bright cyan
69 }69 }
70 70
71 ColorPureBlue = lipgloss.CompleteColor{71 ColorPureBlue = lipgloss.CompleteColor{
72 TrueColor: "#5588cc",72 TrueColor: "#5588cc",
73- ANSI256: "69", // Steel blue73+ ANSI256: "69", // Steel blue
74- ANSI: "12", // Bright blue74+ ANSI: "12", // Bright blue
75 }75 }
76 76
77 ColorLightSkyBlue = lipgloss.CompleteColor{77 ColorLightSkyBlue = lipgloss.CompleteColor{
@@ -82,8 +82,8 @@ var (
82 82
83 ColorSkyBlue = lipgloss.CompleteColor{83 ColorSkyBlue = lipgloss.CompleteColor{
84 TrueColor: "#4a7ba7",84 TrueColor: "#4a7ba7",
85- ANSI256: "67", // Steel blue85+ ANSI256: "67", // Steel blue
86- ANSI: "4", // Blue86+ ANSI: "4", // Blue
87 }87 }
88 88
89 // Status Colors89 // Status Colors
@@ -273,52 +273,52 @@ func HuhTheme() *huh.Theme {
273 // 0=black, 4=blue, 6=cyan, 7=white, 8=grey, 10=bright green, 12=bright blue, 14=bright cyan, 15=bright white273 // 0=black, 4=blue, 6=cyan, 7=white, 8=grey, 10=bright green, 12=bright blue, 14=bright cyan, 15=bright white
274 274
275 // Form and Group styles275 // Form and Group styles
276- theme.Group.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan276+ theme.Group.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
277- theme.Group.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue277+ theme.Group.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
278 278
279 // Focused field styles279 // Focused field styles
280- theme.Focused.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan280+ theme.Focused.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
281- theme.Focused.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue281+ theme.Focused.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) // Bright blue
282 theme.Focused.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")282 theme.Focused.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
283- theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White283+ theme.Focused.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")284 theme.Focused.MultiSelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).SetString("> ")
285- theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan285+ theme.Focused.SelectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
286 theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("[OK] ") // Bright green286 theme.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("10")).SetString("[OK] ") // Bright green
287- theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White287+ theme.Focused.UnselectedOption = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White
288- theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey288+ theme.Focused.UnselectedPrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("○ ") // Grey
289 289
290 // Button styles with explicit background colors for TTY compatibility290 // Button styles with explicit background colors for TTY compatibility
291 // Active/focused button (currently selected - e.g., "Yes" when on Yes)291 // Active/focused button (currently selected - e.g., "Yes" when on Yes)
292 theme.Focused.FocusedButton = lipgloss.NewStyle().292 theme.Focused.FocusedButton = lipgloss.NewStyle().
293- Foreground(lipgloss.Color("15")). // Bright white text293+ Foreground(lipgloss.Color("15")). // Bright white text
294- Background(lipgloss.Color("4")). // Blue background294+ Background(lipgloss.Color("4")). // Blue background
295 Padding(0, 2).295 Padding(0, 2).
296 Bold(true)296 Bold(true)
297 297
298 // Inactive/blurred button (not selected - e.g., "No" when on Yes)298 // Inactive/blurred button (not selected - e.g., "No" when on Yes)
299 theme.Focused.BlurredButton = lipgloss.NewStyle().299 theme.Focused.BlurredButton = lipgloss.NewStyle().
300- Foreground(lipgloss.Color("7")). // White text300+ Foreground(lipgloss.Color("7")). // White text
301- Background(lipgloss.Color("0")). // Black background301+ Background(lipgloss.Color("0")). // Black background
302 Padding(0, 2)302 Padding(0, 2)
303 303
304 // Blurred field styles (when entire field loses focus)304 // Blurred field styles (when entire field loses focus)
305- theme.Blurred.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey305+ theme.Blurred.Title = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
306- theme.Blurred.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey306+ theme.Blurred.Description = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
307 theme.Blurred.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("> ")307 theme.Blurred.SelectSelector = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).SetString("> ")
308- theme.Blurred.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey308+ theme.Blurred.Option = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
309 309
310 // Override buttons in Blurred state too (inherited from Focused in Base16)310 // Override buttons in Blurred state too (inherited from Focused in Base16)
311 theme.Blurred.FocusedButton = theme.Focused.FocusedButton311 theme.Blurred.FocusedButton = theme.Focused.FocusedButton
312 theme.Blurred.BlurredButton = theme.Focused.BlurredButton312 theme.Blurred.BlurredButton = theme.Focused.BlurredButton
313 313
314 // Text input styles314 // Text input styles
315- theme.Focused.TextInput.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan315+ theme.Focused.TextInput.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // Bright cyan
316- theme.Focused.TextInput.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey316+ theme.Focused.TextInput.Placeholder = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // Grey
317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan317 theme.Focused.TextInput.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true) // Bright cyan
318 318
319 // Error styles319 // Error styles
320 theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("[KO] ") // Bright red320 theme.Focused.ErrorIndicator = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).SetString("[KO] ") // Bright red
321- theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red321+ theme.Focused.ErrorMessage = lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Bold(true) // Bright red
322 322
323 return theme323 return theme
324 }324 }
M internal/verify/shell.go +5 -5
@@ -11,11 +11,11 @@ import (
1111
1212 // ShellConfig holds verification results for shell configuration
1313 type ShellConfig struct {
14- BashrcExists bool
15- ShellFilesOK bool
16- BashrcSyntaxOK bool
17- Warnings []string
18- Errors []string
14+ BashrcExists bool
15+ ShellFilesOK bool
16+ BashrcSyntaxOK bool
17+ Warnings []string
18+ Errors []string
1919 }
2020
2121 // ValidateShellConfigs performs comprehensive shell configuration verification
@@ -11,11 +11,11 @@ import (
11 11
12 // ShellConfig holds verification results for shell configuration12 // ShellConfig holds verification results for shell configuration
13 type ShellConfig struct {13 type ShellConfig struct {
14- BashrcExists bool14+ BashrcExists bool
15- ShellFilesOK bool15+ ShellFilesOK bool
16- BashrcSyntaxOK bool16+ BashrcSyntaxOK bool
17- Warnings []string17+ Warnings []string
18- Errors []string18+ Errors []string
19 }19 }
20 20
21 // ValidateShellConfigs performs comprehensive shell configuration verification21 // ValidateShellConfigs performs comprehensive shell configuration verification

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