Each module README now says where the module sits in the dependency graph, why it is its own module, and lists use cases for application developers.
6.2 KiB
compass
Layered YAML configuration with per-environment directories, SUMMER_ environment overrides, embedded plugin defaults and dot-path access.
import "git.golem15.com/golem15/summercms/modules/compass"
Name: Points you the right way; configuration tells the application how to behave in each environment.
Overview
compass is the SummerCMS counterpart of WinterCMS's config/*.php files, per-environment config directories, .env support and Config::get('app.name'). It merges several layers into one tree built on koanf, and every key is read with a dot path such as app.name. Plugin defaults live under the bare plugin ID (acme.blog.posts_per_page) instead of WinterCMS's acme.blog::posts_per_page. The generated main of an application calls compass.Load("config") and hands the result to backpack; party merges plugin defaults into it during activation.
Role in the framework
A dependency-free foundation module that backpack holds and most service modules read from. It is separate so configuration loading can run before the application exists, and so any package can read settings without depending on the container.
Use cases:
- Keep shared settings in a base file and override them per environment.
- Override any key from the environment, for example in containers and CI.
- Ship plugin defaults embedded in the plugin, so the plugin works with no host configuration.
Features
- A fixed layer order, lowest to highest precedence:
- Plugin defaults added with
compass.Config.MergePlugin: a plugin'sconfig.yamlbecomes<plugin id>.<key>, any other<name>.yamlbecomes<plugin id>.<name>.<key>. <dir>/*.yaml(and*.yml): each file is a section named after the file, soconfig/app.yamlprovidesapp.*. Files load in sorted order.<dir>/env/<environment>/*.yaml: per-environment sections with the same naming.SUMMER_environment variables, including values from a.envfile (see Configuration).<dir>/env/<environment>/overrides.yaml, the file written bycompass.Config.Persist.- In-memory values stored with
compass.Config.Set.
- Plugin defaults added with
- Typed getters with zero-value defaults:
compass.Config.String,compass.Config.Int,compass.Config.Bool, pluscompass.Config.Lookupandcompass.Config.Hasto tell a missing key from a zero value. compass.Config.LoadSectionunmarshals a whole subtree into a struct usingkoanfstruct tags.- Runtime overrides:
compass.Config.Setchanges a value in memory,compass.Config.Persistsaves all runtime values atomically to the environment'soverrides.yaml, keeping the keys already saved there and replacing the saved value of any key set at runtime (directory mode 0700, file mode 0600, refusing any path outside the config directory), andcompass.Config.Reloadrereads every source and discards unsaved runtime values. compass.Config.Environmentreports the active environment name, which must consist of letters, digits,-and_.- Safe for concurrent reads and writes.
Usage
package blog
import (
"git.golem15.com/golem15/summercms/modules/compass"
)
type mailSettings struct {
Host string `koanf:"host"`
Port int `koanf:"port"`
}
func loadConfig() (*compass.Config, error) {
cfg, err := compass.Open(compass.Options{Dir: "config", Env: "development"})
if err != nil {
return nil, err
}
name := cfg.String("app.name")
perPage := cfg.Int("acme.blog.posts_per_page")
_, _ = name, perPage
var mail mailSettings
if err := cfg.LoadSection("mail", &mail); err != nil {
return nil, err
}
// Store a runtime override and write it to config/env/development/overrides.yaml.
if err := cfg.Set("acme.blog.posts_per_page", 25); err != nil {
return nil, err
}
return cfg, cfg.Persist()
}
A matching configuration directory:
# config/app.yaml
name: Acme
url: http://localhost:8080
# config/env/development/app.yaml
debug: true
API reference
| Identifier | Description |
|---|---|
compass.Config |
The merged configuration tree with dot-path access. |
compass.Load |
Opens a config directory, taking the environment from SUMMER_ENV. |
compass.Open |
Opens configuration with explicit compass.Options. |
compass.Options |
Config directory, environment name and the environment variable list to read (defaults to the process environment). |
compass.Config.String / compass.Config.Int / compass.Config.Bool |
Typed getters that return the zero value for a missing key. |
compass.Config.Lookup / compass.Config.Has |
Raw value lookup and existence check. |
compass.Config.LoadSection |
Unmarshals a subtree into a struct with koanf tags. |
compass.Config.MergePlugin |
Adds a plugin's embedded default configuration under its plugin ID. |
compass.Config.Set / compass.Config.Persist / compass.Config.Reload |
Runtime overrides, saving them to disk, and rebuilding from disk. |
compass.Config.Environment |
Returns the active environment name. |
Configuration
compass reads the process environment (or compass.Options.Environ when it is set):
| Variable | Default | Effect |
|---|---|---|
SUMMER_ENV |
production |
Selects the environment directory config/env/<name>/. An explicit compass.Options.Env wins over it. |
SUMMER_<SECTION>__<KEY> |
none | Overrides a config key: the prefix is removed, __ separates path segments and the name is lower-cased, so SUMMER_DATABASE__DSN sets database.dsn and SUMMER_ADMIN__JWT__SECRET sets admin.jwt.secret. |
A .env file in the parent directory of the config directory (next to config/) supplies KEY=VALUE lines, with optional export prefixes and quotes, for variables that are not already set in the real environment. It never modifies the process environment.
Dependencies
- SummerCMS modules: none.
- Third-party:
github.com/knadh/koanf/v2with itsproviders/file,providers/env/v2,providers/confmapandparsers/yamlpackages. - Standard library:
fmt,io/fs,os,path/filepath,sort,strings,sync,unicode.
Testing
go test ./modules/compass/...
The tests use temporary directories and explicit environment lists and need no external services.