mirror of
https://github.com/spf13/viper
synced 2024-11-16 18:07:02 +00:00
Merge branch 'master' into feature/unmarshal-with-meta
This commit is contained in:
commit
9cf6bd7828
6 changed files with 73 additions and 56 deletions
|
@ -17,6 +17,7 @@ matrix:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- go install ./...
|
- go install ./...
|
||||||
|
- diff -u <(echo -n) <(gofmt -d .)
|
||||||
- go test -v ./...
|
- go test -v ./...
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
|
|
40
README.md
40
README.md
|
@ -6,18 +6,19 @@ Many Go projects are built using Viper including:
|
||||||
|
|
||||||
* [Hugo](http://gohugo.io)
|
* [Hugo](http://gohugo.io)
|
||||||
* [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
|
* [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
|
||||||
* [Imgur's Incus](https://github.com/Imgur/incus)
|
* [Imgur’s Incus](https://github.com/Imgur/incus)
|
||||||
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
|
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
|
||||||
* [Docker Notary](https://github.com/docker/Notary)
|
* [Docker Notary](https://github.com/docker/Notary)
|
||||||
* [BloomApi](https://www.bloomapi.com/)
|
* [BloomApi](https://www.bloomapi.com/)
|
||||||
* [doctl](https://github.com/digitalocean/doctl)
|
* [doctl](https://github.com/digitalocean/doctl)
|
||||||
|
* [Clairctl](https://github.com/jgsqware/clairctl)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
|
[![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
|
||||||
|
|
||||||
|
|
||||||
## What is Viper?
|
## What is Viper?
|
||||||
|
|
||||||
Viper is a complete configuration solution for go applications including 12 factor apps. It is designed
|
Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed
|
||||||
to work within an application, and can handle all types of configuration needs
|
to work within an application, and can handle all types of configuration needs
|
||||||
and formats. It supports:
|
and formats. It supports:
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ Viper configuration keys are case insensitive.
|
||||||
### Establishing Defaults
|
### Establishing Defaults
|
||||||
|
|
||||||
A good configuration system will support default values. A default value is not
|
A good configuration system will support default values. A default value is not
|
||||||
required for a key, but it's useful in the event that a key hasn’t been set via
|
required for a key, but it’s useful in the event that a key hasn’t been set via
|
||||||
config file, environment variable, remote configuration or flag.
|
config file, environment variable, remote configuration or flag.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
@ -236,7 +237,7 @@ Like `BindEnv`, the value is not set when the binding method is called, but when
|
||||||
it is accessed. This means you can bind as early as you want, even in an
|
it is accessed. This means you can bind as early as you want, even in an
|
||||||
`init()` function.
|
`init()` function.
|
||||||
|
|
||||||
The `BindPFlag()` method provides this functionality.
|
For individual flags, the `BindPFlag()` method provides this functionality.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -245,6 +246,19 @@ serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
|
||||||
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also bind an existing set of pflags (pflag.FlagSet):
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
pflag.Int("flagname", 1234, "help message for flagname")
|
||||||
|
|
||||||
|
pflag.Parse()
|
||||||
|
viper.BindPFlags(pflag.CommandLine)
|
||||||
|
|
||||||
|
i := viper.GetInt("flagname") // retrieve values from viper instead of pflag
|
||||||
|
```
|
||||||
|
|
||||||
The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude
|
The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude
|
||||||
the use of other packages that use the [flag](https://golang.org/pkg/flag/)
|
the use of other packages that use the [flag](https://golang.org/pkg/flag/)
|
||||||
package from the standard library. The pflag package can handle the flags
|
package from the standard library. The pflag package can handle the flags
|
||||||
|
@ -263,15 +277,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
// using standard library "flag" package
|
||||||
|
flag.Int("flagname", 1234, "help message for flagname")
|
||||||
|
|
||||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||||
pflag.Parse()
|
pflag.Parse()
|
||||||
|
viper.BindPFlags(pflag.CommandLine)
|
||||||
|
|
||||||
|
i := viper.GetInt("flagname") // retrieve value from viper
|
||||||
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Flag interfaces
|
#### Flag interfaces
|
||||||
|
|
||||||
Viper provides two Go interfaces to bind other flag systems if you don't use `Pflags`.
|
Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`.
|
||||||
|
|
||||||
`FlagValue` represents a single flag. This is a very simple example on how to implement this interface:
|
`FlagValue` represents a single flag. This is a very simple example on how to implement this interface:
|
||||||
|
|
||||||
|
@ -401,7 +423,7 @@ go func(){
|
||||||
|
|
||||||
## Getting Values From Viper
|
## Getting Values From Viper
|
||||||
|
|
||||||
In Viper, there are a few ways to get a value depending on the value's type.
|
In Viper, there are a few ways to get a value depending on the value’s type.
|
||||||
The following functions and methods exist:
|
The following functions and methods exist:
|
||||||
|
|
||||||
* `Get(key string) : interface{}`
|
* `Get(key string) : interface{}`
|
||||||
|
@ -531,7 +553,7 @@ func NewCache(cfg *Viper) *Cache {...}
|
||||||
```
|
```
|
||||||
|
|
||||||
which creates a cache based on config information formatted as `subv`.
|
which creates a cache based on config information formatted as `subv`.
|
||||||
Now it's easy to create these 2 caches separately as:
|
Now it’s easy to create these 2 caches separately as:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
cfg1 := viper.Sub("app.cache1")
|
cfg1 := viper.Sub("app.cache1")
|
||||||
|
@ -575,13 +597,13 @@ initialization needed to begin using Viper. Since most applications will want
|
||||||
to use a single central repository for their configuration, the viper package
|
to use a single central repository for their configuration, the viper package
|
||||||
provides this. It is similar to a singleton.
|
provides this. It is similar to a singleton.
|
||||||
|
|
||||||
In all of the examples above, they demonstrate using viper in it's singleton
|
In all of the examples above, they demonstrate using viper in its singleton
|
||||||
style approach.
|
style approach.
|
||||||
|
|
||||||
### Working with multiple vipers
|
### Working with multiple vipers
|
||||||
|
|
||||||
You can also create many different vipers for use in your application. Each will
|
You can also create many different vipers for use in your application. Each will
|
||||||
have it’s own unique set of configurations and values. Each can read from a
|
have its own unique set of configurations and values. Each can read from a
|
||||||
different config file, key value store, etc. All of the functions that viper
|
different config file, key value store, etc. All of the functions that viper
|
||||||
package supports are mirrored as methods on a viper.
|
package supports are mirrored as methods on a viper.
|
||||||
|
|
||||||
|
|
|
@ -62,5 +62,4 @@ func TestBindFlagValue(t *testing.T) {
|
||||||
flag.Changed = true //hack for pflag usage
|
flag.Changed = true //hack for pflag usage
|
||||||
|
|
||||||
assert.Equal(t, "testing_mutate", Get("testvalue"))
|
assert.Equal(t, "testing_mutate", Get("testvalue"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ func (rc remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error)
|
||||||
|
|
||||||
return bytes.NewReader(resp), nil
|
return bytes.NewReader(resp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
|
func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
|
||||||
cm, err := getConfigManager(rp)
|
cm, err := getConfigManager(rp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -68,12 +69,9 @@ func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *vi
|
||||||
}(cryptoResponseCh, viperResponsCh, quitwc, quit)
|
}(cryptoResponseCh, viperResponsCh, quitwc, quit)
|
||||||
|
|
||||||
return viperResponsCh, quitwc
|
return viperResponsCh, quitwc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
|
func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
|
||||||
|
|
||||||
var cm crypt.ConfigManager
|
var cm crypt.ConfigManager
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -99,7 +97,6 @@ func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return cm, nil
|
return cm, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCopyAndInsensitiviseMap(t *testing.T) {
|
func TestCopyAndInsensitiviseMap(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
given = map[string]interface{}{
|
given = map[string]interface{}{
|
||||||
"Foo": 32,
|
"Foo": 32,
|
||||||
|
|
27
viper.go
27
viper.go
|
@ -69,8 +69,7 @@ func (str UnsupportedConfigError) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsupportedRemoteProviderError denotes encountering an unsupported remote
|
// UnsupportedRemoteProviderError denotes encountering an unsupported remote
|
||||||
// provider. Currently only etcd and Consul are
|
// provider. Currently only etcd and Consul are supported.
|
||||||
// supported.
|
|
||||||
type UnsupportedRemoteProviderError string
|
type UnsupportedRemoteProviderError string
|
||||||
|
|
||||||
// Error returns the formatted remote provider error.
|
// Error returns the formatted remote provider error.
|
||||||
|
@ -283,8 +282,8 @@ func (v *Viper) WatchConfig() {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfigFile explicitly defines the path, name and extension of the config file
|
// SetConfigFile explicitly defines the path, name and extension of the config file.
|
||||||
// Viper will use this and not check any of the config paths
|
// Viper will use this and not check any of the config paths.
|
||||||
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
||||||
func (v *Viper) SetConfigFile(in string) {
|
func (v *Viper) SetConfigFile(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
|
@ -293,8 +292,8 @@ func (v *Viper) SetConfigFile(in string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
|
// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
|
||||||
// E.g. if your prefix is "spf", the env registry
|
// E.g. if your prefix is "spf", the env registry will look for env
|
||||||
// will look for env. variables that start with "SPF_"
|
// variables that start with "SPF_".
|
||||||
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
|
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
|
||||||
func (v *Viper) SetEnvPrefix(in string) {
|
func (v *Viper) SetEnvPrefix(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
|
@ -312,11 +311,11 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
|
||||||
|
|
||||||
// TODO: should getEnv logic be moved into find(). Can generalize the use of
|
// TODO: should getEnv logic be moved into find(). Can generalize the use of
|
||||||
// rewriting keys many things, Ex: Get('someKey') -> some_key
|
// rewriting keys many things, Ex: Get('someKey') -> some_key
|
||||||
// (cammel case to snake case for JSON keys perhaps)
|
// (camel case to snake case for JSON keys perhaps)
|
||||||
|
|
||||||
// getEnv is a wrapper around os.Getenv which replaces characters in the original
|
// getEnv is a wrapper around os.Getenv which replaces characters in the original
|
||||||
// key. This allows env vars which have different keys then the config object
|
// key. This allows env vars which have different keys than the config object
|
||||||
// keys
|
// keys.
|
||||||
func (v *Viper) getEnv(key string) string {
|
func (v *Viper) getEnv(key string) string {
|
||||||
if v.envKeyReplacer != nil {
|
if v.envKeyReplacer != nil {
|
||||||
key = v.envKeyReplacer.Replace(key)
|
key = v.envKeyReplacer.Replace(key)
|
||||||
|
@ -324,7 +323,7 @@ func (v *Viper) getEnv(key string) string {
|
||||||
return os.Getenv(key)
|
return os.Getenv(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigFileUsed returns the file used to populate the config registry
|
// ConfigFileUsed returns the file used to populate the config registry.
|
||||||
func ConfigFileUsed() string { return v.ConfigFileUsed() }
|
func ConfigFileUsed() string { return v.ConfigFileUsed() }
|
||||||
func (v *Viper) ConfigFileUsed() string { return v.configFile }
|
func (v *Viper) ConfigFileUsed() string { return v.configFile }
|
||||||
|
|
||||||
|
@ -597,15 +596,14 @@ func (v *Viper) Get(key string) interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valType := val
|
|
||||||
if v.typeByDefValue {
|
if v.typeByDefValue {
|
||||||
// TODO(bep) this branch isn't covered by a single test.
|
// TODO(bep) this branch isn't covered by a single test.
|
||||||
|
valType := val
|
||||||
path := strings.Split(lcaseKey, v.keyDelim)
|
path := strings.Split(lcaseKey, v.keyDelim)
|
||||||
defVal := v.searchMap(v.defaults, path)
|
defVal := v.searchMap(v.defaults, path)
|
||||||
if defVal != nil {
|
if defVal != nil {
|
||||||
valType = defVal
|
valType = defVal
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch valType.(type) {
|
switch valType.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
|
@ -623,6 +621,8 @@ func (v *Viper) Get(key string) interface{} {
|
||||||
case []string:
|
case []string:
|
||||||
return cast.ToStringSlice(val)
|
return cast.ToStringSlice(val)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,7 +1329,7 @@ func (v *Viper) WatchRemoteConfigOnChannel() error {
|
||||||
return v.watchKeyValueConfigOnChannel()
|
return v.watchKeyValueConfigOnChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshall a Reader into a map.
|
// Unmarshal a Reader into a map.
|
||||||
// Should probably be an unexported function.
|
// Should probably be an unexported function.
|
||||||
func unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
func unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
||||||
return v.unmarshalReader(in, c)
|
return v.unmarshalReader(in, c)
|
||||||
|
@ -1588,7 +1588,6 @@ func (v *Viper) searchInPath(in string) (filename string) {
|
||||||
// Search all configPaths for any config file.
|
// Search all configPaths for any config file.
|
||||||
// Returns the first path that exists (and is a config file).
|
// Returns the first path that exists (and is a config file).
|
||||||
func (v *Viper) findConfigFile() (string, error) {
|
func (v *Viper) findConfigFile() (string, error) {
|
||||||
|
|
||||||
jww.INFO.Println("Searching for config in ", v.configPaths)
|
jww.INFO.Println("Searching for config in ", v.configPaths)
|
||||||
|
|
||||||
for _, cp := range v.configPaths {
|
for _, cp := range v.configPaths {
|
||||||
|
|
Loading…
Reference in a new issue