Documentation
¶
Overview ¶
Package config exposes an opinionated loader for configuration files.
This package exposes a Loadable interface that knows how to load and merge configuration files.
The resulting configuration is made available to consuming applications as a *viper.Viper configuration registry.
Supported format: YAML, JSON
Supported file extensions: "yml", "yaml", "json"
Folder structure:
{base path}/config.yaml # <- root configuration
{base path}/config.d/{environment}/config.yaml # <- configuration to merge for environment
Index ¶
- Variables
- func GetenvOrDefault(key, defaultValue string) string
- func Load(env string, opts ...Option) (*viper.Viper, error)
- func LoadForTest(env string, opts ...Option) (*viper.Viper, error)
- func LoadWithSecrets(env string, opts ...Option) (*viper.Viper, error)
- type CombinedLoader
- type Loadable
- type Loader
- type Option
- func WithBasePath(pth string) Option
- func WithBasePathFromEnvVar(variable string) Option
- func WithEnvDir(dir string) Option
- func WithMute(mute bool) Option
- func WithOutput(output io.Writer) Option
- func WithRadix(radix string) Option
- func WithSearchParentDir(enabled bool) Option
- func WithSuffix(suffix string) Option
- func WithWatch(canWatch bool) Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // DefaultBasePath is the default location of the root config file. DefaultBasePath = "." // DefaultPathEnv is the default environment variable used // to configure the search path for configurations. DefaultPathEnv = "CONFIG_DIR" // DefaultConfigRadix is the default basename for a configuration file. DefaultConfigRadix = "config" // DefaultEnvPath is the default folder for environment-specific configurations, relative to the base path. DefaultEnvPath = "config.d" // DefaultSecretRadix is the default basename for a secrets file. DefaultSecretRadix = "secrets" // DefaultSecretSuffix is the default optional suffix to look for unencrypted secrets. DefaultSecretSuffix = "dec" )
Default values used by this package (may be overridden when loading this package).
Functions ¶
func GetenvOrDefault ¶
GetenvOrDefault wraps os.Getenv, applying a default value if the environment variable "key" is undefined or empty.
func Load ¶
Load configuration files. The merged outcome is available in a *viper.Viper registry.
Example ¶
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/fredbi/go-cli/config"
)
func mustCwd() string {
here, err := os.Getwd()
if err != nil {
err = fmt.Errorf("get current working dir: %w", err)
log.Fatal(err)
}
return here
}
func main() {
here := mustCwd()
os.Setenv("CONFIG_DIR", filepath.Join(here, "examples"))
// load and merge configuration files for environment "dev"
cfg, err := config.Load("dev", config.WithMute(true))
if err != nil {
err = fmt.Errorf("loading config: %w", err)
log.Fatal(err)
return
}
fmt.Println(cfg.AllSettings())
}
Output: map[app:map[threads:10 url:https://example.dev.co] log:map[level:info] metrics:map[enabled:true exporter:prometheus] trace:map[enabled:true exporter:jaeger]]
func LoadForTest ¶
LoadForTest combines configs from a test loader.
This is a convenient wrapper around LoadForEnv for a configuration composed both regular and secrets files.
Typically, test programs would get a configuration from some "test" environment like so:
Usage:
v, err := config.LoadForTest("test")
func LoadWithSecrets ¶
LoadWithSecrets combines configuration files from a default loader with config from (unencrypted) secrets.
This is a convenient wrapper around LoadForEnv for a configuration composed both regular and secrets files.
Just like ¶
Usage:
v, err := config.LoadWithSecrets("dev")
Example ¶
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/fredbi/go-cli/config"
)
func mustCwd() string {
here, err := os.Getwd()
if err != nil {
err = fmt.Errorf("get current working dir: %w", err)
log.Fatal(err)
}
return here
}
func mustTempDir() (string, func()) {
folder, err := os.MkdirTemp("", "")
if err != nil {
err = fmt.Errorf("creating temp dir: %w", err)
log.Fatal(err)
}
return folder, func() {
_ = os.RemoveAll(folder)
}
}
func main() {
// loads a config, merge clear-text secrets, then save the result file.
var err error
defer func() {
if err != nil {
log.Fatal(err)
}
}()
folder, clean := mustTempDir()
defer clean()
here := mustCwd()
os.Setenv("CONFIG_DIR", filepath.Join(here, "examples"))
// load and merge configuration files
cfg, err := config.LoadWithSecrets("dev", config.WithMute(true))
if err != nil {
err = fmt.Errorf("loading config: %w", err)
return
}
// writes down the merged config
configmap := filepath.Join(folder, "configmap.yaml")
err = cfg.WriteConfigAs(configmap)
if err != nil {
err = fmt.Errorf("writing config: %w", err)
return
}
result, err := os.ReadFile(configmap)
if err != nil {
err = fmt.Errorf("reading result: %w", err)
return
}
_, _ = os.Stdout.Write(result)
}
Output: app: threads: 10 url: https://example.dev.co log: level: info metrics: enabled: true exporter: prometheus secrets: token: xyz trace: enabled: true exporter: jaeger
Types ¶
type CombinedLoader ¶
type CombinedLoader struct {
// contains filtered or unexported fields
}
CombinedLoader loads and merge configuration files using a collection of loaders.
func NewCombinedLoader ¶
func NewCombinedLoader(loaders ...Loadable) *CombinedLoader
NewCombinedLoader builds a compound loader considering several Loadable in the provided order.
This is used for example to load files with different base names.
func (*CombinedLoader) LoadForEnv ¶
func (c *CombinedLoader) LoadForEnv(env string) (*viper.Viper, error)
type Loadable ¶
Loadable knows how to load a configuration for an environment.
func DefaultLoader ¶
DefaultLoader provides a config loader with all defaults.
- The base path from where to search for configuration files is provided by the environment variable "CONFIG_DIR"
- Considered root config files are of the form "config.{json|yaml|yml}"
- Environment-specific config files are found in the "config.d" folder.
- Considered environment-specific files are of the form "config[.*].{json|yaml|yml}".
- Environment-specific files are located in the {base path}/config.d/{env} folder.
- Files are watched for changes.
- Config loading logging goes to os.Stdout.
Options may be provided to override some of these defaults.
func LoaderForTest ¶
LoaderForTest provides a default config loader intended to be used by test programs.
It mutes internal logging to limit unwanted test verbosity. Config watch is disabled: this is convenient when loading many configuration files in different test go routines.
The LoaderForTest searches for configuration files in the tree containing the current working directory, meaning that any test program in your source tree may load a test config.
func LoaderWithSecrets ¶
LoaderWithSecrets combines configuration files and secrets.
func SecretsLoader ¶
SecretsLoader works like the default loader, but includes config files of the form "secrets.{env}.{json|yaml|yml}[.dec]".
This allows to work with files containing secrets, conventionally named "secrets[.*].[json|yaml|yml]".
Secret files may possibly be temporarily decrypted with a ".dec" extension: this allows to work on a local testing environment with secret configurations managed by sops.
type Loader ¶
type Loader struct {
// contains filtered or unexported fields
}
Loader loads and merge configuration files.
type Option ¶
type Option func(*options)
Option to configure the config loader.
func WithBasePath ¶
WithBasePath defines the folder of the root configuration file.
Defaults to "." (this default may be altered by changing DefaultBasePath).
func WithBasePathFromEnvVar ¶
WithBasePathFromEnv specifies the environment variable to be used to define the search path for configs (default: none).
func WithEnvDir ¶
WithEnvDir defines the path to environment-specific configs, relative to the base path.
Defaults to "config.d" (this default may be altered by changing DefaultEnvPath).
func WithMute ¶
WithMute discards any logging occurring inside the config loader.
The default is false.
This option is equivalent to WithOutput({io.Discard|os.Stdout}).
func WithOutput ¶
WithOutput specifies a io.Writer to output logs during config search.
The default is os.Stdout.
func WithRadix ¶
WithRadix defines the radix (base name) of a config file.
Default to "config", meaning that the recognized files are: "config.yaml", "config.yml", "config.json" for root files, or forms such as "config.xxx.{json|yaml|yml} for env-specific files.
The default may be altered by changing DefaultConfigRadix.
func WithSearchParentDir ¶
WithSearchParentDir enables the search for config files in the folder tree that contains the current working directory.
This is primarily designed to support test programs loading config files from a source repository.
func WithSuffix ¶
WithSuffix defines an optional suffix extension to be recognized.
The loader will primarily search for files with the suffix extension, then fall back to no suffix.
Example:
WithSuffix("dec") will look first for "secrets.yaml.dec",
then if none is found, will search for "secrets.yaml".
The default is empty.