Documentation ¶
Overview ¶
Package config is an encoding-agnostic configuration abstraction. It supports merging multiple configuration files, expanding environment variables, and a variety of other small niceties. It currently supports YAML, but may be extended in the future to support more restrictive encodings like JSON or TOML.
Merging Configuration ¶
It's often convenient to separate configuration into multiple files; for example, an application may want to first load some universally-applicable configuration and then merge in some environment-specific overrides. This package supports this pattern in a variety of ways, all of which use the same merge logic.
Simple types (numbers, strings, dates, and anything else YAML would consider a scalar) are merged by replacing lower-priority values with higher-priority overrides. For example, consider this merge of base.yaml and override.yaml:
# base.yaml some_key: foo # override.yaml some_key: bar # merged result some_key: bar
Slices, arrays, and anything else YAML would consider a sequence are also replaced. Again merging base.yaml and override.yaml:
# base.yaml some_key: [foo, bar] # override.yaml some_key: [baz, quux] # merged output some_key: [baz, quux]
Maps are recursively deep-merged, handling scalars and sequences as described above. Consider a merge between a more complex set of YAML files:
# base.yaml some_key: foo: bar foos: [1, 2] # override.yaml some_key: baz: quux foos: [3, 4] # merged output some_key: foo: bar # from base.yaml baz: quux # from override.yaml foos: [3, 4] # from override.yaml
In all cases, explicit nils (represented in YAML with a tilde) override any pre-existing configuration. For example,
# base.yaml foo: {bar: baz} # override.yaml foo: ~ # merged output foo: ~
Strict Unmarshalling ¶
By default, the NewYAML constructor enables gopkg.in/yaml.v2's strict unmarshalling mode. This prevents a variety of common programmer errors, especially when deep-merging loosely-typed YAML files. In strict mode, providers throw errors if keys are duplicated in the same configuration source, all keys aren't used when populating a struct, or a merge encounters incompatible data types. This behavior can be disabled with the Permissive option.
To maintain backward compatibility, all other constructors default to permissive unmarshalling.
Quote Strings ¶
YAML allows strings to appear quoted or unquoted, so these two lines are identical:
foo: bar "foo": "bar"
However, the YAML specification special-cases some unquoted strings. Most obviously, true and false are interpreted as Booleans (unless quoted). Less obviously, yes, no, on, off, and many variants of these words are also treated as Booleans (see http://yaml.org/type/bool.html for the complete specification).
Correctly deep-merging sources requires this package to unmarshal and then remarshal all YAML, which implicitly converts these special-cased unquoted strings to their canonical representation. For example,
foo: yes # before merge foo: true # after merge
Quoting special-cased strings prevents this surprising behavior.
Deprecated APIs ¶
Unfortunately, this package was released with a variety of bugs and an overly large API. The internals of the configuration provider have been completely reworked and all known bugs have been addressed, but many duplicative exported functions were retained to preserve backward compatibility. New users should rely on the NewYAML constructor. In particular, avoid NewValue - it's unnecessary, complex, and may panic.
Deprecated functions are documented in the format expected by the staticcheck linter, available at https://staticcheck.io/.
Example ¶
package main import ( "fmt" "strings" "go.uber.org/config" ) func main() { // A struct to represent the configuration of a self-contained unit of your // application. type cfg struct { Parameter string } // Two sources of YAML configuration to merge. We could also use // config.Static to supply some configuration as a Go struct. base := strings.NewReader("module: {parameter: foo}") override := strings.NewReader("module: {parameter: bar}") // Merge the two sources into a Provider. Later sources are higher-priority. // See the top-level package documentation for details on the merging logic. provider, err := config.NewYAML(config.Source(base), config.Source(override)) if err != nil { panic(err) } var c cfg if err := provider.Get("module").Populate(&c); err != nil { panic(err) } fmt.Printf("%+v\n", c) }
Output: {Parameter:bar}
Index ¶
- Constants
- type LookupFunc
- type NopProvider
- type Provider
- func NewProviderGroup(name string, providers ...Provider) (Provider, error)
- func NewScopedProvider(prefix string, provider Provider) Provider
- func NewStaticProvider(data interface{}) (Provider, error)deprecated
- func NewStaticProviderWithExpand(data interface{}, lookup LookupFunc) (Provider, error)deprecated
- func NewYAMLProviderFromBytes(yamls ...[]byte) (Provider, error)deprecated
- func NewYAMLProviderFromFiles(filenames ...string) (Provider, error)deprecated
- func NewYAMLProviderFromReader(readers ...io.Reader) (Provider, error)deprecated
- func NewYAMLProviderFromReaderWithExpand(lookup LookupFunc, readers ...io.Reader) (Provider, error)deprecated
- func NewYAMLProviderWithExpand(lookup LookupFunc, filenames ...string) (Provider, error)deprecated
- type Value
- func (v Value) Get(path string) Value
- func (v Value) HasValue() booldeprecated
- func (v Value) Populate(target interface{}) error
- func (v Value) Source() string
- func (v Value) String() string
- func (v Value) Value() interface{}deprecated
- func (v Value) WithDefault(d interface{}) (Value, error)deprecated
- type YAML
- type YAMLOption
Examples ¶
Constants ¶
const Root = ""
Root is a virtual key that accesses the entire configuration. Using it as the key when calling Provider.Get or Value.Get returns the whole configuration.
const Version = "1.3.1"
Version is the current semantic version.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type LookupFunc ¶ added in v1.2.0
A LookupFunc behaves like os.LookupEnv: it uses the supplied string as a key into some key-value store and returns the value and whether the key was present.
type NopProvider ¶
type NopProvider struct{}
NopProvider is a no-op provider.
func (NopProvider) Get ¶
func (n NopProvider) Get(_ string) Value
Get returns a value with no configuration available.
type Provider ¶
type Provider interface { Name() string // name of the configuration store Get(key string) Value // retrieves a portion of the configuration, see Value for details }
Provider is an abstraction over a configuration store, such as a collection of merged YAML, JSON, or TOML files.
func NewProviderGroup ¶
NewProviderGroup composes multiple providers, with later providers overriding earlier ones. The merge logic is described in the package-level documentation. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Prefer using NewYAML instead of this where possible. NewYAML gives you strict unmarshalling by default and allows use of other options at the same time.
func NewScopedProvider ¶
NewScopedProvider wraps a provider and adds a prefix to all Get calls.
func NewStaticProvider
deprecated
NewStaticProvider serializes a Go data structure to YAML, then loads it into a provider. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the Static option directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewStaticProviderWithExpand
deprecated
func NewStaticProviderWithExpand(data interface{}, lookup LookupFunc) (Provider, error)
NewStaticProviderWithExpand serializes a Go data structure to YAML, expands any environment variable references using the supplied lookup function, then loads the result into a provider. See the Expand option for a description of the environment variable replacement syntax. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the Static and Expand options directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewYAMLProviderFromBytes
deprecated
NewYAMLProviderFromBytes merges multiple YAML-formatted byte slices into a single provider. Later configuration blobs override earlier ones using the merge logic described in the package-level documentation. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML with the Source and Expand options directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewYAMLProviderFromFiles
deprecated
NewYAMLProviderFromFiles opens and merges multiple YAML files into a single provider. Later files override earlier files using the merge logic described in the package-level documentation. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the File option directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewYAMLProviderFromReader
deprecated
NewYAMLProviderFromReader merges multiple YAML-formatted io.Readers into a single provider. Later readers override earlier ones using the merge logic described in the package-level documentation. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the Source option directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewYAMLProviderFromReaderWithExpand
deprecated
func NewYAMLProviderFromReaderWithExpand(lookup LookupFunc, readers ...io.Reader) (Provider, error)
NewYAMLProviderFromReaderWithExpand merges multiple YAML-formatted io.Readers, expands any environment variable references using the supplied lookup function, and then loads the result into a provider. Later readers override earlier readers using the merge logic described in the package-level documentation. See the Expand option for a description of the environment variable replacement syntax. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the Source and Expand options directly. This enables strict unmarshalling by default and allows use of other options at the same time.
func NewYAMLProviderWithExpand
deprecated
func NewYAMLProviderWithExpand(lookup LookupFunc, filenames ...string) (Provider, error)
NewYAMLProviderWithExpand opens and merges multiple YAML-formatted files, expands any environment variable references using the supplied lookup function, and then loads the result into a provider. Later readers override earlier readers using the merge logic described in the package-level documentation. See the Expand option for a description of the environment variable replacement syntax. To preserve backward compatibility, the resulting provider disables strict unmarshalling.
Deprecated: use NewYAML and the File and Expand options directly. This enables strict unmarshalling by default and allows use of other options at the same time.
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
A Value is a subset of a provider's configuration.
func NewValue
deprecated
NewValue is a highly error-prone constructor preserved only for backward compatibility. If value and found don't match the contents of the provider at the supplied key, it panics.
Deprecated: this internal constructor was mistakenly exported in the initial release of this package, but its behavior was often very surprising. To guarantee sane behavior without changing the function signature, input validation and panics were added in version 1.2. In all cases, it's both safer and less verbose to use Provider.Get directly.
func (Value) Get ¶
Get dives further into the configuration, pulling out more deeply nested values. The supplied path is split on periods, and each segment is treated as a nested map key. For example, if the current value holds the YAML configuration
foo: bar: baz: quux
then a call to Get("foo.bar") will hold the YAML mapping
baz: quux
func (Value) HasValue
deprecated
HasValue checks whether any configuration is available at this key.
It doesn't distinguish between configuration supplied during provider construction and configuration applied by WithDefault. If the value has explicitly been set to nil, HasValue is true.
Deprecated: this function has little value and is often confusing. Rather than checking whether a value has any configuration available, Populate a struct with appropriate defaults and zero values.
func (Value) Populate ¶
Populate unmarshals the value into the target struct, much like json.Unmarshal or yaml.Unmarshal. When populating a struct with some fields already set, data is deep-merged as described in the package-level documentation.
func (Value) WithDefault
deprecated
WithDefault supplies a default configuration for the value. The default is serialized to YAML, and then the existing configuration sources are deep-merged into it using the merge logic described in the package-level documentation. Note that applying defaults requires re-expanding environment variables, which may have unexpected results if the environment changes after provider construction.
Deprecated: the deep-merging behavior of WithDefault is complex, especially when applied multiple times. Instead, create a Go struct, set any defaults directly on the struct, then call Populate.
Example ¶
package main import ( "fmt" "go.uber.org/config" ) func main() { provider, err := config.NewYAML(config.Static(map[string]string{ "key": "value", })) if err != nil { panic(err) } // Using config.Root as a key retrieves the whole configuration. base := provider.Get(config.Root) // Applying a default is equivalent to serializing it to YAML, writing the // serialized bytes to default.yaml, and then merging the existing // configuration into default.yaml. Maps are deep-merged! // // Since we're setting the default for a key that's not already in the // configuration, new_key will now be set to new_value. From now on, it's // impossible to tell whether the value of new_key came from the original // provider or a call to WithDefault. defaulted, err := base.WithDefault(map[string]string{ "new_key": "new_value", }) if err != nil { panic(err) } fmt.Println(defaulted) // If we try to use WithDefault again to set different defaults for the two // existing keys, nothing happens - since both keys already have scalar // values, those values overwrite the new defaults in the merge. See the // package-level documentation for a more detailed discussion of the merge // logic. again, err := defaulted.WithDefault(map[string]string{ "key": "ignored", "new_key": "ignored", }) if err != nil { panic(err) } fmt.Println(again) }
Output:
type YAML ¶ added in v1.2.0
type YAML struct {
// contains filtered or unexported fields
}
YAML is a provider that reads from one or more YAML sources. Many aspects of the resulting provider's behavior can be altered by passing functional options.
By default, the YAML provider attempts to proactively catch common mistakes by enabling gopkg.in/yaml.v2's strict mode. See the package-level documentation on strict unmarshalling for details.
When populating Go structs, values produced by the YAML provider correctly handle all struct tags supported by gopkg.in/yaml.v2. See https://godoc.org/gopkg.in/yaml.v2#Marshal for details.
func NewYAML ¶ added in v1.2.0
func NewYAML(options ...YAMLOption) (*YAML, error)
NewYAML constructs a YAML provider. See the various YAMLOptions for available tweaks to the default behavior.
func (*YAML) Get ¶ added in v1.2.0
Get retrieves a value from the configuration. The supplied key is treated as a period-separated path, with each path segment used as a map key. For example, if the provider contains the YAML
foo: bar: baz: hello
then Get("foo.bar") returns a value holding
baz: hello
To get a value holding the entire configuration, use the Root constant as the key.
type YAMLOption ¶ added in v1.2.0
type YAMLOption interface {
// contains filtered or unexported methods
}
A YAMLOption alters the default configuration of the YAML configuration provider.
func Expand ¶ added in v1.2.0
func Expand(lookup LookupFunc) YAMLOption
Expand enables variable expansion in all non-raw provided sources. The supplied function MUST behave like os.LookupEnv: it looks up a key and returns a value and whether the key was found. Any expansion is deferred until after all sources are merged, so it's not possible to reference different variables in different sources and have the values automatically merged.
Expand allows variable references to take two forms: $VAR or ${VAR:default}. In the first form, variable names MUST adhere to shell naming rules:
...a word consisting solely of underscores, digits, and alphabetics form the portable character set. The first character of a name may not be a digit.
In this form, NewYAML returns an error if any referenced variables aren't found.
In the second form, all characters between the opening curly brace and the first colon are used as the key, and all characters from the colon to the closing curly brace are used as the default value. Keys need not adhere to the shell naming rules above. If a variable isn't found, the default value is used.
$$ is expanded to a literal $.
func File ¶ added in v1.2.0
func File(name string) YAMLOption
File opens a file, uses it as a source of YAML configuration, and closes it once provider construction is complete. Priority, merge, and expansion logic are identical to Source.
func Name ¶ added in v1.2.0
func Name(name string) YAMLOption
Name customizes the name of the provider. The default name is "YAML".
func Permissive ¶ added in v1.2.0
func Permissive() YAMLOption
Permissive disables gopkg.in/yaml.v2's strict mode. It's provided for backward compatibility; to avoid a variety of common mistakes, most users should leave YAML providers in the default strict mode.
In permissive mode, duplicate keys in the same source file are allowed. Later values override earlier ones (note that duplicates are NOT merged, unlike all other merges in this package). Calls to Populate that don't use all keys present in the YAML are allowed. Finally, type conflicts are allowed when merging source files, with later values replacing earlier ones.
func RawSource ¶ added in v1.3.0
func RawSource(r io.Reader) YAMLOption
RawSource adds a source of YAML configuration. Later sources override earlier ones using the merge logic described in the package-level documentation.
Raw sources are not subject to variable expansion. To provide a source with variable expansion enabled, use the Source option.
func Source ¶ added in v1.2.0
func Source(r io.Reader) YAMLOption
Source adds a source of YAML configuration. Later sources override earlier ones using the merge logic described in the package-level documentation.
Sources are subject to variable expansion (via the Expand option). To provide a source that remains unexpanded, use the RawSource option.
func Static ¶ added in v1.2.0
func Static(val interface{}) YAMLOption
Static serializes a Go data structure to YAML and uses the result as a source. If serialization fails, provider construction will return an error. Priority, merge, and expansion logic are identical to Source.