From d09390e25021583ff7ad98c75f64b14be8bb5a6d Mon Sep 17 00:00:00 2001 From: Nathan Trujillo Date: Wed, 17 Oct 2018 18:35:50 -0700 Subject: [PATCH] Add method `GetStringEnv` which will interpolate values which look like environmental variables and return them; --- go.mod | 2 ++ go.sum | 5 +++++ util.go | 17 +++++++++++++++++ viper.go | 6 ++++++ viper_test.go | 20 ++++++++++++++++++++ 5 files changed, 50 insertions(+) diff --git a/go.mod b/go.mod index 3f4e1c2..ce610b3 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,12 @@ require ( github.com/magiconair/properties v1.8.0 github.com/mitchellh/mapstructure v1.0.0 github.com/pelletier/go-toml v1.2.0 + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/afero v1.1.2 github.com/spf13/cast v1.2.0 github.com/spf13/jwalterweatherman v1.0.0 github.com/spf13/pflag v1.0.2 + github.com/stretchr/testify v1.2.2 golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 // indirect golang.org/x/text v0.3.0 // indirect gopkg.in/yaml.v2 v2.2.1 diff --git a/go.sum b/go.sum index 3e3b874..24cf77e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -9,6 +10,8 @@ github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KH github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= @@ -17,6 +20,8 @@ github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg= golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= diff --git a/util.go b/util.go index 952cad4..6f2d771 100644 --- a/util.go +++ b/util.go @@ -17,6 +17,7 @@ import ( "runtime" "strings" "unicode" + "regexp" "github.com/spf13/afero" "github.com/spf13/cast" @@ -219,3 +220,19 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} } return m } +// We look up a environmental variable if it looks like '${HOME}' +func lookupEnvByValue(s string) string { + match, err := regexp.MatchString("\\${[A-Za-z_-]+}", s) + if (err != nil) { + fmt.Println(match, err) + } + if (match) { + re := regexp.MustCompile("(\\$|{|}|)") + clean := re.ReplaceAllString(s, "") + env := os.Getenv(clean) + if ( env != "" ) { + return env + } + } + return s +} diff --git a/viper.go b/viper.go index a32ab73..92e97d9 100644 --- a/viper.go +++ b/viper.go @@ -715,6 +715,12 @@ func (v *Viper) GetString(key string) string { return cast.ToString(v.Get(key)) } +// GetStringEnv returns the value of the environmental variable associated with the key as a string. +func GetStringEnv(key string) string { return lookupEnvByValue(v.GetString(key)) } +func (v *Viper) GetStringEnv(key string) string { + return lookupEnvByValue(cast.ToString(v.Get(key))) +} + // GetBool returns the value associated with the key as a boolean. func GetBool(key string) bool { return v.GetBool(key) } func (v *Viper) GetBool(key string) bool { diff --git a/viper_test.go b/viper_test.go index c8fa1f4..b55db98 100644 --- a/viper_test.go +++ b/viper_test.go @@ -48,6 +48,11 @@ eyes : brown beard: true `) +var yamlExampleWithEnv = []byte(` +home: '${HOME_STUFF}' +undefined: '${UNDEFINED}' +`) + var yamlExampleWithExtras = []byte(`Existing: true Bogus: true `) @@ -437,6 +442,21 @@ func TestSetEnvKeyReplacer(t *testing.T) { assert.Equal(t, "30s", Get("refresh-interval")) } +func TestGetStringEnv(t *testing.T) { + Reset() + home := "." + os.Setenv("HOME_STUFF", home) + v := New() + v.SetConfigType("yaml") + v.ReadConfig(bytes.NewBuffer(yamlExampleWithEnv)) + value := v.GetStringEnv("home") + // defined env variables are interpolated + assert.Equal(t, ".", value) + // undefined env variables are untouched + undefined_value := v.GetStringEnv("undefined") + assert.Equal(t, "${UNDEFINED}", undefined_value) +} + func TestAllKeys(t *testing.T) { initConfigs()