feat(cli): proxdeploy in Go
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>
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user