refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
107
modules/compass/persist.go
Normal file
107
modules/compass/persist.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/knadh/koanf/parsers/yaml"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
// Set stores an in-memory override that wins over every file and env layer.
|
||||
func (c *Config) Set(path string, value any) error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("compass: config is nil")
|
||||
}
|
||||
if path == "" {
|
||||
return fmt.Errorf("compass: empty config path")
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.runtime == nil {
|
||||
c.runtime = koanf.New(".")
|
||||
}
|
||||
return c.runtime.Set(path, value)
|
||||
}
|
||||
|
||||
// Persist writes runtime overrides to config/env/<env>/overrides.yaml
|
||||
// using an atomic replace and restrictive file permissions.
|
||||
func (c *Config) Persist() error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("compass: config is nil")
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.dir == "" {
|
||||
return fmt.Errorf("compass: config directory is empty")
|
||||
}
|
||||
env, err := sanitizeEnv(c.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destDir, dest, err := overridesPath(c.dir, env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(destDir, 0o700); err != nil {
|
||||
return fmt.Errorf("compass: create overrides dir: %w", err)
|
||||
}
|
||||
raw := []byte("{}\n")
|
||||
if c.runtime != nil {
|
||||
body, err := c.runtime.Marshal(yaml.Parser())
|
||||
if err != nil {
|
||||
return fmt.Errorf("compass: marshal overrides: %w", err)
|
||||
}
|
||||
raw = body
|
||||
}
|
||||
tmp := dest + ".tmp"
|
||||
if err := os.WriteFile(tmp, raw, 0o600); err != nil {
|
||||
return fmt.Errorf("compass: write overrides: %w", err)
|
||||
}
|
||||
if err := os.Rename(tmp, dest); err != nil {
|
||||
_ = os.Remove(tmp)
|
||||
return fmt.Errorf("compass: persist overrides: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reload rebuilds the tree from disk and plugin sources and clears runtime Set.
|
||||
func (c *Config) Reload() error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("compass: config is nil")
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.runtime = koanf.New(".")
|
||||
if err := c.refreshSources(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.rebuild()
|
||||
}
|
||||
|
||||
func overridesPath(dir, env string) (destDir, dest string, err error) {
|
||||
root, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("compass: resolve config dir: %w", err)
|
||||
}
|
||||
root = filepath.Clean(root)
|
||||
destDir = filepath.Clean(filepath.Join(root, "env", env))
|
||||
if !within(root, destDir) {
|
||||
return "", "", fmt.Errorf("compass: persist path escapes config directory")
|
||||
}
|
||||
dest = filepath.Clean(filepath.Join(destDir, "overrides.yaml"))
|
||||
if !within(destDir, dest) {
|
||||
return "", "", fmt.Errorf("compass: persist path escapes config directory")
|
||||
}
|
||||
return destDir, dest, nil
|
||||
}
|
||||
|
||||
func within(root, path string) bool {
|
||||
rel, err := filepath.Rel(root, path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return rel == "." || (rel != ".." && !strings.HasPrefix(rel, ".."+string(os.PathSeparator)))
|
||||
}
|
||||
Reference in New Issue
Block a user