added cosmic packages to installer. Still no auto reboot
Some checks failed
Build / build (push) Failing after 4m53s

This commit is contained in:
tumillanino
2025-10-31 23:12:11 +11:00
parent ee79d720ec
commit a7bd4d9457
3 changed files with 169 additions and 38 deletions

71
TESTING.md Normal file
View File

@@ -0,0 +1,71 @@
# Miasma OS Installer - Testing Guide
## Testing in a Minimal Arch VM
### Setup Test Environment
1. **Create Arch VM with minimal install:**
- Boot Arch ISO
- Choose "Install Arch Linux"
- When prompted for profile, select "minimal" (no desktop)
- Complete basic installation
- Reboot into minimal Arch system
2. **Prepare for testing:**
```bash
# Login as root
# Ensure network is working
ping -c 3 archlinux.org
# Install git and go (for building)
pacman -Sy git go base-devel
# Clone the installer
git clone https://git.miasma-os.com/miasma/miasma-installer.git
cd miasma-installer
# Build the installer
make build
```
3. **Run the installer:**
```bash
# Must be run as root
sudo ./build/miasma-installer
```
### What Should Happen
1. **During Installation:**
- Installer detects available disks
- Partitions selected disk (GPT with EFI + root)
- Formats with btrfs (with subvolumes)
- Optional LUKS2 encryption
- Installs base system + linux-hardened
- Installs Cosmic Desktop packages
- Configures bootloader (systemd-boot)
- Sets up user account with sudo
2. **After Installation:**
- Installer exits cleanly
- Unmount filesystems: `umount -R /mnt`
- Reboot: `reboot`
- System boots into Cosmic Desktop login
- Login with created user credentials
### For archiso Integration
The installer will be included as a custom package in the archiso build:
- ISO boots directly to root shell
- Installer auto-starts or user runs `miasma-installer`
- After installation completes, user reboots
- System boots into installed Miasma OS with Cosmic Desktop
### Troubleshooting
If installation fails:
- Check `/mnt` is empty before starting
- Ensure UEFI mode: `ls /sys/firmware/efi`
- Check disk permissions: `lsblk`
- View detailed errors in the TUI
- Manually unmount if needed: `umount -R /mnt`

29
main.go
View File

@@ -9,17 +9,34 @@ import (
) )
func main() { func main() {
p := tea.NewProgram(tui.NewModel(), tea.WithAltScreen()) if os.Geteuid() != 0 {
fmt.Println("Error: This installer must be run as root")
if _, err := p.Run(); err != nil { fmt.Println("Please run: sudo miasma-installer")
fmt.Printf("An error has occured during installation: %v\n", err) os.Exit(1)
}
if _, err := os.Stat("/sys/firmware/efi"); os.IsNotExist(err) {
fmt.Println("Error: UEFI boot mode not detected")
fmt.Println("Miasma OS requires UEFI boot mode")
os.Exit(1)
}
p := tea.NewProgram(tui.NewModel(), tea.WithAltScreen())
finalModel, err := p.Run()
if err != nil {
fmt.Printf("\nAn error occurred during installation: %v\n", err)
os.Exit(1) os.Exit(1)
} }
finalModel, _ := p.Run()
if root, ok := finalModel.(tui.RootModel); ok { if root, ok := finalModel.(tui.RootModel); ok {
if root.State == tui.StateFinished { if root.State == tui.StateFinished {
fmt.Println("\nMiasma OS Installation Complete! Please reboot.") fmt.Println("\nMiasma OS Installation Complete!")
fmt.Println("\nThe system will reboot in 5 seconds...")
fmt.Println("Press Ctrl+C to cancel reboot")
fmt.Print("\nUnmounting filesystems...")
os.Exit(0)
} }
} }
} }

View File

