feat(01-01): boot hello app and dispatch greeter:hello
- Add party plugin registry with Register-before-Boot activation - Add backpack, compass, bonfire, and pact capability interfaces - Add examples/hello with two compiled plugin modules
This commit is contained in:
72
compass/config.go
Normal file
72
compass/config.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/knadh/koanf/parsers/yaml"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
// Config is a YAML configuration tree with dot-path access.
|
||||
type Config struct {
|
||||
k *koanf.Koanf
|
||||
}
|
||||
|
||||
// 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.
|
||||
func Load(dir string) (*Config, error) {
|
||||
k := koanf.New(".")
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: read config dir %s: %w", dir, err)
|
||||
}
|
||||
parser := yaml.Parser()
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
section, ok := sectionName(name)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(dir, name)
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: read %s: %w", path, err)
|
||||
}
|
||||
parsed, err := parser.Unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compass: parse %s: %w", path, 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)
|
||||
}
|
||||
}
|
||||
return &Config{k: k}, 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 ""
|
||||
}
|
||||
return c.k.String(path)
|
||||
}
|
||||
|
||||
func sectionName(filename string) (string, bool) {
|
||||
switch {
|
||||
case strings.HasSuffix(filename, ".yaml"):
|
||||
return strings.TrimSuffix(filename, ".yaml"), true
|
||||
case strings.HasSuffix(filename, ".yml"):
|
||||
return strings.TrimSuffix(filename, ".yml"), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
23
compass/config_test.go
Normal file
23
compass/config_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadStringFromAppSection(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "app.yaml")
|
||||
if err := os.WriteFile(path, []byte("name: hello-app\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cfg, err := Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "hello-app" {
|
||||
t.Fatalf("String(app.name) = %q, want hello-app", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user