mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-08-28 20:06:32 +00:00
chore: cleanup environment variable option parsing and config handling
This commit is contained in:
@@ -62,10 +62,11 @@ Browsing snapshots:
|
||||
|
||||
## Dev Depedencies
|
||||
|
||||
**Basic Dependencies**
|
||||
**Build Dependencies**
|
||||
|
||||
* Node.JS for UI development
|
||||
* Go 1.21 or greater for server development
|
||||
* go.rice `go install github.com/GeertJohan/go.rice@latest` and `go install github.com/GeertJohan/go.rice/rice@latest`
|
||||
|
||||
**To Edit Protobuffers**
|
||||
```sh
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
(cd proto && ./build.sh)
|
||||
|
||||
go build ./..
|
||||
@@ -0,0 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
go install github.com/GeertJohan/go.rice/rice@latest
|
||||
go install github.com/GeertJohan/go.rice@latest
|
||||
pip install lastversion
|
||||
@@ -22,13 +22,14 @@ import (
|
||||
|
||||
type Server struct {
|
||||
*v1.UnimplementedResticUIServer
|
||||
config config.ConfigStore
|
||||
orchestrator *orchestrator.Orchestrator
|
||||
oplog *oplog.OpLog
|
||||
}
|
||||
|
||||
var _ v1.ResticUIServer = &Server{}
|
||||
|
||||
func NewServer(orchestrator *orchestrator.Orchestrator, oplog *oplog.OpLog) *Server {
|
||||
func NewServer(config config.ConfigStore, orchestrator *orchestrator.Orchestrator, oplog *oplog.OpLog) *Server {
|
||||
s := &Server{
|
||||
orchestrator: orchestrator,
|
||||
oplog: oplog,
|
||||
@@ -39,12 +40,12 @@ func NewServer(orchestrator *orchestrator.Orchestrator, oplog *oplog.OpLog) *Ser
|
||||
|
||||
// GetConfig implements GET /v1/config
|
||||
func (s *Server) GetConfig(ctx context.Context, empty *emptypb.Empty) (*v1.Config, error) {
|
||||
return config.Default.Get()
|
||||
return s.config.Get()
|
||||
}
|
||||
|
||||
// SetConfig implements POST /v1/config
|
||||
func (s *Server) SetConfig(ctx context.Context, c *v1.Config) (*v1.Config, error) {
|
||||
existing, err := config.Default.Get()
|
||||
existing, err := s.config.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check current config: %w", err)
|
||||
}
|
||||
@@ -55,21 +56,21 @@ func (s *Server) SetConfig(ctx context.Context, c *v1.Config) (*v1.Config, error
|
||||
}
|
||||
c.Modno += 1
|
||||
|
||||
if err := config.Default.Update(c); err != nil {
|
||||
if err := s.config.Update(c); err != nil {
|
||||
return nil, fmt.Errorf("failed to update config: %w", err)
|
||||
}
|
||||
|
||||
newConfig, err := config.Default.Get()
|
||||
newConfig, err := s.config.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get newly set config: %w", err)
|
||||
}
|
||||
s.orchestrator.ApplyConfig(newConfig)
|
||||
return config.Default.Get()
|
||||
return newConfig, nil
|
||||
}
|
||||
|
||||
// AddRepo implements POST /v1/config/repo, it includes validation that the repo can be initialized.
|
||||
func (s *Server) AddRepo(ctx context.Context, repo *v1.Repo) (*v1.Config, error) {
|
||||
c, err := config.Default.Get()
|
||||
c, err := s.config.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get config: %w", err)
|
||||
}
|
||||
@@ -88,7 +89,7 @@ func (s *Server) AddRepo(ctx context.Context, repo *v1.Repo) (*v1.Config, error)
|
||||
}
|
||||
|
||||
zap.L().Debug("Updating config")
|
||||
if err := config.Default.Update(c); err != nil {
|
||||
if err := s.config.Update(c); err != nil {
|
||||
return nil, fmt.Errorf("failed to update config: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -12,13 +11,6 @@ import (
|
||||
)
|
||||
|
||||
var ErrConfigNotFound = fmt.Errorf("config not found")
|
||||
var configDirFlag = flag.String("config_dir", "", "The directory to store the config file")
|
||||
|
||||
var Default ConfigStore = &CachingValidatingStore{
|
||||
ConfigStore: &JsonFileStore{
|
||||
Path: path.Join(configDir(*configDirFlag), "config.json"),
|
||||
},
|
||||
}
|
||||
|
||||
type ConfigStore interface {
|
||||
Get() (*v1.Config, error)
|
||||
@@ -51,7 +43,7 @@ func configDir(override string) string {
|
||||
|
||||
type CachingValidatingStore struct {
|
||||
ConfigStore
|
||||
mu sync.Mutex
|
||||
mu sync.Mutex
|
||||
config *v1.Config
|
||||
}
|
||||
|
||||
@@ -94,4 +86,4 @@ func (c *CachingValidatingStore) Update(config *v1.Config) error {
|
||||
|
||||
c.config = config
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package envopts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ConfigFilePath() string {
|
||||
if val := os.Getenv("RESTICUI_CONFIG_PATH"); val != "" {
|
||||
return val
|
||||
}
|
||||
if val := os.Getenv("XDG_CONFIG_HOME"); val != "" {
|
||||
return path.Join(val, "resticui/config.json")
|
||||
}
|
||||
return path.Join(getHomeDir(), ".config/resticui/config.json")
|
||||
}
|
||||
|
||||
func DataDir() string {
|
||||
if val := os.Getenv("RESTICUI_DATA_DIR"); val != "" {
|
||||
return val
|
||||
}
|
||||
if val := os.Getenv("XDG_DATA_HOME"); val != "" {
|
||||
return path.Join(val, "resticui")
|
||||
}
|
||||
return path.Join(getHomeDir(), ".local/share/resticui")
|
||||
}
|
||||
|
||||
func BindAddress() string {
|
||||
if val := os.Getenv("RESTICUI_PORT"); val != "" {
|
||||
if !strings.Contains(val, ":") {
|
||||
return ":" + val
|
||||
}
|
||||
return val
|
||||
}
|
||||
return ":9898"
|
||||
}
|
||||
|
||||
func getHomeDir() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("couldn't determine home directory: %v", err))
|
||||
}
|
||||
return home
|
||||
}
|
||||
@@ -30,15 +30,11 @@ type Orchestrator struct {
|
||||
externTasks chan Task // externTasks is a channel that externally added tasks can be added to, they will be consumed by Run()
|
||||
}
|
||||
|
||||
func NewOrchestrator(configProvider config.ConfigStore, oplog *oplog.OpLog) (*Orchestrator, error) {
|
||||
cfg, err := configProvider.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get config: %w", err)
|
||||
}
|
||||
|
||||
func NewOrchestrator(cfg *v1.Config, oplog *oplog.OpLog) (*Orchestrator, error) {
|
||||
return &Orchestrator{
|
||||
config: cfg,
|
||||
OpLog: oplog,
|
||||
config: cfg,
|
||||
OpLog: oplog,
|
||||
// repoPool created with a memory store to ensure the config is updated in an atomic operation with the repo pool's config value.
|
||||
repoPool: newResticRepoPool(&config.MemoryStore{Config: cfg}),
|
||||
externTasks: make(chan Task, 2),
|
||||
}, nil
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func TestReadBackupProgressEntries(t *testing.T) {
|
||||
t.Parallel()
|
||||
testInput := `{"message_type":"status","percent_done":0,"total_files":1,"total_bytes":15}
|
||||
{"message_type":"summary","files_new":0,"files_changed":0,"files_unmodified":166,"dirs_new":0,"dirs_changed":0,"dirs_unmodified":128,"data_blobs":0,"tree_blobs":0,"data_added":0,"total_files_processed":166,"total_bytes_processed":16754463,"total_duration":0.235433378,"id":"d4558b360cc1b7966e416e010382ab8feb49d14da7832266832d69a43af10147"}`
|
||||
{"message_type":"summary","files_new":0,"files_changed":0,"files_unmodified":166,"dirs_new":0,"dirs_changed":0,"dirs_unmodified":128,"data_blobs":0,"tree_blobs":0,"data_added":0,"total_files_processed":166,"total_bytes_processed":16754463,"total_duration":0.235433378,"snapshot_id":"d4558b360cc1b7966e416e010382ab8feb49d14da7832266832d69a43af10147"}`
|
||||
|
||||
b := bytes.NewBuffer([]byte(testInput))
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#! /bin/bash
|
||||
buf generate
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#! /bin/sh
|
||||
|
||||
buf generate
|
||||
+14
-9
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
|
||||
"github.com/garethgeorge/resticui/internal/api"
|
||||
"github.com/garethgeorge/resticui/internal/config"
|
||||
"github.com/garethgeorge/resticui/internal/envopts"
|
||||
"github.com/garethgeorge/resticui/internal/oplog"
|
||||
"github.com/garethgeorge/resticui/internal/orchestrator"
|
||||
static "github.com/garethgeorge/resticui/webui"
|
||||
@@ -25,16 +25,14 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := os.Getenv("RESTICUI_PORT")
|
||||
if port == "" {
|
||||
port = "9898"
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
go onterm(cancel)
|
||||
|
||||
if _, err := config.Default.Get(); err != nil {
|
||||
configStore := createConfigProvider()
|
||||
|
||||
cfg, err := configStore.Get()
|
||||
if err != nil {
|
||||
zap.S().Fatalf("Error loading config: %v", err)
|
||||
}
|
||||
|
||||
@@ -53,7 +51,7 @@ func main() {
|
||||
}
|
||||
defer oplog.Close()
|
||||
|
||||
orchestrator, err := orchestrator.NewOrchestrator(config.Default, oplog)
|
||||
orchestrator, err := orchestrator.NewOrchestrator(cfg, oplog)
|
||||
if err != nil {
|
||||
zap.S().Fatalf("Error creating orchestrator: %v", err)
|
||||
}
|
||||
@@ -68,6 +66,7 @@ func main() {
|
||||
}()
|
||||
|
||||
apiServer := api.NewServer(
|
||||
configStore,
|
||||
orchestrator, // TODO: eliminate default config
|
||||
oplog,
|
||||
)
|
||||
@@ -85,7 +84,7 @@ func main() {
|
||||
|
||||
// Serve the HTTP gateway
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%s", port),
|
||||
Addr: envopts.BindAddress(),
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
@@ -122,6 +121,12 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func createConfigProvider() config.ConfigStore {
|
||||
return &config.CachingValidatingStore{
|
||||
ConfigStore: &config.JsonFileStore{Path: envopts.ConfigFilePath()},
|
||||
}
|
||||
}
|
||||
|
||||
func onterm(callback func()) {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigchan, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
Reference in New Issue
Block a user