bartender/main.go

213 lines
4.2 KiB
Go
Raw Normal View History

2024-09-07 10:36:44 -07:00
package main
import (
"fmt"
"os"
2024-09-07 16:31:10 -07:00
"sort"
"strings"
2024-09-07 10:36:44 -07:00
2024-09-07 15:23:46 -07:00
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
2024-09-07 16:31:10 -07:00
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/viewport"
2024-09-07 10:36:44 -07:00
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
2024-09-08 18:52:55 -07:00
"github.com/charmbracelet/log"
2024-09-07 14:38:48 -07:00
"golang.org/x/term"
2024-09-07 10:36:44 -07:00
)
type menu struct {
order []string
2024-09-08 20:14:35 -07:00
recipes SoftwarePackages
current int
keys keyMap
help help.Model
spinner spinner.Model
quitting bool
width int
height int
sub chan string
output *string
viewport viewport.Model
2024-09-08 18:52:55 -07:00
logger *log.Logger
2024-09-07 10:36:44 -07:00
}
2024-09-07 18:01:05 -07:00
const (
2024-09-08 20:14:35 -07:00
ordersFile = "/Users/marley/hackin/install.fairie/home/.chezmoidata.yaml"
recipesFile = "/Users/marley/hackin/install.fairie/software.yml"
softwareGroup = "_Full-Desktop"
2024-09-07 18:01:05 -07:00
)
2024-09-08 18:52:55 -07:00
func initialModel(logFile *os.File) menu {
2024-09-07 16:31:10 -07:00
s := spinner.New()
s.Spinner = spinner.MiniDot
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
width, height, _ := term.GetSize(int(os.Stdout.Fd()))
2024-09-07 16:31:10 -07:00
2024-09-08 18:52:55 -07:00
logger := log.New(logFile)
logger.SetLevel(log.InfoLevel)
logger.SetFormatter(log.TextFormatter)
m := menu{
current: 0,
sub: make(chan string),
output: new(string),
viewport: viewport.New(0, 30),
2024-09-08 18:52:55 -07:00
width: width,
height: height,
spinner: s,
keys: keys,
help: help.New(),
logger: logger,
quitting: false,
2024-09-07 15:23:46 -07:00
}
return m
2024-09-07 15:23:46 -07:00
}
type keyMap struct {
Quit key.Binding
}
var keys = keyMap{
Quit: key.NewBinding(
key.WithKeys("q", "esc", "ctrl+c"),
key.WithHelp("q", "quit"),
),
}
func (k keyMap) ShortHelp() []key.Binding {
return []key.Binding{k.Quit}
}
func (k keyMap) FullHelp() [][]key.Binding {
keys := k.ShortHelp()
return [][]key.Binding{
keys,
2024-09-07 10:36:44 -07:00
}
}
2024-09-07 14:38:48 -07:00
type errMsg struct{ err error }
func (e errMsg) Error() string { return e.err.Error() }
func (m *menu) appendOutput(s string) {
*m.output += "\n" + s
m.viewport.SetContent(*m.output)
m.viewport.GotoBottom()
}
2024-09-07 10:36:44 -07:00
func (m menu) Init() tea.Cmd {
2024-09-08 20:14:35 -07:00
return tea.Batch(getOrders(ordersFile), getRecipes(recipesFile), m.spinner.Tick)
2024-09-07 10:36:44 -07:00
}
func (m menu) setDimensions() {
m.width, m.height, _ = term.GetSize(int(os.Stdout.Fd()))
}
2024-09-07 10:36:44 -07:00
func (m menu) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
2024-09-07 16:31:10 -07:00
var cmd tea.Cmd
var cmds []tea.Cmd
2024-09-07 10:36:44 -07:00
switch msg := msg.(type) {
2024-09-07 14:38:48 -07:00
2024-09-08 20:14:35 -07:00
case ordersMsg:
2024-09-07 18:01:05 -07:00
m.order = msg
2024-09-08 20:14:35 -07:00
if len(m.recipes) > 0 {
cmds = append(cmds, m.installPackage(), waitForCmdResponses(m.sub))
}
case recipesMsg:
m.recipes = SoftwarePackages(msg)
if len(m.recipes) > 0 {
cmds = append(cmds, m.installPackage(), waitForCmdResponses(m.sub))
}
case cmdMsg:
m.appendOutput(string(msg))
cmds = append(cmds, waitForCmdResponses(m.sub))
case cmdDoneMsg:
m.current++
m.output = new(string)
cmds = append(cmds, m.installPackage(), waitForCmdResponses(m.sub))
2024-09-07 14:38:48 -07:00
2024-09-07 10:36:44 -07:00
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Quit):
m.quitting = true
2024-09-07 10:36:44 -07:00
return m, tea.Quit
}
2024-09-07 16:31:10 -07:00
case spinner.TickMsg:
m.spinner, cmd = m.spinner.Update(msg)
cmds = append(cmds, cmd)
case tea.WindowSizeMsg:
m.setDimensions()
m.viewport.Width = lipgloss.Width(m.mainView())
m.viewport.Height = lipgloss.Height(m.mainView())
case errMsg:
2024-09-08 18:52:55 -07:00
m.logger.Error("Error: " + msg.Error())
2024-09-07 10:36:44 -07:00
}
m.viewport, cmd = m.viewport.Update(msg)
cmds = append(cmds, cmd)
2024-09-07 16:31:10 -07:00
return m, tea.Batch(cmds...)
2024-09-07 10:36:44 -07:00
}
func (m menu) View() string {
content := lipgloss.JoinHorizontal(lipgloss.Top, m.mainView(), m.sidebarView())
2024-09-07 10:36:44 -07:00
top := strings.Repeat("\n", topPadding)
last := ""
if m.quitting {
last = "\n"
}
page := lipgloss.JoinVertical(lipgloss.Left, top, content, m.helpView(), last)
2024-09-07 15:23:46 -07:00
return lipgloss.PlaceHorizontal(m.width, lipgloss.Center, page)
2024-09-07 10:36:44 -07:00
}
func main() {
2024-09-08 18:52:55 -07:00
l, err := os.Create("log.txt")
if err != nil {
2024-09-08 20:14:35 -07:00
fmt.Println("fatal:", err)
os.Exit(1)
2024-09-08 18:52:55 -07:00
}
defer l.Close()
2024-09-08 20:14:35 -07:00
f, err := tea.LogToFile("tea-log.txt", "debug")
if err != nil {
fmt.Println("fatal:", err)
os.Exit(1)
}
defer f.Close()
p := tea.NewProgram(
2024-09-08 18:52:55 -07:00
initialModel(l),
tea.WithAltScreen(),
)
2024-09-07 10:36:44 -07:00
if _, err := p.Run(); err != nil {
fmt.Printf("There's been an error: %v", err)
os.Exit(1)
}
}
func sortMapKeys(m SoftwarePackages) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}