@@ -266,7 +266,7 @@ func (m InstallModel) configureSystem() error {
genfstab := exec.Command("genfstab", "-U", "/mnt") genfstab := exec.Command("genfstab", "-U", "/mnt")
fstab, err := genfstab.Output() fstab, err := genfstab.Output()
if err != nil { if err != nil {
return err return fmt.Errorf("genfstab failed: %w", err)
} }
os.WriteFile("/mnt/etc/fstab", fstab, 0644) os.WriteFile("/mnt/etc/fstab", fstab, 0644)
@@ -277,7 +277,9 @@ func (m InstallModel) configureSystem() error {
os.WriteFile("/mnt/etc/hosts", []byte(hosts), 0644) os.WriteFile("/mnt/etc/hosts", []byte(hosts), 0644)
os.WriteFile("/mnt/etc/locale.gen", []byte("en_US.UTF-8 UTF-8\n"), 0644) os.WriteFile("/mnt/etc/locale.gen", []byte("en_US.UTF-8 UTF-8\n"), 0644)
chroot([]string{"locale-gen"}) if _, err := chroot([]string{"locale-gen"}); err != nil {
return fmt.Errorf("locale-gen failed: %w", err)
}
os.WriteFile("/mnt/etc/locale.conf", []byte("LANG=en_US.UTF-8\n"), 0644) os.WriteFile("/mnt/etc/locale.conf", []byte("LANG=en_US.UTF-8\n"), 0644)
@@ -285,24 +287,38 @@ func (m InstallModel) configureSystem() error {
chroot([]string{"hwclock", "--systohc"}) chroot([]string{"hwclock", "--systohc"})
useraddCmd := fmt.Sprintf("useradd -m -G wheel -s /bin/bash %s", m.config.Username) useraddCmd := fmt.Sprintf("useradd -m -G wheel -s /bin/bash %s", m.config.Username)
chroot([]string{"sh", "-c", useraddCmd}) if _, err := chroot([]string{"sh", "-c", useraddCmd}); err != nil {
return fmt.Errorf("useradd failed: %w", err)
}
passwdCmd := fmt.Sprintf("echo '%s:%s' | chpasswd", m.config.Username, m.config.UserPassword) passwdCmd := fmt.Sprintf("echo '%s:%s' | chpasswd", m.config.Username, m.config.UserPassword)
chroot([]string{"sh", "-c", passwdCmd}) if _, err := chroot([]string{"sh", "-c", passwdCmd}); err != nil {
return fmt.Errorf("user password set failed: %w", err)
}
rootPasswdCmd := fmt.Sprintf("echo 'root:%s' | chpasswd", m.config.RootPassword) rootPasswd := m.config.RootPassword
chroot([]string{"sh", "-c", rootPasswdCmd}) if rootPasswd == "" {
rootPasswd = m.config.UserPassword
}
rootPasswdCmd := fmt.Sprintf("echo 'root:%s' | chpasswd", rootPasswd)
if _, err := chroot([]string{"sh", "-c", rootPasswdCmd}); err != nil {
return fmt.Errorf("root password set failed: %w", err)
}
sudoers := "%wheel ALL=(ALL:ALL) ALL\n" sudoers := "%wheel ALL=(ALL:ALL) ALL\n"
os.WriteFile("/mnt/etc/sudoers.d/wheel", []byte(sudoers), 0440) os.WriteFile("/mnt/etc/sudoers.d/wheel", []byte(sudoers), 0440)
chroot([]string{"systemctl", "enable", "NetworkManager"}) if _, err := chroot([]string{"systemctl", "enable", "NetworkManager"}); err != nil {
return fmt.Errorf("failed to enable NetworkManager: %w", err)
}
return nil return nil
} }
func (m InstallModel) installBootloader() error { func (m InstallModel) installBootloader() error {
chroot([]string{"bootctl", "install"}) if _, err := chroot([]string{"bootctl", "install"}); err != nil {
return fmt.Errorf("bootctl install failed: %w", err)
}
loaderConf := `default arch.conf loaderConf := `default arch.conf
timeout 3 timeout 3
@@ -317,25 +333,18 @@ editor no
rootPart = disk + "p2" rootPart = disk + "p2"
} }
rootUUID := "" var options string
if m.config.EnableLUKS {
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output()
rootUUID = strings.TrimSpace(string(output))
} else {
rootPart = "/dev/mapper/cryptroot"
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output()
rootUUID = strings.TrimSpace(string(output))
}
options := fmt.Sprintf("root=UUID=%s rootflags=subvol=@ rw", rootUUID)
if m.config.EnableLUKS { if m.config.EnableLUKS {
cryptUUID := "" cryptUUID := ""
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", disk+"2") blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output() output, _ := blkid.Output()
cryptUUID = strings.TrimSpace(string(output)) cryptUUID = strings.TrimSpace(string(output))
options = fmt.Sprintf("cryptdevice=UUID=%s:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw", cryptUUID) options = fmt.Sprintf("cryptdevice=UUID=%s:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw quiet splash", cryptUUID)
} else {
blkid := exec.Command("blkid", "-s", "UUID", "-o", "value", rootPart)
output, _ := blkid.Output()
rootUUID := strings.TrimSpace(string(output))
options = fmt.Sprintf("root=UUID=%s rootflags=subvol=@ rw quiet splash", rootUUID)
} }
entryConf := fmt.Sprintf(`title Miasma OS entryConf := fmt.Sprintf(`title Miasma OS
@@ -346,21 +355,55 @@ options %s
os.WriteFile("/mnt/boot/loader/entries/arch.conf", []byte(entryConf), 0644) os.WriteFile("/mnt/boot/loader/entries/arch.conf", []byte(entryConf), 0644)
if m.config.EnableLUKS { if m.config.EnableLUKS {
mkinitcpio, _ := os.ReadFile("/mnt/etc/mkinitcpio.conf") mkinitcpioConf, err := os.ReadFile("/mnt/etc/mkinitcpio.conf")
newConf := strings.Replace(string(mkinitcpio), if err != nil {
return fmt.Errorf("failed to read mkinitcpio.conf: %w", err)
}
newConf := string(mkinitcpioConf)
newConf = strings.Replace(newConf,
"HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block filesystems fsck)",
"HOOKS=(base udev autodetect keyboard keymap consolefont modconf kms block encrypt filesystems fsck)",
1)
newConf = strings.Replace(newConf,
"HOOKS=(base udev autodetect modconf block filesystems keyboard fsck)", "HOOKS=(base udev autodetect modconf block filesystems keyboard fsck)",
"HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt filesystems fsck)", "HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt filesystems fsck)",
1) 1)
os.WriteFile("/mnt/etc/mkinitcpio.conf", []byte(newConf), 0644)
chroot([]string{"mkinitcpio", "-P"}) if err := os.WriteFile("/mnt/etc/mkinitcpio.conf", []byte(newConf), 0644); err != nil {
return fmt.Errorf("failed to write mkinitcpio.conf: %w", err)
}
if _, err := chroot([]string{"mkinitcpio", "-P"}); err != nil {
return fmt.Errorf("mkinitcpio failed: %w", err)
}
} }
return nil return nil
} }
func (m InstallModel) installDesktop() error { func (m InstallModel) installDesktop() error {
chroot([]string{"pacman", "-Sy", "--noconfirm", "cosmic-session", "cosmic-greeter"}) cosmicPackages := []string{
chroot([]string{"systemctl", "enable", "cosmic-greeter"}) "cosmic-session",
"cosmic-greeter",
"cosmic-files",
"cosmic-edit",
"cosmic-term",
"cosmic-store",
"cosmic-settings",
"xorg-xwayland",
}
for _, pkg := range cosmicPackages {
if _, err := chroot([]string{"pacman", "-Sy", "--noconfirm", pkg}); err != nil {
return fmt.Errorf("failed to install %s: %w", pkg, err)
}
}
if _, err := chroot([]string{"systemctl", "enable", "cosmic-greeter"}); err != nil {
return fmt.Errorf("failed to enable cosmic-greeter: %w", err)
}
return nil return nil
} }
@@ -414,7 +457,7 @@ func (m InstallModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.status = "Installation complete!" m.status = "Installation complete!"
} }
m.Finished = true m.Finished = true
return m, nil return m, tea.Quit
} }
return m, nil return m, nil
@@ -445,10 +488,10 @@ func (m InstallModel) View() string {
} }
if m.Finished && m.err == nil { if m.Finished && m.err == nil {
success := "✓ Installation successful!\n\nYou can now reboot your system." success := "✓ Installation successful!\n\nPress Ctrl+C to exit and reboot."
content.WriteString(styles.BoxStyle.Render(success)) content.WriteString(styles.BoxStyle.Render(success))
content.WriteString("\n\n") content.WriteString("\n\n")
content.WriteString(styles.RenderHelp("Ctrl+C", "Exit")) content.WriteString(styles.RenderHelp("Ctrl+C", "Exit and reboot"))
} }
return styles.AppStyle.Render(content.String()) return styles.AppStyle.Render(content.String())