mirror of
https://github.com/spf13/viper
synced 2024-12-22 11:37:02 +00:00
Adding support for ENV variables
This commit is contained in:
parent
d56c59c66a
commit
181a3b5f3b
2 changed files with 65 additions and 3 deletions
51
viper.go
51
viper.go
|
@ -3,6 +3,17 @@
|
||||||
// Use of this source code is governed by an MIT-style
|
// Use of this source code is governed by an MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Viper is a application configuration system.
|
||||||
|
// It believes that applications can be configured a variety of ways
|
||||||
|
// via flags, ENVIRONMENT variables, configuration files.
|
||||||
|
|
||||||
|
// Each item takes precedence over the item below it:
|
||||||
|
|
||||||
|
// flag
|
||||||
|
// env
|
||||||
|
// config
|
||||||
|
// default
|
||||||
|
|
||||||
package viper
|
package viper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -40,6 +51,7 @@ var configType string
|
||||||
|
|
||||||
var config map[string]interface{} = make(map[string]interface{})
|
var config map[string]interface{} = make(map[string]interface{})
|
||||||
var override map[string]interface{} = make(map[string]interface{})
|
var override map[string]interface{} = make(map[string]interface{})
|
||||||
|
var env map[string]string = make(map[string]string)
|
||||||
var defaults map[string]interface{} = make(map[string]interface{})
|
var defaults map[string]interface{} = make(map[string]interface{})
|
||||||
var pflags map[string]*pflag.Flag = make(map[string]*pflag.Flag)
|
var pflags map[string]*pflag.Flag = make(map[string]*pflag.Flag)
|
||||||
var aliases map[string]string = make(map[string]string)
|
var aliases map[string]string = make(map[string]string)
|
||||||
|
@ -114,7 +126,7 @@ func Marshal(rawVal interface{}) error {
|
||||||
}
|
}
|
||||||
err = mapstructure.Decode(config, rawVal)
|
err = mapstructure.Decode(config, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mapstructure.Decode(override, rawVal)
|
err = mapstructure.Decode(override, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -148,6 +160,28 @@ func BindPFlag(key string, flag *pflag.Flag) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Binds a viper key to a ENV variable
|
||||||
|
// ENV variables are case sensitive
|
||||||
|
// If only a key is provided, it will use the env key matching the key, uppercased.
|
||||||
|
func BindEnv(input ...string) (err error) {
|
||||||
|
var key, envkey string
|
||||||
|
if len(input) == 0 {
|
||||||
|
return fmt.Errorf("BindEnv missing key to bind to")
|
||||||
|
}
|
||||||
|
|
||||||
|
key = input[0]
|
||||||
|
|
||||||
|
if len(input) == 1 {
|
||||||
|
envkey = strings.ToUpper(key)
|
||||||
|
} else {
|
||||||
|
envkey = input[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
env[key] = envkey
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func find(key string) interface{} {
|
func find(key string) interface{} {
|
||||||
var val interface{}
|
var val interface{}
|
||||||
var exists bool
|
var exists bool
|
||||||
|
@ -170,6 +204,17 @@ func find(key string) interface{} {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envkey, exists := env[key]
|
||||||
|
if exists {
|
||||||
|
jww.TRACE.Println(key, "registered as env var", envkey)
|
||||||
|
if val = os.Getenv(envkey); val != "" {
|
||||||
|
jww.TRACE.Println(envkey, "found in environement with val:", val)
|
||||||
|
return val
|
||||||
|
} else {
|
||||||
|
jww.TRACE.Println(envkey, "env value unset:")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val, exists = config[key]
|
val, exists = config[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "found in config:", val)
|
jww.TRACE.Println(key, "found in config:", val)
|
||||||
|
@ -348,7 +393,6 @@ func insensativiseMap(m map[string]interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Name for the config file.
|
// Name for the config file.
|
||||||
// Does not include extension.
|
// Does not include extension.
|
||||||
func SetConfigName(in string) {
|
func SetConfigName(in string) {
|
||||||
|
@ -510,6 +554,8 @@ func absPathify(inPath string) string {
|
||||||
func Debug() {
|
func Debug() {
|
||||||
fmt.Println("Config:")
|
fmt.Println("Config:")
|
||||||
pretty.Println(config)
|
pretty.Println(config)
|
||||||
|
fmt.Println("Env:")
|
||||||
|
pretty.Println(env)
|
||||||
fmt.Println("Defaults:")
|
fmt.Println("Defaults:")
|
||||||
pretty.Println(defaults)
|
pretty.Println(defaults)
|
||||||
fmt.Println("Override:")
|
fmt.Println("Override:")
|
||||||
|
@ -529,6 +575,7 @@ func Reset() {
|
||||||
|
|
||||||
config = make(map[string]interface{})
|
config = make(map[string]interface{})
|
||||||
override = make(map[string]interface{})
|
override = make(map[string]interface{})
|
||||||
|
env = make(map[string]string)
|
||||||
defaults = make(map[string]interface{})
|
defaults = make(map[string]interface{})
|
||||||
aliases = make(map[string]string)
|
aliases = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package viper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -123,6 +124,20 @@ func TestTOML(t *testing.T) {
|
||||||
assert.Equal(t, "TOML Example", Get("title"))
|
assert.Equal(t, "TOML Example", Get("title"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnv(t *testing.T) {
|
||||||
|
SetConfigType("json")
|
||||||
|
r := bytes.NewReader(jsonExample)
|
||||||
|
MarshallReader(r)
|
||||||
|
BindEnv("id")
|
||||||
|
BindEnv("f", "FOOD")
|
||||||
|
|
||||||
|
os.Setenv("ID", "13")
|
||||||
|
os.Setenv("FOOD", "apple")
|
||||||
|
|
||||||
|
assert.Equal(t, "13", Get("id"))
|
||||||
|
assert.Equal(t, "apple", Get("f"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestCaseInSensitive(t *testing.T) {
|
func TestCaseInSensitive(t *testing.T) {
|
||||||
assert.Equal(t, true, Get("hacker"))
|
assert.Equal(t, true, Get("hacker"))
|
||||||
Set("Title", "Checking Case")
|
Set("Title", "Checking Case")
|
||||||
|
@ -164,4 +179,4 @@ func TestMarshal(t *testing.T) {
|
||||||
t.Fatalf("unable to decode into struct, %v", err)
|
t.Fatalf("unable to decode into struct, %v", err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, &C, &config{Name: "Steve", Port: 1234})
|
assert.Equal(t, &C, &config{Name: "Steve", Port: 1234})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue