Adding support for ENV variables

This commit is contained in:
spf13 2014-09-27 14:03:00 -07:00
parent d56c59c66a
commit 181a3b5f3b
2 changed files with 65 additions and 3 deletions

View File

@ -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)
} }

View File

@ -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})
} }