added installer shell script and additional steps
This commit is contained in:
71
tui/steps/confirm.go
Normal file
71
tui/steps/confirm.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type ConfirmModel struct {
|
||||
Disk string
|
||||
EnableLUKS bool
|
||||
Hostname string
|
||||
Username string
|
||||
Confirmed bool
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func NewConfirmModel(disk string, enableLUKS bool, hostname string, username string) ConfirmModel {
|
||||
return ConfirmModel{
|
||||
Disk: disk,
|
||||
EnableLUKS: enableLUKS,
|
||||
Hostname: hostname,
|
||||
Username: username,
|
||||
}
|
||||
}
|
||||
|
||||
func (m ConfirmModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ConfirmModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "y":
|
||||
m.Confirmed = true
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
case "n":
|
||||
m.Confirmed = false
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m ConfirmModel) View() string {
|
||||
s := styles.TitleStyle.Render("Confirm Installation")
|
||||
s += "\n\n"
|
||||
s += "Please review your installation settings:\n\n"
|
||||
s += fmt.Sprintf(" Disk: %s\n", m.Disk)
|
||||
s += fmt.Sprintf(" Encryption: %s\n", map[bool]string{true: "Enabled (LUKS2)", false: "Disabled"}[m.EnableLUKS])
|
||||
s += fmt.Sprintf(" Hostname: %s\n", m.Hostname)
|
||||
s += fmt.Sprintf(" Username: %s\n", m.Username)
|
||||
s += fmt.Sprintf(" Filesystem: btrfs\n")
|
||||
s += fmt.Sprintf(" Desktop: Cosmic Desktop\n")
|
||||
s += fmt.Sprintf(" Kernel: linux-hardened\n")
|
||||
s += fmt.Sprintf(" Bootloader: systemd-boot (UEFI)\n")
|
||||
s += "\n"
|
||||
s += styles.HelpStyle.Render("WARNING: This will ERASE ALL DATA on ") + m.Disk + "\n\n"
|
||||
s += styles.HelpStyle.Render("[y] Proceed with installation [n] Cancel")
|
||||
|
||||
return styles.MainStyle.Render(s)
|
||||
}
|
||||
132
tui/steps/encryption.go
Normal file
132
tui/steps/encryption.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type EncryptionModel struct {
|
||||
EnableEncryption bool
|
||||
Password string
|
||||
ConfirmPassword string
|
||||
passwordInput textinput.Model
|
||||
confirmInput textinput.Model
|
||||
focusIndex int
|
||||
Finished bool
|
||||
showInputs bool
|
||||
}
|
||||
|
||||
func NewEncryptionModel() EncryptionModel {
|
||||
pi := textinput.New()
|
||||
pi.Placeholder = "Enter encryption password"
|
||||
pi.EchoMode = textinput.EchoPassword
|
||||
pi.Focus()
|
||||
|
||||
ci := textinput.New()
|
||||
ci.Placeholder = "Confirm password"
|
||||
ci.EchoMode = textinput.EchoPassword
|
||||
|
||||
return EncryptionModel{
|
||||
EnableEncryption: true,
|
||||
passwordInput: pi,
|
||||
confirmInput: ci,
|
||||
showInputs: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (m EncryptionModel) Init() tea.Cmd {
|
||||
return textinput.Blink
|
||||
}
|
||||
|
||||
func (m EncryptionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "enter":
|
||||
if !m.showInputs {
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if m.focusIndex == 0 {
|
||||
m.focusIndex = 1
|
||||
m.passwordInput.Blur()
|
||||
return m, m.confirmInput.Focus()
|
||||
} else if m.focusIndex == 1 {
|
||||
if m.passwordInput.Value() == m.confirmInput.Value() && m.passwordInput.Value() != "" {
|
||||
m.Password = m.passwordInput.Value()
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
case "y":
|
||||
if !m.showInputs {
|
||||
m.EnableEncryption = true
|
||||
m.showInputs = true
|
||||
return m, m.passwordInput.Focus()
|
||||
}
|
||||
|
||||
case "n":
|
||||
if !m.showInputs {
|
||||
m.EnableEncryption = false
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
|
||||
case "tab", "shift+tab":
|
||||
if m.showInputs {
|
||||
if m.focusIndex == 0 {
|
||||
m.focusIndex = 1
|
||||
m.passwordInput.Blur()
|
||||
return m, m.confirmInput.Focus()
|
||||
} else {
|
||||
m.focusIndex = 0
|
||||
m.confirmInput.Blur()
|
||||
return m, m.passwordInput.Focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
if m.showInputs {
|
||||
if m.focusIndex == 0 {
|
||||
m.passwordInput, cmd = m.passwordInput.Update(msg)
|
||||
} else {
|
||||
m.confirmInput, cmd = m.confirmInput.Update(msg)
|
||||
}
|
||||
}
|
||||
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m EncryptionModel) View() string {
|
||||
s := styles.TitleStyle.Render("Disk Encryption")
|
||||
s += "\n\n"
|
||||
|
||||
if !m.showInputs {
|
||||
s += "Enable LUKS2 disk encryption? (recommended)\n\n"
|
||||
s += styles.HelpStyle.Render("[y] Yes [n] No")
|
||||
} else {
|
||||
s += "Enter encryption password:\n\n"
|
||||
s += m.passwordInput.View() + "\n\n"
|
||||
s += m.confirmInput.View() + "\n\n"
|
||||
|
||||
if m.passwordInput.Value() != "" && m.confirmInput.Value() != "" {
|
||||
if m.passwordInput.Value() != m.confirmInput.Value() {
|
||||
s += styles.HelpStyle.Render("Passwords do not match\n")
|
||||
}
|
||||
}
|
||||
|
||||
s += styles.HelpStyle.Render("[Tab] Switch fields [Enter] Continue")
|
||||
}
|
||||
|
||||
return styles.MainStyle.Render(s)
|
||||
}
|
||||
61
tui/steps/hostname.go
Normal file
61
tui/steps/hostname.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type HostnameModel struct {
|
||||
Hostname string
|
||||
input textinput.Model
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func NewHostnameModel() HostnameModel {
|
||||
ti := textinput.New()
|
||||
ti.Placeholder = "miasma"
|
||||
ti.Focus()
|
||||
ti.CharLimit = 63
|
||||
|
||||
return HostnameModel{
|
||||
input: ti,
|
||||
}
|
||||
}
|
||||
|
||||
func (m HostnameModel) Init() tea.Cmd {
|
||||
return textinput.Blink
|
||||
}
|
||||
|
||||
func (m HostnameModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "enter":
|
||||
if m.input.Value() != "" {
|
||||
m.Hostname = m.input.Value()
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
m.input, cmd = m.input.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m HostnameModel) View() string {
|
||||
s := styles.TitleStyle.Render("System Hostname")
|
||||
s += "\n\n"
|
||||
s += "Enter a hostname for your system:\n\n"
|
||||
s += m.input.View() + "\n\n"
|
||||
s += styles.HelpStyle.Render("[Enter] Continue")
|
||||
|
||||
return styles.MainStyle.Render(s)
|
||||
}
|
||||
125
tui/steps/user.go
Normal file
125
tui/steps/user.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package steps
|
||||
|
||||
import (
|
||||
"miasma-installer/tui/styles"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type UserModel struct {
|
||||
Username string
|
||||
Password string
|
||||
usernameInput textinput.Model
|
||||
passwordInput textinput.Model
|
||||
confirmInput textinput.Model
|
||||
focusIndex int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func NewUserModel() UserModel {
|
||||
ui := textinput.New()
|
||||
ui.Placeholder = "username"
|
||||
ui.Focus()
|
||||
ui.CharLimit = 32
|
||||
|
||||
pi := textinput.New()
|
||||
pi.Placeholder = "password"
|
||||
pi.EchoMode = textinput.EchoPassword
|
||||
|
||||
ci := textinput.New()
|
||||
ci.Placeholder = "confirm password"
|
||||
ci.EchoMode = textinput.EchoPassword
|
||||
|
||||
return UserModel{
|
||||
usernameInput: ui,
|
||||
passwordInput: pi,
|
||||
confirmInput: ci,
|
||||
}
|
||||
}
|
||||
|
||||
func (m UserModel) Init() tea.Cmd {
|
||||
return textinput.Blink
|
||||
}
|
||||
|
||||
func (m UserModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.Finished {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "enter":
|
||||
if m.focusIndex == 0 && m.usernameInput.Value() != "" {
|
||||
m.focusIndex = 1
|
||||
m.usernameInput.Blur()
|
||||
return m, m.passwordInput.Focus()
|
||||
} else if m.focusIndex == 1 && m.passwordInput.Value() != "" {
|
||||
m.focusIndex = 2
|
||||
m.passwordInput.Blur()
|
||||
return m, m.confirmInput.Focus()
|
||||
} else if m.focusIndex == 2 {
|
||||
if m.passwordInput.Value() == m.confirmInput.Value() && m.passwordInput.Value() != "" {
|
||||
m.Username = m.usernameInput.Value()
|
||||
m.Password = m.passwordInput.Value()
|
||||
m.Finished = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
case "tab", "shift+tab":
|
||||
m.focusIndex = (m.focusIndex + 1) % 3
|
||||
cmds := make([]tea.Cmd, 3)
|
||||
|
||||
if m.focusIndex == 0 {
|
||||
cmds[0] = m.usernameInput.Focus()
|
||||
m.passwordInput.Blur()
|
||||
m.confirmInput.Blur()
|
||||
} else if m.focusIndex == 1 {
|
||||
cmds[1] = m.passwordInput.Focus()
|
||||
m.usernameInput.Blur()
|
||||
m.confirmInput.Blur()
|
||||
} else {
|
||||
cmds[2] = m.confirmInput.Focus()
|
||||
m.usernameInput.Blur()
|
||||
m.passwordInput.Blur()
|
||||
}
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
if m.focusIndex == 0 {
|
||||
m.usernameInput, cmd = m.usernameInput.Update(msg)
|
||||
} else if m.focusIndex == 1 {
|
||||
m.passwordInput, cmd = m.passwordInput.Update(msg)
|
||||
} else {
|
||||
m.confirmInput, cmd = m.confirmInput.Update(msg)
|
||||
}
|
||||
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m UserModel) View() string {
|
||||
s := styles.TitleStyle.Render("User Account")
|
||||
s += "\n\n"
|
||||
s += "Create your user account:\n\n"
|
||||
s += "Username:\n"
|
||||
s += m.usernameInput.View() + "\n\n"
|
||||
s += "Password:\n"
|
||||
s += m.passwordInput.View() + "\n\n"
|
||||
s += "Confirm Password:\n"
|
||||
s += m.confirmInput.View() + "\n\n"
|
||||
|
||||
if m.passwordInput.Value() != "" && m.confirmInput.Value() != "" {
|
||||
if m.passwordInput.Value() != m.confirmInput.Value() {
|
||||
s += styles.HelpStyle.Render("Passwords do not match\n")
|
||||
}
|
||||
}
|
||||
|
||||
s += styles.HelpStyle.Render("[Tab] Switch fields [Enter] Continue")
|
||||
|
||||
return styles.MainStyle.Render(s)
|
||||
}
|
||||
Reference in New Issue
Block a user