yacfg

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2024 License: MIT Imports: 13 Imported by: 0

README

yacfg – Yet Another Config Library (for Go)

Go Reference

Package yacfg is yet another config package.

  • Sets configuration values from environment
  • Loads more than one config file and merges them (last write wins)
  • Works with Go's standard flag library
  • Can watch config files for changes and react to config changes
var config = struct {
	Log    yachg.Obs[string] // Observable string
	SubPkg subpkg.Config
}{
	Log: yachg.NewObs("info"),
	SubPkg: subpkg.Config{
		SrvAddr: "localhost:8080",
		Timeout: 5 * time.Second,
	},
}

func init() {
	// Observe config.Log to change log level, when config changes
	cfg.LogLevel.ObsRegister(0, "", change.UpdateFunc(func(_ any, e change.Event) {
		ce := e.(change.Changed[string])
		log.Printf("Reconfigure log-level to %s", ce.NewValue())
		log.SetLogLevel(...)
	}))
}

func main() {
	cfgFiles, _ := yacfg.EnvThenFiles{
		EnvPrefix:     "YACFG_", // E.g. export YACFG_SUBPKG_TIMEOUT=3s
		FilesFlagName: "config", // Use '-config' (--config) on CLI to load files
	}.Configure(&cfg)            // Now, evaluate env and load files
	
	// Now the flags…
	flag.StringVar(&config.SubPkg.SrvAddr, "srv-addr", config.SubPkg.SrvAddr,
		"Set server address")
	flag.DurationVar(&config.SubPkg.Timeout, "srv-timeout", config.SubPkg.Timeout,
		"Set server timeout duration")
	flag.StringVar(&config.Log, "log", config.Log,
		"Set log level")
	flag.Parse()

	go yachg.Reload(&cfg, nil, cfgFiles...) // Start watching config files
	...
}

Documentation

Overview

Package yacfg is yet another config package. Its meant to be modular and supplemental to commandline parsing which is already part of the standard library. The focus of yacfg is to populate configration data structures from environment variables or configuration files.

The example package is an executable that shows how to use it.

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultEnvMapper = EnvMapList{
	EnvMapTag(true),
	EnvMapUpper{EnvMapField{PathSep: "_"}},
}

DefaultEnvMapper first tries to determine the name of an environment variable from the field tag with the key 'env'—stopping when the value is "-". Next it takes the field's path and name joined with "_" as separator and converts the result to upper case.

Functions

func DefaultEnv

func DefaultEnv(cfg any) error

DefaultEnv calls Env with DefaultEnvMapper

Example
type testCfgBase struct {
	Foo string `env:"HOME"`
	Bar int
}
type testCfg struct {
	testCfgBase
	Baz  bool
	Quux testCfgBase
	Home string
	Bar  int `env:"-"`
}

os.Setenv("HOME", "/usr/johndoe")
os.Setenv("BAR", "4")
os.Setenv("QUUX_BAR", "4711")
os.Setenv("BAZ", "true")
var cfg testCfg
fmt.Println(DefaultEnv(&cfg))
fmt.Println(cfg)
Output:

<nil>
{{/usr/johndoe 4} true {/usr/johndoe 4711} /usr/johndoe 0}

func Env

func Env(cfg any, m EnvMapper) error

Env visits all fields of the cfg struct and uses the EvnMapper e to find an environment variable that provides a value for the field. If a value can be obtained from the environment is is set to the field in cfg.

Example
type testCfgBase struct {
	Foo string `env:"HOME"`
	Bar int
}
type testCfg struct {
	testCfgBase
	Baz  bool
	Quux testCfgBase
	Home string
	Bar  int `env:"-"`
}

os.Setenv("HOME", "/usr/johndoe")
os.Setenv("YACFG_HOME", "/usr/johndoe")
os.Setenv("YACFG_BAR", "4")
os.Setenv("QUUX_BAR", "4711")
os.Setenv("FLAG", "true")
var cfg testCfg
fmt.Println(Env(&cfg, EnvMapList{
	EnvMap{"Baz": "FLAG", "Quux/Bar": "QUUX_BAR"},
	EnvMapTag(true),
	EnvMapUpper{EnvMapField{Prefix: "YACFG_"}},
}))
fmt.Println(cfg)
Output:

<nil>
{{/usr/johndoe 4} true {/usr/johndoe 4711} /usr/johndoe 0}

func FileFormat

func FileFormat(ext string, f FileReadFunc)

FileFormat registers a FileReadFunc for the file extension ext. The Go JSON reader from "encoding/json" is preconfigured for the ".json" extension.

func Files

func Files(cfg any, log func(string), names ...string) (files []string, err error)

func FlagFiles added in v0.4.2

func FlagFiles(args []string, flag, dir string) (files []string, err error)
Example
package main

