Befehle login, servers, distros, profiles, presets, vm, lxc, template list|build, batch, status, logs --follow, cancel. Renderer im Aufbau der Vorgabe (zeichengenau per Golden-File), 24-bit/256/ohne Farbe, --ascii, --quiet, --json, --dry-run; live im Terminal, zeilenweise ohne. SSE mit Wiederverbinden und Polling als Rückfall. Typen aus openapi.json per oapi-codegen; Release-Builds per cli/bauen.sh. Refs #013 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
// Package konfig liest und schreibt ~/.config/proxdeploy/config.toml.
|
||
//
|
||
// url = "https://proxdeploy.example"
|
||
// token = "pd_…"
|
||
// server = "rz1" # optional: Standard für --server
|
||
//
|
||
// [instances.labor] # weitere Instanzen, Auswahl mit --instance labor
|
||
// url = "https://proxdeploy.labor"
|
||
// token = "pd_…"
|
||
//
|
||
// PROXDEPLOY_URL, PROXDEPLOY_TOKEN und PROXDEPLOY_INSTANCE gehen der Datei vor.
|
||
package konfig
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"io/fs"
|
||
"os"
|
||
"path/filepath"
|
||
"runtime"
|
||
|
||
"github.com/BurntSushi/toml"
|
||
)
|
||
|
||
type Instanz struct {
|
||
URL string `toml:"url"`
|
||
Token string `toml:"token"`
|
||
Server string `toml:"server,omitempty"`
|
||
}
|
||
|
||
type Datei struct {
|
||
Instanz
|
||
Instanzen map[string]Instanz `toml:"instances,omitempty"`
|
||
}
|
||
|
||
// Pfad: $XDG_CONFIG_HOME/proxdeploy/config.toml, sonst ~/.config/…; unter Windows %AppData%.
|
||
func Pfad() (string, error) {
|
||
if eigener := os.Getenv("PROXDEPLOY_CONFIG"); eigener != "" {
|
||
return eigener, nil
|
||
}
|
||
basis := os.Getenv("XDG_CONFIG_HOME")
|
||
if basis == "" {
|
||
if runtime.GOOS == "windows" {
|
||
var err error
|
||
if basis, err = os.UserConfigDir(); err != nil {
|
||
return "", err
|
||
}
|
||
} else {
|
||
heim, err := os.UserHomeDir()
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
basis = filepath.Join(heim, ".config")
|
||
}
|
||
}
|
||
return filepath.Join(basis, "proxdeploy", "config.toml"), nil
|
||
}
|
||
|
||
// Lesen liefert die Datei oder eine leere, wenn es sie noch nicht gibt.
|
||
func Lesen() (Datei, string, error) {
|
||
pfad, err := Pfad()
|
||
if err != nil {
|
||
return Datei{}, "", err
|
||
}
|
||
var d Datei
|
||
if _, err := toml.DecodeFile(pfad, &d); err != nil {
|
||
if errors.Is(err, fs.ErrNotExist) {
|
||
return Datei{}, pfad, nil
|
||
}
|
||
return Datei{}, pfad, fmt.Errorf("%s: %w", pfad, err)
|
||
}
|
||
return d, pfad, nil
|
||
}
|
||
|
||
// Waehlen: die gewünschte Instanz (leer = Hauptabschnitt), überlagert von der Umgebung.
|
||
func (d Datei) Waehlen(name string) (Instanz, error) {
|
||
if name == "" {
|
||
name = os.Getenv("PROXDEPLOY_INSTANCE")
|
||
}
|
||
i := d.Instanz
|
||
if name != "" {
|
||
gefunden, ok := d.Instanzen[name]
|
||
if !ok {
|
||
return Instanz{}, fmt.Errorf("Instanz %q steht nicht in der Konfiguration", name)
|
||
}
|
||
i = gefunden
|
||
}
|
||
if url := os.Getenv("PROXDEPLOY_URL"); url != "" {
|
||
i.URL = url
|
||
}
|
||
if token := os.Getenv("PROXDEPLOY_TOKEN"); token != "" {
|
||
i.Token = token
|
||
}
|
||
return i, nil
|
||
}
|
||
|
||
// Setzen trägt eine Instanz ein (leer = Hauptabschnitt).
|
||
func (d *Datei) Setzen(name string, i Instanz) {
|
||
if name == "" {
|
||
d.Instanz = i
|
||
return
|
||
}
|
||
if d.Instanzen == nil {
|
||
d.Instanzen = map[string]Instanz{}
|
||
}
|
||
d.Instanzen[name] = i
|
||
}
|
||
|
||
// Schreiben legt die Datei mit Rechten 0600 an – sie enthält das Token.
|
||
func Schreiben(pfad string, d Datei) error {
|
||
if err := os.MkdirAll(filepath.Dir(pfad), 0o700); err != nil {
|
||
return err
|
||
}
|
||
tmp, err := os.CreateTemp(filepath.Dir(pfad), ".config-*.toml")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer os.Remove(tmp.Name())
|
||
if err := tmp.Chmod(0o600); err != nil {
|
||
tmp.Close()
|
||
return err
|
||
}
|
||
if err := toml.NewEncoder(tmp).Encode(d); err != nil {
|
||
tmp.Close()
|
||
return err
|
||
}
|
||
if err := tmp.Close(); err != nil {
|
||
return err
|
||
}
|
||
return os.Rename(tmp.Name(), pfad)
|
||
}
|