feat(01-02): implement layered compass config
- Merge plugin defaults, sorted YAML, SUMMER_ env, overrides and Set - Persist atomically to env overrides; Reload clears runtime Set - Discover HasConfig before Register and print layered hello values
This commit is contained in:
@@ -2,62 +2,348 @@ package compass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/knadh/koanf/parsers/yaml"
|
||||
"github.com/knadh/koanf/providers/confmap"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
// Config is a YAML configuration tree with dot-path access.
|
||||
type Config struct {
|
||||
k *koanf.Koanf
|
||||
// Options controls how configuration is loaded.
|
||||
type Options struct {
|
||||
// Dir is the app config directory, typically "config".
|
||||
Dir string
|
||||
// Env is the environment name. Empty means detect from SUMMER_ENV,
|
||||
// defaulting to "production". An explicit value wins over SUMMER_ENV.
|
||||
Env string
|
||||
// Environ is the KEY=VALUE list used for SUMMER_ variables and
|
||||
// SUMMER_ENV detection. Nil means os.Environ(). A .env file fills
|
||||
// only keys absent from this list and never mutates the process
|
||||
// environment.
|
||||
Environ []string
|
||||
}
|
||||
|
||||
// Load reads config/<section>.yaml files from dir. Each filename stem becomes
|
||||
// the top-level section, so config/app.yaml key name is app.name.
|
||||
type pluginFS struct {
|
||||
id string
|
||||
fsys fs.FS
|
||||
}
|
||||
|
||||
// Config is a YAML configuration tree with layered overrides and
|
||||
// dot-path access.
|
||||
type Config struct {
|
||||
mu sync.RWMutex
|
||||
opts Options
|
||||
dir string
|
||||
env string
|
||||
environ []string
|
||||
plugins []pluginFS
|
||||
k *koanf.Koanf
|
||||
runtime *koanf.Koanf
|
||||
}
|
||||
|
||||
// Load reads config from dir using SUMMER_ENV (default production).
|
||||
func Load(dir string) (*Config, error) {
|
||||
return Open(Options{Dir: dir})
|
||||
}
|
||||
|
||||
// Open loads configuration using opts.
|
||||
func Open(opts Options) (*Config, error) {
|
||||
if opts.Dir == "" {
|
||||
return nil, fmt.Errorf("compass: config directory is empty")
|
||||
}
|
||||
c := &Config{
|
||||
opts: opts,
|
||||
dir: opts.Dir,
|
||||
runtime: koanf.New("."),
|
||||
}
|
||||
if err := c.refreshSources(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.rebuild(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Environment returns the active environment name.
|
||||
func (c *Config) Environment() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.env
|
||||
}
|
||||
|
||||
// MergePlugin merges an embedded plugin config filesystem at the bare
|
||||
// plugin ID path. config/config.yaml keys become <id>.<key>.
|
||||
func (c *Config) MergePlugin(id string, fsys fs.FS) error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("compass: config is nil")
|
||||
}
|
||||
if id == "" {
|
||||
return fmt.Errorf("compass: plugin id is empty")
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
replaced := false
|
||||
for i, p := range c.plugins {
|
||||
if p.id == id {
|
||||
c.plugins[i] = pluginFS{id: id, fsys: fsys}
|
||||
replaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !replaced {
|
||||
c.plugins = append(c.plugins, pluginFS{id: id, fsys: fsys})
|
||||
}
|
||||
if c.runtime == nil {
|
||||
c.runtime = koanf.New(".")
|
||||
}
|
||||
return c.rebuild()
|
||||
}
|
||||
|
||||
// Lookup returns the value at path and whether it exists.
|
||||
func (c *Config) Lookup(path string) (any, bool) {
|
||||
v := c.view()
|
||||
if v == nil || !v.Exists(path) {
|
||||
return nil, false
|
||||
}
|
||||
return v.Get(path), true
|
||||
}
|
||||
|
||||
// String returns the string value at path, or "" if unset.
|
||||
func (c *Config) String(path string) string {
|
||||
v := c.view()
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.String(path)
|
||||
}
|
||||
|
||||
// Int returns the int value at path, or 0 if unset.
|
||||
func (c *Config) Int(path string) int {
|
||||
v := c.view()
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
return v.Int(path)
|
||||
}
|
||||
|
||||
// Bool returns the bool value at path, or false if unset.
|
||||
func (c *Config) Bool(path string) bool {
|
||||
v := c.view()
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return v.Bool(path)
|
||||
}
|
||||
|
||||
// Has reports whether path exists in the merged tree.
|
||||
func (c *Config) Has(path string) bool {
|
||||
v := c.view()
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return v.Exists(path)
|
||||
}
|
||||
|
||||
// LoadSection unmarshals the map at path into out using `koanf` tags.
|
||||
func (c *Config) LoadSection(path string, out any) error {
|
||||
v := c.view()
|
||||
if v == nil {
|
||||
return fmt.Errorf("compass: config is empty")
|
||||
}
|
||||
return v.UnmarshalWithConf(path, out, koanf.UnmarshalConf{Tag: "koanf"})
|
||||
}
|
||||
|
||||
func (c *Config) view() *koanf.Koanf {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
if c.k == nil {
|
||||
return nil
|
||||
}
|
||||
out := c.k.Copy()
|
||||
if c.runtime != nil {
|
||||
_ = out.Merge(c.runtime)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (c *Config) refreshSources() error {
|
||||
base := c.opts.Environ
|
||||
if c.opts.Environ == nil {
|
||||
base = os.Environ()
|
||||
}
|
||||
dotenv, err := readDotEnv(filepath.Join(filepath.Dir(c.dir), ".env"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.environ = mergeEnviron(base, dotenv)
|
||||
|
||||
envName := c.opts.Env
|
||||
if envName == "" {
|
||||
envName = lookupEnv(c.environ, "SUMMER_ENV")
|
||||
}
|
||||
if envName == "" {
|
||||
envName = "production"
|
||||
}
|
||||
envName, err = sanitizeEnv(envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.env = envName
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) rebuild() error {
|
||||
k := koanf.New(".")
|
||||
for _, p := range c.plugins {
|
||||
if err := mergePluginFS(k, p.id, p.fsys); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.dir != "" {
|
||||
if err := loadSortedSections(k, c.dir, false); err != nil {
|
||||
return err
|
||||
}
|
||||
envDir := filepath.Join(c.dir, "env", c.env)
|
||||
if err := loadSortedSections(k, envDir, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := loadEnvVars(k, c.environ); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.dir != "" && c.env != "" {
|
||||
overrides := filepath.Join(c.dir, "env", c.env, "overrides.yaml")
|
||||
if err := loadOverrides(k, overrides); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.k = k
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadSortedSections(k *koanf.Koanf, dir string, skipOverrides bool) error {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: read config dir %s: %w", dir, err)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
parser := yaml.Parser()
|
||||
return fmt.Errorf("compass: read config dir: %w", err)
|
||||
}
|
||||
names := make([]string, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
section, ok := sectionName(name)
|
||||
if !ok {
|
||||
if skipOverrides && isOverridesFile(name) {
|
||||
continue
|
||||
}
|
||||
if _, ok := sectionName(name); !ok {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
parser := yaml.Parser()
|
||||
for _, name := range names {
|
||||
section, _ := sectionName(name)
|
||||
path := filepath.Join(dir, name)
|
||||
raw, err := os.ReadFile(path)
|
||||
tmp := koanf.New(".")
|
||||
if err := tmp.Load(file.Provider(path), parser); err != nil {
|
||||
return fmt.Errorf("compass: parse %s: %w", filepath.Base(path), err)
|
||||
}
|
||||
if err := k.MergeAt(tmp, section); err != nil {
|
||||
return fmt.Errorf("compass: merge %s: %w", filepath.Base(path), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadOverrides(k *koanf.Koanf, path string) error {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("compass: stat overrides: %w", err)
|
||||
}
|
||||
if err := k.Load(file.Provider(path), yaml.Parser()); err != nil {
|
||||
return fmt.Errorf("compass: parse overrides: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mergePluginFS(k *koanf.Koanf, id string, fsys fs.FS) error {
|
||||
if fsys == nil {
|
||||
return nil
|
||||
}
|
||||
var files []string
|
||||
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: read %s: %w", path, err)
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if _, ok := sectionName(filepath.Base(path)); !ok {
|
||||
return nil
|
||||
}
|
||||
files = append(files, path)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("compass: read plugin config %s: %w", id, err)
|
||||
}
|
||||
sort.Strings(files)
|
||||
parser := yaml.Parser()
|
||||
for _, path := range files {
|
||||
raw, err := fs.ReadFile(fsys, path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("compass: read plugin config %s: %w", id, err)
|
||||
}
|
||||
parsed, err := parser.Unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: parse %s: %w", path, err)
|
||||
return fmt.Errorf("compass: parse plugin config %s: %w", id, err)
|
||||
}
|
||||
if parsed == nil {
|
||||
parsed = map[string]any{}
|
||||
}
|
||||
if err := k.Set(section, parsed); err != nil {
|
||||
return nil, fmt.Errorf("compass: set section %s: %w", section, err)
|
||||
tmp := koanf.New(".")
|
||||
if err := tmp.Load(confmap.Provider(parsed, ""), nil); err != nil {
|
||||
return fmt.Errorf("compass: load plugin config %s: %w", id, err)
|
||||
}
|
||||
at := pluginMergePath(id, path)
|
||||
if err := k.MergeAt(tmp, at); err != nil {
|
||||
return fmt.Errorf("compass: merge plugin config %s: %w", id, err)
|
||||
}
|
||||
}
|
||||
return &Config{k: k}, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the string value at path, or "" if unset.
|
||||
func (c *Config) String(path string) string {
|
||||
if c == nil || c.k == nil {
|
||||
return ""
|
||||
func pluginMergePath(id, path string) string {
|
||||
rel := filepath.ToSlash(path)
|
||||
base := filepath.Base(rel)
|
||||
section, _ := sectionName(base)
|
||||
if section == "config" {
|
||||
return id
|
||||
}
|
||||
return c.k.String(path)
|
||||
return id + "." + section
|
||||
}
|
||||
|
||||
func isOverridesFile(name string) bool {
|
||||
return name == "overrides.yaml" || name == "overrides.yml"
|
||||
}
|
||||
|
||||
func sectionName(filename string) (string, bool) {
|
||||
|
||||
124
compass/env.go
Normal file
124
compass/env.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/knadh/koanf/providers/env/v2"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
const envPrefix = "SUMMER_"
|
||||
|
||||
func loadEnvVars(k *koanf.Koanf, environ []string) error {
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
return k.Load(env.Provider(".", env.Opt{
|
||||
Prefix: envPrefix,
|
||||
EnvironFunc: func() []string {
|
||||
if environ == nil {
|
||||
return []string{}
|
||||
}
|
||||
return environ
|
||||
},
|
||||
TransformFunc: transformSummerKey,
|
||||
}), nil)
|
||||
}
|
||||
|
||||
func transformSummerKey(key, value string) (string, any) {
|
||||
if key == "SUMMER_ENV" {
|
||||
return "", nil
|
||||
}
|
||||
rest, ok := strings.CutPrefix(key, envPrefix)
|
||||
if !ok || rest == "" {
|
||||
return "", nil
|
||||
}
|
||||
parts := strings.Split(rest, "__")
|
||||
for i, part := range parts {
|
||||
parts[i] = strings.ToLower(part)
|
||||
}
|
||||
return strings.Join(parts, "."), value
|
||||
}
|
||||
|
||||
func readDotEnv(path string) ([]string, error) {
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("compass: read .env: %w", err)
|
||||
}
|
||||
var out []string
|
||||
for _, line := range strings.Split(string(raw), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if after, ok := strings.CutPrefix(line, "export "); ok {
|
||||
line = strings.TrimSpace(after)
|
||||
}
|
||||
key, val, ok := strings.Cut(line, "=")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key = strings.TrimSpace(key)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
val = strings.TrimSpace(val)
|
||||
if len(val) >= 2 {
|
||||
if (val[0] == '"' && val[len(val)-1] == '"') || (val[0] == '\'' && val[len(val)-1] == '\'') {
|
||||
val = val[1 : len(val)-1]
|
||||
}
|
||||
}
|
||||
out = append(out, key+"="+val)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mergeEnviron(real, dotenv []string) []string {
|
||||
present := make(map[string]struct{}, len(real))
|
||||
out := make([]string, 0, len(real)+len(dotenv))
|
||||
for _, kv := range real {
|
||||
key, _, _ := strings.Cut(kv, "=")
|
||||
present[key] = struct{}{}
|
||||
out = append(out, kv)
|
||||
}
|
||||
for _, kv := range dotenv {
|
||||
key, _, _ := strings.Cut(kv, "=")
|
||||
if _, ok := present[key]; ok {
|
||||
continue
|
||||
}
|
||||
out = append(out, kv)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func lookupEnv(environ []string, key string) string {
|
||||
for i := len(environ) - 1; i >= 0; i-- {
|
||||
k, v, ok := strings.Cut(environ[i], "=")
|
||||
if ok && k == key {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func sanitizeEnv(env string) (string, error) {
|
||||
if env == "" {
|
||||
return "", fmt.Errorf("compass: environment name is empty")
|
||||
}
|
||||
if env == "." || env == ".." || strings.Contains(env, "..") || strings.ContainsAny(env, `/\`) {
|
||||
return "", fmt.Errorf("compass: invalid environment name")
|
||||
}
|
||||
for _, r := range env {
|
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '-' || r == '_' {
|
||||
continue
|
||||
}
|
||||
return "", fmt.Errorf("compass: invalid environment name")
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
107
compass/persist.go
Normal file
107
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)))
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
name: hello-app
|
||||
debug: false
|
||||
|
||||
2
examples/hello/config/env/development/app.yaml
vendored
Normal file
2
examples/hello/config/env/development/app.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
name: hello-dev
|
||||
debug: true
|
||||
@@ -11,16 +11,21 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 // indirect
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/file v1.2.1 // indirect
|
||||
github.com/knadh/koanf/v2 v2.3.6 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/spf13/cobra v1.10.2 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -9,6 +11,12 @@ github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpb
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 h1:u70vV5IyaM0HvONh8HoqBC97oTgO33KcpZbTLiKVinU=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 h1:L15hbvMqlvhwUuCtL9BkL+rqiMAjk6cZc8O9XoDtE3A=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 h1:a3KagndPqhcWHQv6Pz4OZmwkI/yMeTjkiZye6ZCkyW0=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1/go.mod h1:1g01PE+Ve1gBfWNNw2wmULRP0tc8RJrjn5p2N/jNCIc=
|
||||
github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP3AESOJYp9wM=
|
||||
github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
||||
github.com/knadh/koanf/v2 v2.3.6 h1:JoQPSJmvS4aP0xNc8xMDr5tcrkSEInL23/Il7pITAKo=
|
||||
github.com/knadh/koanf/v2 v2.3.6/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
@@ -30,6 +38,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
1
examples/hello/plugins/base/config/config.yaml
Normal file
1
examples/hello/plugins/base/config/config.yaml
Normal file
@@ -0,0 +1 @@
|
||||
posts_per_page: 10
|
||||
@@ -7,13 +7,21 @@ toolchain go1.27.0
|
||||
require git.golem15.com/golem15/summercms v0.0.0
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 // indirect
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/file v1.2.1 // indirect
|
||||
github.com/knadh/koanf/v2 v2.3.6 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/spf13/cobra v1.10.2 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
)
|
||||
|
||||
replace git.golem15.com/golem15/summercms => ../../../..
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 h1:u70vV5IyaM0HvONh8HoqBC97oTgO33KcpZbTLiKVinU=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 h1:L15hbvMqlvhwUuCtL9BkL+rqiMAjk6cZc8O9XoDtE3A=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 h1:a3KagndPqhcWHQv6Pz4OZmwkI/yMeTjkiZye6ZCkyW0=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1/go.mod h1:1g01PE+Ve1gBfWNNw2wmULRP0tc8RJrjn5p2N/jNCIc=
|
||||
github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP3AESOJYp9wM=
|
||||
github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
||||
github.com/knadh/koanf/v2 v2.3.6 h1:JoQPSJmvS4aP0xNc8xMDr5tcrkSEInL23/Il7pITAKo=
|
||||
github.com/knadh/koanf/v2 v2.3.6/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
@@ -18,10 +29,17 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
|
||||
"git.golem15.com/golem15/summercms/backpack"
|
||||
"git.golem15.com/golem15/summercms/party"
|
||||
)
|
||||
|
||||
//go:embed config
|
||||
var configFS embed.FS
|
||||
|
||||
// Plugin is the golem15.hello plugin.
|
||||
type Plugin struct{}
|
||||
|
||||
@@ -14,6 +20,8 @@ func (p *Plugin) Requires() []string { return nil }
|
||||
func (p *Plugin) Register(*backpack.App) error { return nil }
|
||||
func (p *Plugin) Boot(*backpack.App) error { return nil }
|
||||
|
||||
func (p *Plugin) ConfigFS() fs.FS { return configFS }
|
||||
|
||||
func init() {
|
||||
party.Register(&Plugin{})
|
||||
}
|
||||
|
||||
@@ -7,16 +7,21 @@ toolchain go1.27.0
|
||||
require git.golem15.com/golem15/summercms v0.0.0
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 // indirect
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 // indirect
|
||||
github.com/knadh/koanf/providers/file v1.2.1 // indirect
|
||||
github.com/knadh/koanf/v2 v2.3.6 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/spf13/cobra v1.10.2 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
)
|
||||
|
||||
replace git.golem15.com/golem15/summercms => ../../../..
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -9,6 +11,12 @@ github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpb
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 h1:u70vV5IyaM0HvONh8HoqBC97oTgO33KcpZbTLiKVinU=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 h1:L15hbvMqlvhwUuCtL9BkL+rqiMAjk6cZc8O9XoDtE3A=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 h1:a3KagndPqhcWHQv6Pz4OZmwkI/yMeTjkiZye6ZCkyW0=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1/go.mod h1:1g01PE+Ve1gBfWNNw2wmULRP0tc8RJrjn5p2N/jNCIc=
|
||||
github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP3AESOJYp9wM=
|
||||
github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
||||
github.com/knadh/koanf/v2 v2.3.6 h1:JoQPSJmvS4aP0xNc8xMDr5tcrkSEInL23/Il7pITAKo=
|
||||
github.com/knadh/koanf/v2 v2.3.6/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
@@ -30,6 +38,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -29,10 +29,14 @@ func (p *Plugin) Commands() []bonfire.Command {
|
||||
Description: "Print the configured application name",
|
||||
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
||||
name := ""
|
||||
posts := 0
|
||||
debug := false
|
||||
if p.app != nil && p.app.Config != nil {
|
||||
name = p.app.Config.String("app.name")
|
||||
posts = p.app.Config.Int("golem15.hello.posts_per_page")
|
||||
debug = p.app.Config.Bool("app.debug")
|
||||
}
|
||||
out.Println(name)
|
||||
out.Printf("name=%s posts_per_page=%d debug=%t\n", name, posts, debug)
|
||||
return nil
|
||||
},
|
||||
}}
|
||||
|
||||
5
go.mod
5
go.mod
@@ -6,11 +6,15 @@ toolchain go1.27.0
|
||||
|
||||
require (
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1
|
||||
github.com/knadh/koanf/providers/file v1.2.1
|
||||
github.com/knadh/koanf/v2 v2.3.6
|
||||
github.com/spf13/cobra v1.10.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
@@ -18,4 +22,5 @@ require (
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
)
|
||||
|
||||
10
go.sum
10
go.sum
@@ -1,6 +1,8 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -9,6 +11,12 @@ github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpb
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1 h1:u70vV5IyaM0HvONh8HoqBC97oTgO33KcpZbTLiKVinU=
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1 h1:L15hbvMqlvhwUuCtL9BkL+rqiMAjk6cZc8O9XoDtE3A=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.1/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1 h1:a3KagndPqhcWHQv6Pz4OZmwkI/yMeTjkiZye6ZCkyW0=
|
||||
github.com/knadh/koanf/providers/env/v2 v2.0.1/go.mod h1:1g01PE+Ve1gBfWNNw2wmULRP0tc8RJrjn5p2N/jNCIc=
|
||||
github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP3AESOJYp9wM=
|
||||
github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
||||
github.com/knadh/koanf/v2 v2.3.6 h1:JoQPSJmvS4aP0xNc8xMDr5tcrkSEInL23/Il7pITAKo=
|
||||
github.com/knadh/koanf/v2 v2.3.6/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
@@ -30,6 +38,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"git.golem15.com/golem15/summercms/backpack"
|
||||
"git.golem15.com/golem15/summercms/pact"
|
||||
)
|
||||
|
||||
// Plugin is the required descriptor every compiled plugin implements.
|
||||
@@ -97,6 +98,13 @@ func activate(registered []Plugin, app *backpack.App, ids []string) ([]Plugin, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, p := range ordered {
|
||||
if hc, ok := p.(pact.HasConfig); ok && app.Config != nil {
|
||||
if err := app.Config.MergePlugin(p.ID(), hc.ConfigFS()); err != nil {
|
||||
return nil, fmt.Errorf("party: config %s: %w", p.ID(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, p := range ordered {
|
||||
if err := p.Register(app); err != nil {
|
||||
return nil, fmt.Errorf("party: register %s: %w", p.ID(), err)
|
||||
|
||||
Reference in New Issue
Block a user