once-add/internal/config/config.go
28allday 68c64265a6 once-add: deploy + remove Once apps at <name>.local
A small Go tool that wraps the `/etc/hosts` + `once deploy --disable-tls`
recipe needed to host a Once app on a single-label `<name>.local`. Adds
the hosts entry, runs the deploy, polls /up, and on removal cleans the
hosts line that the Once UI orphans (including the orphan-only case,
where the app is already gone).

Bubble Tea TUI for interactive use; non-interactive CLI for scripts.
Curated apps live in /etc/once-add/apps.toml; seeded with Writebook +
Campfire on first run.
2026-05-28 07:23:07 +01:00

64 lines
1.8 KiB
Go

// Package config loads the curated app list for the once-add wizard from
// /etc/once-add/apps.toml, writing a default seed if the file is absent.
package config
import (
"os"
"path/filepath"
"github.com/BurntSushi/toml"
)
// Path is the on-disk location of the curated app list. Edit it to add apps;
// no rebuild of once-add is needed.
const Path = "/etc/once-add/apps.toml"
// App is one curated entry shown in the wizard's app picker.
type App struct {
Name string `toml:"name"` // display name, e.g. "Writebook"
Image string `toml:"image"` // container image ref
Description string `toml:"description"` // one-line description
Suggested string `toml:"suggested"` // pre-fills the hostname field
}
type file struct {
App []App `toml:"app"`
}
const defaultSeed = `# once-add curated apps. Edit freely — add [[app]] blocks; no rebuild needed.
# 'suggested' pre-fills the hostname field in the wizard.
[[app]]
name = "Writebook"
image = "ghcr.io/basecamp/writebook"
description = "Books & documentation"
suggested = "book"
[[app]]
name = "Campfire"
image = "ghcr.io/basecamp/once-campfire"
description = "Team chat"
suggested = "chat"
`
// Load reads the curated app list, writing the default seed first if the file
// does not yet exist. Writing the seed requires root (once-add runs as root).
func Load() ([]App, error) {
if _, err := os.Stat(Path); os.IsNotExist(err) {
if err := writeDefault(); err != nil {
return nil, err
}
}
var f file
if _, err := toml.DecodeFile(Path, &f); err != nil {
return nil, err
}
return f.App, nil
}
func writeDefault() error {
if err := os.MkdirAll(filepath.Dir(Path), 0o755); err != nil {
return err
}
return os.WriteFile(Path, []byte(defaultSeed), 0o644)
}