import (
	"fmt"
)

const testFilesDir = "testdata"

func main() {
	c, err := FlagFiles([]string{"-cfg"}, "cfg", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"--cfg"}, "cfg", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"--c"}, "cfg", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"--c"}, "c", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"-c"}, "c", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"-cfg", "cfg.json"}, "cfg", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
	c, err = FlagFiles([]string{"-cfg=cfg.json"}, "cfg", testFilesDir)
	fmt.Printf("'%s' (%v)\n", c, err)
}
Output:

'[]' (missing value for config flag 'cfg')
'[]' (missing value for config flag 'cfg')
'[]' (<nil>)
'[]' (missing value for config flag 'c')
'[]' (missing value for config flag 'c')
'[]' (missing config file for '-cfg=cfg.json')
'[]' (missing config file for '-cfg=cfg.json')

func FlagFilesDoc added in v0.4.2

func FlagFilesDoc(name string) string

func GlobFlagDoc added in v0.2.0

func GlobFlagDoc() string

func MustFlagFiles added in v0.4.2

func MustFlagFiles(args []string, flag, dir string) []string

Types

type EnvMap

type EnvMap map[string]string

EnvMap explicitly maps the complete path of a config field to the name of an environment variable. The complete path is the joined path with the field's name computed by path.Join().

func (EnvMap) VarName

func (m EnvMap) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapField

type EnvMapField struct {
	Prefix  string
	PathSep string
}

EnvMapField computes the name of the environment variable from the config field. The name will start with Prefix and ends with the field name.

If PathSep is not empty the elements of the field's path with appended separator will be put between the prefix and the field name.

func (EnvMapField) VarName

func (em EnvMapField) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapList

type EnvMapList []EnvMapper

EnvMapList successively tries the listed EnvMappers until it finds a non-empty name for an environment variable. If one EnvMapper returns stop==true EnvMapList immediatley returns the result from that mapper.

func (EnvMapList) VarName

func (m EnvMapList) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapTag

type EnvMapTag bool

EnvMapTag inspects the field's tag with the key 'env' for the name of the environment variable. EnvMapTag(true) return stop==true for the tag `env:"-"`. I.e. one can specify a struct field to be not intended for Env configuration. With EnvMapTag(false) that intend can be ignored.

func (EnvMapTag) VarName

func (stop EnvMapTag) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapUpTo

type EnvMapUpTo struct {
	Level int
	Map   EnvMapper
}

func (EnvMapUpTo) VarName

func (em EnvMapUpTo) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapUpper

type EnvMapUpper struct {
	Map EnvMapper
}

EnvMapUpper wraps another EnvMapper and converts its result to upper case.

func (EnvMapUpper) VarName

func (em EnvMapUpper) VarName(f *reflect.StructField, path []string) (string, bool)

VarName implements EnvMapper

type EnvMapper

type EnvMapper interface {
	// VarName computes the name of the environment variable from the
	// current field of the config structure and the path, i.e. the
	// names of all parent structures, of the filed. If no environment
	// variable can be determined name is the empty string.
	//
	// When an EnvMapper is used in an EnvMapList the returned stop
	// value determines if further mappers are queried if name is
	// empty.
	VarName(f *reflect.StructField, path []string) (name string, stop bool)
}

EnvMapper is an interface that defines how the name of the environment variable is determined depending on the configuration field that is to be set.

See also: Env

type EnvThenFiles added in v0.4.2

type EnvThenFiles struct {
	EnvPrefix     string
	FilesFlagName string
	Flags         *flag.FlagSet
	Log           func(string)
}

func (EnvThenFiles) Configure added in v0.4.2

func (cfgr EnvThenFiles) Configure(cfg any) (files []string, err error)

func (EnvThenFiles) ListFlagDoc added in v0.4.2

func (cfgr EnvThenFiles) ListFlagDoc() string

func (EnvThenFiles) MustConfigure added in v0.4.2

func (cfgr EnvThenFiles) MustConfigure(cfg any) (files []string)

type FileReadFunc

type FileReadFunc = func(rd io.Reader, cfg any) error

FileReadFunc reads config data from files of a specific format, e.g. JSON.

type ValueSetter

type ValueSetter interface {
	Set(string) error
}

ValueSetter is an interface that allow to define how a value is parsed from string.

Directories

Path Synopsis
cmd
examples
Package yachg provides observable config values and tools to watch config files for changes while a program is running.
Package yachg provides observable config values and tools to watch config files for changes while a program is running.
Package yaml registers a YAML config file reader for the extensions ".yaml" and ".yml".
Package yaml registers a YAML config file reader for the extensions ".yaml" and ".yml".
Package yasec helps to keep secrets in config files as secret as possible.
Package yasec helps to keep secrets in config files as secret as possible.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL