Compare commits

...
Author SHA1 Message Date
Jean de KlerkandBjørn Erik Pedersen b5bf975e58 Clean up dependencies
This commit was created by manually removing github.com/ugorji/go/codec from
the go.mod (which now does not exist - see https://github.com/ugorji/go/issues/299)
and running `go mod tidy`.

Closes #658
2019-05-24 21:57:43 +02:00
Anthony Fok 2bd2732789 Use GetInt64 for largenum in viper_test.go
to prevent overflow error on 32-bit platforms.

Fixes #704
2019-05-24 11:53:49 -06:00
Anthony Fok 93066f92c6 Fix typo in viper_test.go: lagrenum → largenum 2019-05-24 07:40:12 -06:00
Mitch ConnorsandSteve Francia 7a605a50e6 Uint Support (#681)
* add GetUint/GetUint32/GetUint64

* Add Get(string) support for uint.
2019-04-08 10:06:45 -04:00
KrisandSteve Francia fccfc2c271 Add API for setting file permissions 2019-04-04 14:02:01 +02:00
Bjørn Erik Pedersen 9e56dacc08 Remove superflous insensitiviseMaps in Unmarshal methods
Fixes #482
2019-03-13 10:29:51 +01:00
Mark Sagi-KazarandBjørn Erik Pedersen d104d259b3 Update go.sum with go1.11.4
In Go 1.11.4 a bug was fixed related to checksum calculation.
As a result, some packages might end up with a different checksum
from this version. The solution is upgrading, cleaning the mod cache
and recalculating the go.sum file.

See https://github.com/golang/go/issues/27093
2019-01-27 10:44:59 +01:00
Bjørn Erik Pedersen 6d33b5a963 Make the map in MergeConfigMap case insensitive 2018-12-07 11:03:36 +01:00
Bjørn Erik Pedersen 41cd1c3aa3 Restrict Travis to >= Go 1.11, use Go Modules, and get the test to pass 2018-12-05 17:13:47 +01:00
Bjørn Erik Pedersen 3535c75fa8 Add MergeConfigMap
Fixes #605
2018-12-05 17:13:47 +01:00
Bjørn Erik Pedersen 06c7c0d9b3 Use assert.EqualValues for slice checking 2018-11-19 10:38:40 +01:00
Benoit MassonandBjørn Erik Pedersen ae103d7e59 Moved shared resources out of the loops in TestBindPFlagsStringSlice()
Common code and resources put out of the loops, to improve
efficiency and readability.
2018-11-07 12:08:59 +01:00
Benoit MassonandBjørn Erik Pedersen 69647fb422 Fixed TestBindPFlagsStringSlice()
Replaced Visit() by VisitAll(), so that the Changed attribute of
the updated flag is correctly set.
2018-11-07 12:08:59 +01:00
Benoit MassonandBjørn Erik Pedersen cc7e906d88 Updated TestBindPFlagsStringSlice() to highlight a failure
When pflag marked as changed, the value is not detected
(and lower priority value used)
2018-11-07 12:08:59 +01:00
Márk Sági-KazárandBjørn Erik Pedersen b7a3b95476 Lookup environment variables instead of checking if the value is empty
This commit adds an `AllowEmptyEnv` option that, default off, that when set will allow set, but empty, environment variables

Fixes #317
2018-11-06 22:53:21 +01:00
Andrew Stuart 62edee3196 Revert "Cater for case-sensitive dependencies (#463)"
This reverts commit b56071875a.
2018-09-29 21:41:27 -07:00
Panagiotis MoustafellosandAndrew Stuart b56071875a Cater for case-sensitive dependencies (#463)
Switching jww from jwalterweatherman to jWalterWeatherman for cases when vgo is broken
2018-09-29 20:32:38 -07:00
Andrew Stuart 8e194e8ad2 Merge branch 'master' into mergefix/Issue284_Kubernetes_config 2018-09-28 01:05:04 -07:00
Andrew Stuart 0d783e7344 Use test log 2018-09-28 01:04:19 -07:00
Andrew StuartandGitHub 2c12c60302 Fix nil pointer on watch function (#568) 2018-09-28 00:53:21 -07:00
Xavier Coulon 41f829b2c9 refactor test to avoid negative counter on WG
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
2018-08-06 09:29:13 +02:00
Xavier Coulon e12d3d32d1 Merge branch 'master' into Issue284_Kubernetes_config 2018-08-06 08:18:53 +02:00
Xavier Coulon c1250e5dd7 apply review comments
use masks for checking the events.

Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
2018-07-13 10:30:23 +02:00
Xavier Coulon 242f4890f5 Refactor with WaitGroup and check channel is open
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
2018-05-24 10:09:29 +02:00
Xavier Coulon e0f7631cf3 WatchConfig and Kubernetes (#284)
Support override of symlink to config file
Include tests for WatchConfig of regular files, as well
as config file which links to a folder which is itself a
link to another folder in the same "watch dir" (the way
Kubernetes exposes config files from ConfigMaps mounted
on a volume in a Pod)

Also:
- Add synchronization with WaitGroup to ensure that the WatchConfig
is properly started before returning
- Remove the watcher when the Config file is removed.

Fixes #284

Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
2018-01-03 10:37:18 +01:00
7 changed files with 538 additions and 78 deletions
+6 -1
View File
@@ -21,4 +21,9 @@ _testmain.go
*.exe
*.test
*.bench
*.bench
.vscode
# exclude dependencies in the `/vendor` folder
vendor
+5 -1
View File
@@ -1,8 +1,12 @@
go_import_path: github.com/spf13/viper
language: go
env:
global:
- GO111MODULE="on"
go:
- 1.10.x
- 1.11.x
- tip
+6 -1
View File
@@ -179,13 +179,14 @@ viper.GetBool("verbose") // true
### Working with Environment Variables
Viper has full support for environment variables. This enables 12 factor
applications out of the box. There are four methods that exist to aid working
applications out of the box. There are five methods that exist to aid working
with ENV:
* `AutomaticEnv()`
* `BindEnv(string...) : error`
* `SetEnvPrefix(string)`
* `SetEnvKeyReplacer(string...) *strings.Replacer`
* `AllowEmptyEnvVar(bool)`
_When working with ENV variables, its important to recognize that Viper
treats ENV variables as case sensitive._
@@ -217,6 +218,10 @@ keys to an extent. This is useful if you want to use `-` or something in your
`Get()` calls, but want your environmental variables to use `_` delimiters. An
example of using it can be found in `viper_test.go`.
By default empty environment variables are considered unset and will fall back to
the next configuration source. To treat empty environment variables as set, use
the `AllowEmptyEnv` method.
#### Env example
```go
+33 -6
View File
@@ -1,16 +1,43 @@
module github.com/spf13/viper
require (
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/coreos/bbolt v1.3.2 // indirect
github.com/coreos/etcd v3.3.10+incompatible // indirect
github.com/coreos/go-semver v0.2.0 // indirect
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/gogo/protobuf v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
github.com/google/btree v1.0.0 // indirect
github.com/gorilla/websocket v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.9.0 // indirect
github.com/hashicorp/hcl v1.0.0
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/magiconair/properties v1.8.0
github.com/mitchellh/mapstructure v1.0.0
github.com/mitchellh/mapstructure v1.1.2
github.com/pelletier/go-toml v1.2.0
github.com/prometheus/client_golang v0.9.3 // indirect
github.com/soheilhy/cmux v0.1.4 // indirect
github.com/spf13/afero v1.1.2
github.com/spf13/cast v1.2.0
github.com/spf13/cast v1.3.0
github.com/spf13/jwalterweatherman v1.0.0
github.com/spf13/pflag v1.0.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
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.2.2
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
github.com/ugorji/go v1.1.4 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77
go.etcd.io/bbolt v1.3.2 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/grpc v1.21.0 // indirect
gopkg.in/yaml.v2 v2.2.2
)
+161 -9
View File
@@ -1,26 +1,178 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
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=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I=
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
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/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
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=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
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=
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=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+106 -42
View File
@@ -30,6 +30,7 @@ import (
"path/filepath"
"reflect"
"strings"
"sync"
"time"
yaml "gopkg.in/yaml.v2"
@@ -179,13 +180,15 @@ type Viper struct {
remoteProviders []*defaultRemoteProvider
// Name of file to look for inside the path
configName string
configFile string
configType string
envPrefix string
configName string
configFile string
configType string
configPermissions os.FileMode
envPrefix string
automaticEnvApplied bool
envKeyReplacer *strings.Replacer
allowEmptyEnv bool
config map[string]interface{}
override map[string]interface{}
@@ -208,6 +211,7 @@ func New() *Viper {
v := new(Viper)
v.keyDelim = "."
v.configName = "config"
v.configPermissions = os.FileMode(0644)
v.fs = afero.NewOsFs()
v.config = make(map[string]interface{})
v.override = make(map[string]interface{})
@@ -276,48 +280,73 @@ func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
}
func WatchConfig() { v.WatchConfig() }
func (v *Viper) WatchConfig() {
initWG := sync.WaitGroup{}
initWG.Add(1)
go func() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
filename, err := v.getConfigFile()
if err != nil {
log.Println("error:", err)
log.Printf("error: %v\n", err)
return
}
configFile := filepath.Clean(filename)
configDir, _ := filepath.Split(configFile)
realConfigFile, _ := filepath.EvalSymlinks(filename)
done := make(chan bool)
eventsWG := sync.WaitGroup{}
eventsWG.Add(1)
go func() {
for {
select {
case event := <-watcher.Events:
// we only care about the config file
if filepath.Clean(event.Name) == configFile {
if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
err := v.ReadInConfig()
if err != nil {
log.Println("error:", err)
}
case event, ok := <-watcher.Events:
if !ok { // 'Events' channel is closed
eventsWG.Done()
return
}
currentConfigFile, _ := filepath.EvalSymlinks(filename)
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if (filepath.Clean(event.Name) == configFile &&
event.Op&writeOrCreateMask != 0) ||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
realConfigFile = currentConfigFile
err := v.ReadInConfig()
if err != nil {
log.Printf("error reading config file: %v\n", err)
}
if v.onConfigChange != nil {
v.onConfigChange(event)
}
} else if filepath.Clean(event.Name) == configFile &&
event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
eventsWG.Done()
return
}
case err := <-watcher.Errors:
log.Println("error:", err)
case err, ok := <-watcher.Errors:
if ok { // 'Errors' channel is not closed
log.Printf("watcher error: %v\n", err)
}
eventsWG.Done()
return
}
}
}()
watcher.Add(configDir)
<-done
initWG.Done() // done initalizing the watch in this go routine, so the parent routine can move on...
eventsWG.Wait() // now, wait for event loop to end in this go-routine...
}()
initWG.Wait() // make sure that the go routine above fully ended before returning
}
// SetConfigFile explicitly defines the path, name and extension of the config file.
@@ -347,6 +376,14 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
return strings.ToUpper(in)
}
// AllowEmptyEnv tells Viper to consider set,
// but empty environment variables as valid values instead of falling back.
// For backward compatibility reasons this is false by default.
func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) }
func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) {
v.allowEmptyEnv = allowEmptyEnv
}
// TODO: should getEnv logic be moved into find(). Can generalize the use of
// rewriting keys many things, Ex: Get('someKey') -> some_key
// (camel case to snake case for JSON keys perhaps)
@@ -354,11 +391,14 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
// getEnv is a wrapper around os.Getenv which replaces characters in the original
// key. This allows env vars which have different keys than the config object
// keys.
func (v *Viper) getEnv(key string) string {
func (v *Viper) getEnv(key string) (string, bool) {
if v.envKeyReplacer != nil {
key = v.envKeyReplacer.Replace(key)
}
return os.Getenv(key)
val, ok := os.LookupEnv(key)
return val, ok && (v.allowEmptyEnv || val != "")
}
// ConfigFileUsed returns the file used to populate the config registry.
@@ -585,10 +625,9 @@ func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
var parentKey string
var val string
for i := 1; i < len(path); i++ {
parentKey = strings.Join(path[0:i], v.keyDelim)
if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" {
if _, ok := v.getEnv(v.mergeWithEnvPrefix(parentKey)); ok {
return parentKey
}
}
@@ -650,6 +689,12 @@ func (v *Viper) Get(key string) interface{} {
return cast.ToString(val)
case int32, int16, int8, int:
return cast.ToInt(val)
case uint:
return cast.ToUint(val)
case uint32:
return cast.ToUint32(val)
case uint64:
return cast.ToUint64(val)
case int64:
return cast.ToInt64(val)
case float64, float32:
@@ -713,6 +758,24 @@ func (v *Viper) GetInt64(key string) int64 {
return cast.ToInt64(v.Get(key))
}
// GetUint returns the value associated with the key as an unsigned integer.
func GetUint(key string) uint { return v.GetUint(key) }
func (v *Viper) GetUint(key string) uint {
return cast.ToUint(v.Get(key))
}
// GetUint32 returns the value associated with the key as an unsigned integer.
func GetUint32(key string) uint32 { return v.GetUint32(key) }
func (v *Viper) GetUint32(key string) uint32 {
return cast.ToUint32(v.Get(key))
}
// GetUint64 returns the value associated with the key as an unsigned integer.
func GetUint64(key string) uint64 { return v.GetUint64(key) }
func (v *Viper) GetUint64(key string) uint64 {
return cast.ToUint64(v.Get(key))
}
// GetFloat64 returns the value associated with the key as a float64.
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
func (v *Viper) GetFloat64(key string) float64 {
@@ -774,8 +837,6 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConf
return err
}
v.insensitiviseMaps()
return nil
}
@@ -791,8 +852,6 @@ func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error
return err
}
v.insensitiviseMaps()
return nil
}
@@ -835,8 +894,6 @@ func (v *Viper) UnmarshalExact(rawVal interface{}) error {
return err
}
v.insensitiviseMaps()
return nil
}
@@ -967,7 +1024,7 @@ func (v *Viper) find(lcaseKey string) interface{} {
if v.automaticEnvApplied {
// even if it hasn't been registered, if automaticEnv is used,
// check any Get request
if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" {
if val, ok := v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); ok {
return val
}
if nested && v.isPathShadowedInAutoEnv(path) != "" {
@@ -976,7 +1033,7 @@ func (v *Viper) find(lcaseKey string) interface{} {
}
envkey, exists := v.env[lcaseKey]
if exists {
if val = v.getEnv(envkey); val != "" {
if val, ok := v.getEnv(envkey); ok {
return val
}
}
@@ -1222,13 +1279,21 @@ func (v *Viper) ReadConfig(in io.Reader) error {
// MergeConfig merges a new configuration with an existing config.
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error {
if v.config == nil {
v.config = make(map[string]interface{})
}
cfg := make(map[string]interface{})
if err := v.unmarshalReader(in, cfg); err != nil {
return err
}
return v.MergeConfigMap(cfg)
}
// MergeConfigMap merges the configuration from the map given with an existing config.
// Note that the map given may be modified.
func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) }
func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
if v.config == nil {
v.config = make(map[string]interface{})
}
insensitiviseMap(cfg)
mergeMaps(cfg, v.config, nil)
return nil
}
@@ -1289,7 +1354,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
return fmt.Errorf("File: %s exists. Use WriteConfig to overwrite.", filename)
}
}
f, err := v.fs.OpenFile(filename, flags, os.FileMode(0644))
f, err := v.fs.OpenFile(filename, flags, v.configPermissions)
if err != nil {
return err
}
@@ -1534,13 +1599,6 @@ func (v *Viper) WatchRemoteConfigOnChannel() error {
return v.watchKeyValueConfigOnChannel()
}
func (v *Viper) insensitiviseMaps() {
insensitiviseMap(v.config)
insensitiviseMap(v.defaults)
insensitiviseMap(v.override)
insensitiviseMap(v.kvstore)
}
// Retrieve the first found remote configuration.
func (v *Viper) getKeyValueConfig() error {
if RemoteConfig == nil {
@@ -1733,6 +1791,12 @@ func (v *Viper) SetConfigType(in string) {
}
}
// SetConfigPermissions sets the permissions for the config file.
func SetConfigPermissions(perm os.FileMode) { v.SetConfigPermissions(perm) }
func (v *Viper) SetConfigPermissions(perm os.FileMode) {
v.configPermissions = perm.Perm()
}
func (v *Viper) getConfigType() string {
if v.configType != "" {
return v.configType
+221 -18
View File
@@ -12,19 +12,24 @@ import (
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"reflect"
"runtime"
"sort"
"strings"
"sync"
"testing"
"time"
"github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var yamlExample = []byte(`Hacker: true
@@ -383,6 +388,36 @@ func TestEnv(t *testing.T) {
}
func TestEmptyEnv(t *testing.T) {
initJSON()
BindEnv("type") // Empty environment variable
BindEnv("name") // Bound, but not set environment variable
os.Clearenv()
os.Setenv("TYPE", "")
assert.Equal(t, "donut", Get("type"))
assert.Equal(t, "Cake", Get("name"))
}
func TestEmptyEnv_Allowed(t *testing.T) {
initJSON()
AllowEmptyEnv(true)
BindEnv("type") // Empty environment variable
BindEnv("name") // Bound, but not set environment variable
os.Clearenv()
os.Setenv("TYPE", "")
assert.Equal(t, "", Get("type"))
assert.Equal(t, "Cake", Get("name"))
}
func TestEnvPrefix(t *testing.T) {
initJSON()
@@ -578,24 +613,28 @@ func TestBindPFlags(t *testing.T) {
}
func TestBindPFlagsStringSlice(t *testing.T) {
for _, testValue := range []struct {
tests := []struct {
Expected []string
Value string
}{
{[]string{}, ""},
{nil, ""},
{[]string{"jeden"}, "jeden"},
{[]string{"dwa", "trzy"}, "dwa,trzy"},
{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""}} {
{[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""},
}
v := New() // create independent Viper object
defaultVal := []string{"default"}
v.SetDefault("stringslice", defaultVal)
for _, testValue := range tests {
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
flagSet.StringSlice("stringslice", testValue.Expected, "test")
for _, changed := range []bool{true, false} {
v := New() // create independent Viper object
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
flagSet.StringSlice("stringslice", testValue.Expected, "test")
flagSet.Visit(func(f *pflag.Flag) {
if len(testValue.Value) > 0 {
f.Value.Set(testValue.Value)
f.Changed = changed
}
flagSet.VisitAll(func(f *pflag.Flag) {
f.Value.Set(testValue.Value)
f.Changed = changed
})
err := v.BindPFlags(flagSet)
@@ -610,7 +649,11 @@ func TestBindPFlagsStringSlice(t *testing.T) {
if err := v.Unmarshal(val); err != nil {
t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
}
assert.Equal(t, testValue.Expected, val.StringSlice)
if changed {
assert.Equal(t, testValue.Expected, val.StringSlice)
} else {
assert.Equal(t, defaultVal, val.StringSlice)
}
}
}
}
@@ -1073,7 +1116,8 @@ func TestWriteConfigYAML(t *testing.T) {
var yamlMergeExampleTgt = []byte(`
hello:
pop: 37890
lagrenum: 765432101234567
largenum: 765432101234567
num2pow63: 9223372036854775808
world:
- us
- uk
@@ -1084,7 +1128,7 @@ hello:
var yamlMergeExampleSrc = []byte(`
hello:
pop: 45000
lagrenum: 7654321001234567
largenum: 7654321001234567
universe:
- mw
- ad
@@ -1106,8 +1150,20 @@ func TestMergeConfig(t *testing.T) {
t.Fatalf("pop != 37890, = %d", pop)
}
if pop := v.GetInt64("hello.lagrenum"); pop != int64(765432101234567) {
t.Fatalf("int64 lagrenum != 765432101234567, = %d", pop)
if pop := v.GetInt64("hello.largenum"); pop != int64(765432101234567) {
t.Fatalf("int64 largenum != 765432101234567, = %d", pop)
}
if pop := v.GetUint("hello.pop"); pop != 37890 {
t.Fatalf("uint pop != 37890, = %d", pop)
}
if pop := v.GetUint32("hello.pop"); pop != 37890 {
t.Fatalf("uint32 pop != 37890, = %d", pop)
}
if pop := v.GetUint64("hello.num2pow63"); pop != 9223372036854775808 {
t.Fatalf("uint64 num2pow63 != 9223372036854775808, = %d", pop)
}
if world := v.GetStringSlice("hello.world"); len(world) != 4 {
@@ -1130,8 +1186,8 @@ func TestMergeConfig(t *testing.T) {
t.Fatalf("pop != 45000, = %d", pop)
}
if pop := v.GetInt64("hello.lagrenum"); pop != int64(7654321001234567) {
t.Fatalf("int64 lagrenum != 7654321001234567, = %d", pop)
if pop := v.GetInt64("hello.largenum"); pop != int64(7654321001234567) {
t.Fatalf("int64 largenum != 7654321001234567, = %d", pop)
}
if world := v.GetStringSlice("hello.world"); len(world) != 4 {
@@ -1187,6 +1243,48 @@ func TestMergeConfigNoMerge(t *testing.T) {
}
}
func TestMergeConfigMap(t *testing.T) {
v := New()
v.SetConfigType("yml")
if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
t.Fatal(err)
}
assert := func(i int) {
large := v.GetInt64("hello.largenum")
pop := v.GetInt("hello.pop")
if large != 765432101234567 {
t.Fatal("Got large num:", large)
}
if pop != i {
t.Fatal("Got pop:", pop)
}
}
assert(37890)
update := map[string]interface{}{
"Hello": map[string]interface{}{
"Pop": 1234,
},
"World": map[interface{}]interface{}{
"Rock": 345,
},
}
if err := v.MergeConfigMap(update); err != nil {
t.Fatal(err)
}
if rock := v.GetInt("world.rock"); rock != 345 {
t.Fatal("Got rock:", rock)
}
assert(1234)
}
func TestUnmarshalingWithAliases(t *testing.T) {
v := New()
v.SetDefault("ID", 1)
@@ -1406,6 +1504,111 @@ func doTestCaseInsensitive(t *testing.T, typ, config string) {
}
func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
watchDir, err := ioutil.TempDir("", "")
require.Nil(t, err)
configFile := path.Join(watchDir, "config.yaml")
err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0640)
require.Nil(t, err)
cleanup := func() {
os.RemoveAll(watchDir)
}
v := New()
v.SetConfigFile(configFile)
err = v.ReadInConfig()
require.Nil(t, err)
require.Equal(t, "bar", v.Get("foo"))
return v, configFile, cleanup
}
func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
watchDir, err := ioutil.TempDir("", "")
require.Nil(t, err)
dataDir1 := path.Join(watchDir, "data1")
err = os.Mkdir(dataDir1, 0777)
require.Nil(t, err)
realConfigFile := path.Join(dataDir1, "config.yaml")
t.Logf("Real config file location: %s\n", realConfigFile)
err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0640)
require.Nil(t, err)
cleanup := func() {
os.RemoveAll(watchDir)
}
// now, symlink the tm `data1` dir to `data` in the baseDir
os.Symlink(dataDir1, path.Join(watchDir, "data"))
// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
configFile := path.Join(watchDir, "config.yaml")
os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
// init Viper
v := New()
v.SetConfigFile(configFile)
err = v.ReadInConfig()
require.Nil(t, err)
require.Equal(t, "bar", v.Get("foo"))
return v, watchDir, configFile, cleanup
}
func TestWatchFile(t *testing.T) {
if runtime.GOOS == "linux" {
// TODO(bep) FIX ME
t.Skip("Skip test on Linux ...")
}
t.Run("file content changed", func(t *testing.T) {
// given a `config.yaml` file being watched
v, configFile, cleanup := newViperWithConfigFile(t)
defer cleanup()
_, err := os.Stat(configFile)
require.NoError(t, err)
t.Logf("test config file: %s\n", configFile)
wg := sync.WaitGroup{}
wg.Add(1)
v.OnConfigChange(func(in fsnotify.Event) {
t.Logf("config file changed")
wg.Done()
})
v.WatchConfig()
// when overwriting the file and waiting for the custom change notification handler to be triggered
err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0640)
wg.Wait()
// then the config value should have changed
require.Nil(t, err)
assert.Equal(t, "baz", v.Get("foo"))
})
t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
// skip if not executed on Linux
if runtime.GOOS != "linux" {
t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
}
v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
// defer cleanup()
wg := sync.WaitGroup{}
v.WatchConfig()
v.OnConfigChange(func(in fsnotify.Event) {
t.Logf("config file changed")
wg.Done()
})
wg.Add(1)
// when link to another `config.yaml` file
dataDir2 := path.Join(watchDir, "data2")
err := os.Mkdir(dataDir2, 0777)
require.Nil(t, err)
configFile2 := path.Join(dataDir2, "config.yaml")
err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0640)
require.Nil(t, err)
// change the symlink using the `ln -sfn` command
err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
require.Nil(t, err)
wg.Wait()
// then
require.Nil(t, err)
assert.Equal(t, "baz", v.Get("foo"))
})
}
func BenchmarkGetBool(b *testing.B) {
key := "BenchmarkGetBool"
v = New()