spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 1 | // Copyright © 2014 Steve Francia <spf@spf13.com>. |
| 2 | // |
| 3 | // Use of this source code is governed by an MIT-style |
| 4 | // license that can be found in the LICENSE file. |
| 5 | |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 6 | // Viper is a application configuration system. |
| 7 | // It believes that applications can be configured a variety of ways |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 8 | // via flags, ENVIRONMENT variables, configuration files retrieved |
| 9 | // from the file system, or a remote key/value store. |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 10 | |
| 11 | // Each item takes precedence over the item below it: |
| 12 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 13 | // overrides |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 14 | // flag |
| 15 | // env |
| 16 | // config |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 17 | // key/value store |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 18 | // default |
| 19 | |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 20 | package viper |
| 21 | |
| 22 | import ( |
| 23 | "bytes" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 24 | "fmt" |
| 25 | "io" |
| 26 | "io/ioutil" |
| 27 | "os" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 28 | "path/filepath" |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 29 | "reflect" |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 30 | "strings" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 31 | "time" |
| 32 | |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 33 | "github.com/kr/pretty" |
spf13 | af373af | 2014-06-26 17:58:55 -0400 | [diff] [blame] | 34 | "github.com/mitchellh/mapstructure" |
jackspirou | d028fd6 | 2015-07-30 15:44:12 -0500 | [diff] [blame] | 35 | "github.com/spf13/cast" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 36 | jww "github.com/spf13/jwalterweatherman" |
spf13 | 7c42740 | 2014-06-27 12:29:37 -0400 | [diff] [blame] | 37 | "github.com/spf13/pflag" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 38 | ) |
| 39 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 40 | var v *Viper |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 41 | |
| 42 | func init() { |
| 43 | v = New() |
| 44 | } |
| 45 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 46 | type remoteConfigFactory interface { |
| 47 | Get(rp RemoteProvider) (io.Reader, error) |
| 48 | Watch(rp RemoteProvider) (io.Reader, error) |
| 49 | } |
| 50 | |
| 51 | // RemoteConfig is optional, see the remote package |
| 52 | var RemoteConfig remoteConfigFactory |
| 53 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 54 | // Denotes encountering an unsupported |
| 55 | // configuration filetype. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 56 | type UnsupportedConfigError string |
| 57 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 58 | // Returns the formatted configuration error. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 59 | func (str UnsupportedConfigError) Error() string { |
| 60 | return fmt.Sprintf("Unsupported Config Type %q", string(str)) |
| 61 | } |
| 62 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 63 | // Denotes encountering an unsupported remote |
| 64 | // provider. Currently only Etcd and Consul are |
| 65 | // supported. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 66 | type UnsupportedRemoteProviderError string |
| 67 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 68 | // Returns the formatted remote provider error. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 69 | func (str UnsupportedRemoteProviderError) Error() string { |
| 70 | return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str)) |
| 71 | } |
| 72 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 73 | // Denotes encountering an error while trying to |
| 74 | // pull the configuration from the remote provider. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 75 | type RemoteConfigError string |
| 76 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 77 | // Returns the formatted remote provider error |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 78 | func (rce RemoteConfigError) Error() string { |
| 79 | return fmt.Sprintf("Remote Configurations Error: %s", string(rce)) |
| 80 | } |
| 81 | |
Vlad Didenko | 9fca101 | 2015-08-01 19:37:27 -0500 | [diff] [blame] | 82 | // Denotes failing to find configuration file. |
| 83 | type ConfigFileNotFoundError struct { |
| 84 | name, locations string |
| 85 | } |
| 86 | |
| 87 | // Returns the formatted configuration error. |
| 88 | func (fnfe ConfigFileNotFoundError) Error() string { |
| 89 | return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) |
| 90 | } |
| 91 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 92 | // Viper is a prioritized configuration registry. It |
| 93 | // maintains a set of configuration sources, fetches |
| 94 | // values to populate those, and provides them according |
| 95 | // to the source's priority. |
| 96 | // The priority of the sources is the following: |
| 97 | // 1. overrides |
| 98 | // 2. flags |
| 99 | // 3. env. variables |
| 100 | // 4. config file |
| 101 | // 5. key/value store |
| 102 | // 6. defaults |
| 103 | // |
| 104 | // For example, if values from the following sources were loaded: |
| 105 | // |
| 106 | // Defaults : { |
| 107 | // "secret": "", |
| 108 | // "user": "default", |
| 109 | // "endpoint": "https://localhost" |
| 110 | // } |
| 111 | // Config : { |
| 112 | // "user": "root" |
| 113 | // "secret": "defaultsecret" |
| 114 | // } |
| 115 | // Env : { |
| 116 | // "secret": "somesecretkey" |
| 117 | // } |
| 118 | // |
| 119 | // The resulting config will have the following values: |
| 120 | // |
| 121 | // { |
| 122 | // "secret": "somesecretkey", |
| 123 | // "user": "root", |
| 124 | // "endpoint": "https://localhost" |
| 125 | // } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 126 | type Viper struct { |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 127 | // Delimiter that separates a list of keys |
| 128 | // used to access a nested value in one go |
| 129 | keyDelim string |
| 130 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 131 | // A set of paths to look for the config file in |
| 132 | configPaths []string |
| 133 | |
| 134 | // A set of remote providers to search for the configuration |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 135 | remoteProviders []*defaultRemoteProvider |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 136 | |
| 137 | // Name of file to look for inside the path |
| 138 | configName string |
| 139 | configFile string |
| 140 | configType string |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 141 | envPrefix string |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 142 | |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 143 | automaticEnvApplied bool |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 144 | envKeyReplacer *strings.Replacer |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 145 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 146 | config map[string]interface{} |
| 147 | override map[string]interface{} |
| 148 | defaults map[string]interface{} |
| 149 | kvstore map[string]interface{} |
| 150 | pflags map[string]*pflag.Flag |
| 151 | env map[string]string |
| 152 | aliases map[string]string |
| 153 | } |
| 154 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 155 | // Returns an initialized Viper instance. |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 156 | func New() *Viper { |
| 157 | v := new(Viper) |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 158 | v.keyDelim = "." |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 159 | v.configName = "config" |
| 160 | v.config = make(map[string]interface{}) |
| 161 | v.override = make(map[string]interface{}) |
| 162 | v.defaults = make(map[string]interface{}) |
| 163 | v.kvstore = make(map[string]interface{}) |
| 164 | v.pflags = make(map[string]*pflag.Flag) |
| 165 | v.env = make(map[string]string) |
| 166 | v.aliases = make(map[string]string) |
| 167 | |
| 168 | return v |
| 169 | } |
| 170 | |
Ross Cooperman | 9073483 | 2015-02-19 10:39:44 -0500 | [diff] [blame] | 171 | // Intended for testing, will reset all to default settings. |
| 172 | // In the public interface for the viper package so applications |
| 173 | // can use it in their testing as well. |
| 174 | func Reset() { |
| 175 | v = New() |
| 176 | SupportedExts = []string{"json", "toml", "yaml", "yml"} |
| 177 | SupportedRemoteProviders = []string{"etcd", "consul"} |
| 178 | } |
| 179 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 180 | type defaultRemoteProvider struct { |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 181 | provider string |
| 182 | endpoint string |
| 183 | path string |
| 184 | secretKeyring string |
| 185 | } |
| 186 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 187 | func (rp defaultRemoteProvider) Provider() string { |
| 188 | return rp.provider |
| 189 | } |
| 190 | |
| 191 | func (rp defaultRemoteProvider) Endpoint() string { |
| 192 | return rp.endpoint |
| 193 | } |
| 194 | |
| 195 | func (rp defaultRemoteProvider) Path() string { |
| 196 | return rp.path |
| 197 | } |
| 198 | |
| 199 | func (rp defaultRemoteProvider) SecretKeyring() string { |
| 200 | return rp.secretKeyring |
| 201 | } |
| 202 | |
| 203 | // RemoteProvider stores the configuration necessary |
| 204 | // to connect to a remote key/value store. |
| 205 | // Optional secretKeyring to unencrypt encrypted values |
| 206 | // can be provided. |
| 207 | type RemoteProvider interface { |
| 208 | Provider() string |
| 209 | Endpoint() string |
| 210 | Path() string |
| 211 | SecretKeyring() string |
| 212 | } |
| 213 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 214 | // Universally supported extensions. |
Wayne Walker | ba3382d | 2015-04-14 13:15:02 -0500 | [diff] [blame] | 215 | var SupportedExts []string = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop"} |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 216 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 217 | // Universally supported remote providers. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 218 | var SupportedRemoteProviders []string = []string{"etcd", "consul"} |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 219 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 220 | // Explicitly define the path, name and extension of the config file |
| 221 | // Viper will use this and not check any of the config paths |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 222 | func SetConfigFile(in string) { v.SetConfigFile(in) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 223 | func (v *Viper) SetConfigFile(in string) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 224 | if in != "" { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 225 | v.configFile = in |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 226 | } |
| 227 | } |
| 228 | |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 229 | // Define a prefix that ENVIRONMENT variables will use. |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 230 | // E.g. if your prefix is "spf", the env registry |
| 231 | // will look for env. variables that start with "SPF_" |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 232 | func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 233 | func (v *Viper) SetEnvPrefix(in string) { |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 234 | if in != "" { |
| 235 | v.envPrefix = in |
| 236 | } |
| 237 | } |
| 238 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 239 | func (v *Viper) mergeWithEnvPrefix(in string) string { |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 240 | if v.envPrefix != "" { |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 241 | return strings.ToUpper(v.envPrefix + "_" + in) |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 242 | } |
| 243 | |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 244 | return strings.ToUpper(in) |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 245 | } |
| 246 | |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 247 | // TODO: should getEnv logic be moved into find(). Can generalize the use of |
| 248 | // rewriting keys many things, Ex: Get('someKey') -> some_key |
| 249 | // (cammel case to snake case for JSON keys perhaps) |
| 250 | |
| 251 | // getEnv s a wrapper around os.Getenv which replaces characters in the original |
| 252 | // key. This allows env vars which have different keys then the config object |
| 253 | // keys |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 254 | func (v *Viper) getEnv(key string) string { |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 255 | if v.envKeyReplacer != nil { |
| 256 | key = v.envKeyReplacer.Replace(key) |
| 257 | } |
| 258 | return os.Getenv(key) |
| 259 | } |
| 260 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 261 | // Return the file used to populate the config registry |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 262 | func ConfigFileUsed() string { return v.ConfigFileUsed() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 263 | func (v *Viper) ConfigFileUsed() string { return v.configFile } |
spf13 | 8b744a9 | 2014-04-07 23:35:40 -0400 | [diff] [blame] | 264 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 265 | // Add a path for Viper to search for the config file in. |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 266 | // Can be called multiple times to define multiple search paths. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 267 | func AddConfigPath(in string) { v.AddConfigPath(in) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 268 | func (v *Viper) AddConfigPath(in string) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 269 | if in != "" { |
| 270 | absin := absPathify(in) |
| 271 | jww.INFO.Println("adding", absin, "to paths to search") |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 272 | if !stringInSlice(absin, v.configPaths) { |
| 273 | v.configPaths = append(v.configPaths, absin) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 278 | // AddRemoteProvider adds a remote configuration source. |
| 279 | // Remote Providers are searched in the order they are added. |
| 280 | // provider is a string value, "etcd" or "consul" are currently supported. |
| 281 | // endpoint is the url. etcd requires http://ip:port consul requires ip:port |
| 282 | // path is the path in the k/v store to retrieve configuration |
| 283 | // To retrieve a config file called myapp.json from /configs/myapp.json |
| 284 | // you should set path to /configs and set config name (SetConfigName()) to |
| 285 | // "myapp" |
| 286 | func AddRemoteProvider(provider, endpoint, path string) error { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 287 | return v.AddRemoteProvider(provider, endpoint, path) |
| 288 | } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 289 | func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 290 | if !stringInSlice(provider, SupportedRemoteProviders) { |
| 291 | return UnsupportedRemoteProviderError(provider) |
| 292 | } |
| 293 | if provider != "" && endpoint != "" { |
| 294 | jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 295 | rp := &defaultRemoteProvider{ |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 296 | endpoint: endpoint, |
| 297 | provider: provider, |
Brian Ketelsen | 5e1d5e7 | 2014-10-27 12:21:03 -0400 | [diff] [blame] | 298 | path: path, |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 299 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 300 | if !v.providerPathExists(rp) { |
| 301 | v.remoteProviders = append(v.remoteProviders, rp) |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 302 | } |
| 303 | } |
| 304 | return nil |
| 305 | } |
| 306 | |
| 307 | // AddSecureRemoteProvider adds a remote configuration source. |
| 308 | // Secure Remote Providers are searched in the order they are added. |
| 309 | // provider is a string value, "etcd" or "consul" are currently supported. |
| 310 | // endpoint is the url. etcd requires http://ip:port consul requires ip:port |
| 311 | // secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg |
| 312 | // path is the path in the k/v store to retrieve configuration |
| 313 | // To retrieve a config file called myapp.json from /configs/myapp.json |
| 314 | // you should set path to /configs and set config name (SetConfigName()) to |
| 315 | // "myapp" |
| 316 | // Secure Remote Providers are implemented with github.com/xordataexchange/crypt |
Brian Ketelsen | 5e1d5e7 | 2014-10-27 12:21:03 -0400 | [diff] [blame] | 317 | func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 318 | return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring) |
| 319 | } |
| 320 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 321 | func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 322 | if !stringInSlice(provider, SupportedRemoteProviders) { |
| 323 | return UnsupportedRemoteProviderError(provider) |
| 324 | } |
| 325 | if provider != "" && endpoint != "" { |
| 326 | jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 327 | rp := &defaultRemoteProvider{ |
Kiril Zvezdarov | db7ff93 | 2015-06-21 19:19:00 -0400 | [diff] [blame] | 328 | endpoint: endpoint, |
| 329 | provider: provider, |
| 330 | path: path, |
| 331 | secretKeyring: secretkeyring, |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 332 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 333 | if !v.providerPathExists(rp) { |
| 334 | v.remoteProviders = append(v.remoteProviders, rp) |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 335 | } |
| 336 | } |
| 337 | return nil |
| 338 | } |
| 339 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 340 | func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 341 | for _, y := range v.remoteProviders { |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 342 | if reflect.DeepEqual(y, p) { |
| 343 | return true |
| 344 | } |
| 345 | } |
| 346 | return false |
| 347 | } |
| 348 | |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 349 | func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { |
| 350 | |
| 351 | if len(path) == 0 { |
| 352 | return source |
| 353 | } |
| 354 | |
| 355 | if next, ok := source[path[0]]; ok { |
| 356 | switch next.(type) { |
Dotan Nahum | 28ada1e | 2015-05-27 18:15:02 +0300 | [diff] [blame] | 357 | case map[interface{}]interface{}: |
| 358 | return v.searchMap(cast.ToStringMap(next), path[1:]) |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 359 | case map[string]interface{}: |
| 360 | // Type assertion is safe here since it is only reached |
| 361 | // if the type of `next` is the same as the type being asserted |
| 362 | return v.searchMap(next.(map[string]interface{}), path[1:]) |
| 363 | default: |
| 364 | return next |
| 365 | } |
| 366 | } else { |
| 367 | return nil |
| 368 | } |
| 369 | } |
| 370 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 371 | // Viper is essentially repository for configurations |
| 372 | // Get can retrieve any value given the key to use |
| 373 | // Get has the behavior of returning the value associated with the first |
| 374 | // place from where it is set. Viper will check in the following order: |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 375 | // override, flag, env, config file, key/value store, default |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 376 | // |
| 377 | // Get returns an interface. For a specific value use one of the Get____ methods. |
| 378 | func Get(key string) interface{} { return v.Get(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 379 | func (v *Viper) Get(key string) interface{} { |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 380 | path := strings.Split(key, v.keyDelim) |
| 381 | |
| 382 | val := v.find(strings.ToLower(key)) |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 383 | |
| 384 | if val == nil { |
Kiril Zvezdarov | c174e24 | 2015-04-26 15:02:19 -0400 | [diff] [blame] | 385 | source := v.find(path[0]) |
| 386 | if source == nil { |
| 387 | return nil |
| 388 | } |
| 389 | |
| 390 | if reflect.TypeOf(source).Kind() == reflect.Map { |
| 391 | val = v.searchMap(cast.ToStringMap(source), path[1:]) |
| 392 | } |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 393 | } |
| 394 | |
| 395 | switch val.(type) { |
| 396 | case bool: |
| 397 | return cast.ToBool(val) |
| 398 | case string: |
| 399 | return cast.ToString(val) |
| 400 | case int64, int32, int16, int8, int: |
| 401 | return cast.ToInt(val) |
| 402 | case float64, float32: |
| 403 | return cast.ToFloat64(val) |
| 404 | case time.Time: |
| 405 | return cast.ToTime(val) |
Chance Zibolski | ededa04 | 2015-02-18 19:03:20 -0800 | [diff] [blame] | 406 | case time.Duration: |
| 407 | return cast.ToDuration(val) |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 408 | case []string: |
| 409 | return val |
| 410 | } |
| 411 | return val |
| 412 | } |
| 413 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 414 | // Returns the value associated with the key as a string |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 415 | func GetString(key string) string { return v.GetString(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 416 | func (v *Viper) GetString(key string) string { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 417 | return cast.ToString(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 418 | } |
| 419 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 420 | // Returns the value associated with the key asa boolean |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 421 | func GetBool(key string) bool { return v.GetBool(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 422 | func (v *Viper) GetBool(key string) bool { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 423 | return cast.ToBool(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 424 | } |
| 425 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 426 | // Returns the value associated with the key as an integer |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 427 | func GetInt(key string) int { return v.GetInt(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 428 | func (v *Viper) GetInt(key string) int { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 429 | return cast.ToInt(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 430 | } |
| 431 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 432 | // Returns the value associated with the key as a float64 |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 433 | func GetFloat64(key string) float64 { return v.GetFloat64(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 434 | func (v *Viper) GetFloat64(key string) float64 { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 435 | return cast.ToFloat64(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 436 | } |
| 437 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 438 | // Returns the value associated with the key as time |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 439 | func GetTime(key string) time.Time { return v.GetTime(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 440 | func (v *Viper) GetTime(key string) time.Time { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 441 | return cast.ToTime(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 442 | } |
| 443 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 444 | // Returns the value associated with the key as a duration |
Chance Zibolski | ededa04 | 2015-02-18 19:03:20 -0800 | [diff] [blame] | 445 | func GetDuration(key string) time.Duration { return v.GetDuration(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 446 | func (v *Viper) GetDuration(key string) time.Duration { |
Chance Zibolski | ededa04 | 2015-02-18 19:03:20 -0800 | [diff] [blame] | 447 | return cast.ToDuration(v.Get(key)) |
| 448 | } |
| 449 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 450 | // Returns the value associated with the key as a slice of strings |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 451 | func GetStringSlice(key string) []string { return v.GetStringSlice(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 452 | func (v *Viper) GetStringSlice(key string) []string { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 453 | return cast.ToStringSlice(v.Get(key)) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 454 | } |
| 455 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 456 | // Returns the value associated with the key as a map of interfaces |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 457 | func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 458 | func (v *Viper) GetStringMap(key string) map[string]interface{} { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 459 | return cast.ToStringMap(v.Get(key)) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 460 | } |
| 461 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 462 | // Returns the value associated with the key as a map of strings |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 463 | func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 464 | func (v *Viper) GetStringMapString(key string) map[string]string { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 465 | return cast.ToStringMapString(v.Get(key)) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 466 | } |
| 467 | |
jackspirou | 3c0ff86 | 2015-08-03 11:42:26 -0500 | [diff] [blame^] | 468 | // Returns the value associated with the key as a map to a slice of strings. |
jackspirou | cc1c9a8 | 2015-07-30 15:43:18 -0500 | [diff] [blame] | 469 | func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } |
jackspirou | 09ba0a6 | 2015-07-30 15:46:38 -0500 | [diff] [blame] | 470 | func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { |
jackspirou | b9316c3 | 2015-07-30 15:27:34 -0500 | [diff] [blame] | 471 | return cast.ToStringMapStringSlice(v.Get(key)) |
| 472 | } |
| 473 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 474 | // Returns the size of the value associated with the given key |
| 475 | // in bytes. |
Daniel Eloff | e133904 | 2015-02-28 16:03:22 -0500 | [diff] [blame] | 476 | func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 477 | func (v *Viper) GetSizeInBytes(key string) uint { |
Daniel Eloff | e133904 | 2015-02-28 16:03:22 -0500 | [diff] [blame] | 478 | sizeStr := cast.ToString(v.Get(key)) |
| 479 | return parseSizeInBytes(sizeStr) |
| 480 | } |
| 481 | |
spf13 | c5a9056 | 2014-07-11 10:41:45 -0400 | [diff] [blame] | 482 | // Takes a single key and marshals it into a Struct |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 483 | func MarshalKey(key string, rawVal interface{}) error { return v.MarshalKey(key, rawVal) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 484 | func (v *Viper) MarshalKey(key string, rawVal interface{}) error { |
kgv | 2909239 | 2014-12-09 15:42:09 +0300 | [diff] [blame] | 485 | return mapstructure.Decode(v.Get(key), rawVal) |
spf13 | af373af | 2014-06-26 17:58:55 -0400 | [diff] [blame] | 486 | } |
| 487 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 488 | // Marshals the config into a Struct. Make sure that the tags |
| 489 | // on the fields of the structure are properly set. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 490 | func Marshal(rawVal interface{}) error { return v.Marshal(rawVal) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 491 | func (v *Viper) Marshal(rawVal interface{}) error { |
Kiril Zvezdarov | 2e2f3b2 | 2015-02-16 23:42:08 -0500 | [diff] [blame] | 492 | err := mapstructure.WeakDecode(v.AllSettings(), rawVal) |
| 493 | |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 494 | if err != nil { |
| 495 | return err |
| 496 | } |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 497 | |
Anthony Fok | 5b0b926 | 2015-01-22 00:43:42 -0700 | [diff] [blame] | 498 | v.insensitiviseMaps() |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 499 | |
| 500 | return nil |
spf13 | af373af | 2014-06-26 17:58:55 -0400 | [diff] [blame] | 501 | } |
| 502 | |
Kiril Zvezdarov | 24dd877 | 2015-04-01 21:38:54 -0400 | [diff] [blame] | 503 | // Bind a full flag set to the configuration, using each flag's long |
| 504 | // name as the config key. |
| 505 | func BindPFlags(flags *pflag.FlagSet) (err error) { return v.BindPFlags(flags) } |
| 506 | func (v *Viper) BindPFlags(flags *pflag.FlagSet) (err error) { |
| 507 | flags.VisitAll(func(flag *pflag.Flag) { |
| 508 | if err != nil { |
| 509 | // an error has been encountered in one of the previous flags |
| 510 | return |
| 511 | } |
| 512 | |
| 513 | err = v.BindPFlag(flag.Name, flag) |
Kiril Zvezdarov | c861bde | 2015-04-01 21:42:06 -0400 | [diff] [blame] | 514 | switch flag.Value.Type() { |
| 515 | case "int", "int8", "int16", "int32", "int64": |
| 516 | v.SetDefault(flag.Name, cast.ToInt(flag.Value.String())) |
| 517 | case "bool": |
| 518 | v.SetDefault(flag.Name, cast.ToBool(flag.Value.String())) |
| 519 | default: |
| 520 | v.SetDefault(flag.Name, flag.Value.String()) |
| 521 | } |
Kiril Zvezdarov | 24dd877 | 2015-04-01 21:38:54 -0400 | [diff] [blame] | 522 | }) |
| 523 | return |
| 524 | } |
| 525 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 526 | // Bind a specific key to a flag (as used by cobra) |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 527 | // Example(where serverCmd is a Cobra instance): |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 528 | // |
| 529 | // serverCmd.Flags().Int("port", 1138, "Port to run Application server on") |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 530 | // Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 531 | // |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 532 | func BindPFlag(key string, flag *pflag.Flag) (err error) { return v.BindPFlag(key, flag) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 533 | func (v *Viper) BindPFlag(key string, flag *pflag.Flag) (err error) { |
spf13 | 7c42740 | 2014-06-27 12:29:37 -0400 | [diff] [blame] | 534 | if flag == nil { |
| 535 | return fmt.Errorf("flag for %q is nil", key) |
| 536 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 537 | v.pflags[strings.ToLower(key)] = flag |
spf13 | 1cebee8 | 2014-07-11 10:28:03 -0400 | [diff] [blame] | 538 | |
| 539 | switch flag.Value.Type() { |
| 540 | case "int", "int8", "int16", "int32", "int64": |
Vlad Didenko | f14e1ba | 2015-07-18 17:30:30 -0500 | [diff] [blame] | 541 | v.SetDefault(key, cast.ToInt(flag.Value.String())) |
spf13 | 1cebee8 | 2014-07-11 10:28:03 -0400 | [diff] [blame] | 542 | case "bool": |
Vlad Didenko | f14e1ba | 2015-07-18 17:30:30 -0500 | [diff] [blame] | 543 | v.SetDefault(key, cast.ToBool(flag.Value.String())) |
spf13 | 1cebee8 | 2014-07-11 10:28:03 -0400 | [diff] [blame] | 544 | default: |
Vlad Didenko | f14e1ba | 2015-07-18 17:30:30 -0500 | [diff] [blame] | 545 | v.SetDefault(key, flag.Value.String()) |
spf13 | 1cebee8 | 2014-07-11 10:28:03 -0400 | [diff] [blame] | 546 | } |
spf13 | 7c42740 | 2014-06-27 12:29:37 -0400 | [diff] [blame] | 547 | return nil |
| 548 | } |
| 549 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 550 | // Binds a Viper key to a ENV variable |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 551 | // ENV variables are case sensitive |
| 552 | // If only a key is provided, it will use the env key matching the key, uppercased. |
spf13 | 1022d75 | 2014-12-22 18:31:11 -0500 | [diff] [blame] | 553 | // EnvPrefix will be used when set when env name is not provided. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 554 | func BindEnv(input ...string) (err error) { return v.BindEnv(input...) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 555 | func (v *Viper) BindEnv(input ...string) (err error) { |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 556 | var key, envkey string |
| 557 | if len(input) == 0 { |
| 558 | return fmt.Errorf("BindEnv missing key to bind to") |
| 559 | } |
| 560 | |
Chris Hamant | 1b8adf4 | 2014-10-09 16:39:24 -0400 | [diff] [blame] | 561 | key = strings.ToLower(input[0]) |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 562 | |
| 563 | if len(input) == 1 { |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 564 | envkey = v.mergeWithEnvPrefix(key) |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 565 | } else { |
| 566 | envkey = input[1] |
| 567 | } |
| 568 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 569 | v.env[key] = envkey |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 570 | |
| 571 | return nil |
| 572 | } |
| 573 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 574 | // Given a key, find the value |
| 575 | // Viper will check in the following order: |
| 576 | // flag, env, config file, key/value store, default |
| 577 | // Viper will check to see if an alias exists first |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 578 | func (v *Viper) find(key string) interface{} { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 579 | var val interface{} |
| 580 | var exists bool |
| 581 | |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 582 | // if the requested key is an alias, then return the proper key |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 583 | key = v.realKey(key) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 584 | |
spf13 | 7c42740 | 2014-06-27 12:29:37 -0400 | [diff] [blame] | 585 | // PFlag Override first |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 586 | flag, exists := v.pflags[key] |
spf13 | 7c42740 | 2014-06-27 12:29:37 -0400 | [diff] [blame] | 587 | if exists { |
| 588 | if flag.Changed { |
| 589 | jww.TRACE.Println(key, "found in override (via pflag):", val) |
| 590 | return flag.Value.String() |
| 591 | } |
| 592 | } |
| 593 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 594 | val, exists = v.override[key] |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 595 | if exists { |
| 596 | jww.TRACE.Println(key, "found in override:", val) |
| 597 | return val |
| 598 | } |
| 599 | |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 600 | if v.automaticEnvApplied { |
| 601 | // even if it hasn't been registered, if automaticEnv is used, |
| 602 | // check any Get request |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 603 | if val = v.getEnv(v.mergeWithEnvPrefix(key)); val != "" { |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 604 | jww.TRACE.Println(key, "found in environment with val:", val) |
| 605 | return val |
| 606 | } |
| 607 | } |
| 608 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 609 | envkey, exists := v.env[key] |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 610 | if exists { |
| 611 | jww.TRACE.Println(key, "registered as env var", envkey) |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 612 | if val = v.getEnv(envkey); val != "" { |
Kevin Bowrin | 6c340f2 | 2014-11-07 18:14:27 +0000 | [diff] [blame] | 613 | jww.TRACE.Println(envkey, "found in environment with val:", val) |
spf13 | 181a3b5 | 2014-09-27 14:03:00 -0700 | [diff] [blame] | 614 | return val |
| 615 | } else { |
| 616 | jww.TRACE.Println(envkey, "env value unset:") |
| 617 | } |
| 618 | } |
| 619 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 620 | val, exists = v.config[key] |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 621 | if exists { |
| 622 | jww.TRACE.Println(key, "found in config:", val) |
| 623 | return val |
| 624 | } |
| 625 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 626 | val, exists = v.kvstore[key] |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 627 | if exists { |
| 628 | jww.TRACE.Println(key, "found in key/value store:", val) |
| 629 | return val |
| 630 | } |
| 631 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 632 | val, exists = v.defaults[key] |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 633 | if exists { |
| 634 | jww.TRACE.Println(key, "found in defaults:", val) |
| 635 | return val |
| 636 | } |
| 637 | |
| 638 | return nil |
| 639 | } |
| 640 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 641 | // Check to see if the key has been set in any of the data locations |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 642 | func IsSet(key string) bool { return v.IsSet(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 643 | func (v *Viper) IsSet(key string) bool { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 644 | t := v.Get(key) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 645 | return t != nil |
| 646 | } |
| 647 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 648 | // Have Viper check ENV variables for all |
spf13 | 83fd926 | 2014-09-27 14:01:11 -0700 | [diff] [blame] | 649 | // keys set in config, default & flags |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 650 | func AutomaticEnv() { v.AutomaticEnv() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 651 | func (v *Viper) AutomaticEnv() { |
spf13 | d8f2aa7 | 2014-12-22 22:47:25 -0500 | [diff] [blame] | 652 | v.automaticEnvApplied = true |
spf13 | 83fd926 | 2014-09-27 14:01:11 -0700 | [diff] [blame] | 653 | } |
| 654 | |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 655 | // SetEnvKeyReplacer sets the strings.Replacer on the viper object |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 656 | // Useful for mapping an environmental variable to a key that does |
| 657 | // not match it. |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 658 | func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 659 | func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { |
Chance Zibolski | 03fb74b | 2015-03-06 11:21:17 -0800 | [diff] [blame] | 660 | v.envKeyReplacer = r |
| 661 | } |
| 662 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 663 | // Aliases provide another accessor for the same key. |
| 664 | // This enables one to change a name without breaking the application |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 665 | func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 666 | func (v *Viper) RegisterAlias(alias string, key string) { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 667 | v.registerAlias(alias, strings.ToLower(key)) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 668 | } |
| 669 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 670 | func (v *Viper) registerAlias(alias string, key string) { |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 671 | alias = strings.ToLower(alias) |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 672 | if alias != key && alias != v.realKey(key) { |
| 673 | _, exists := v.aliases[alias] |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 674 | |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 675 | if !exists { |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 676 | // if we alias something that exists in one of the maps to another |
| 677 | // name, we'll never be able to get that value using the original |
| 678 | // name, so move the config value to the new realkey. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 679 | if val, ok := v.config[alias]; ok { |
| 680 | delete(v.config, alias) |
| 681 | v.config[key] = val |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 682 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 683 | if val, ok := v.kvstore[alias]; ok { |
| 684 | delete(v.kvstore, alias) |
| 685 | v.kvstore[key] = val |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 686 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 687 | if val, ok := v.defaults[alias]; ok { |
| 688 | delete(v.defaults, alias) |
| 689 | v.defaults[key] = val |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 690 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 691 | if val, ok := v.override[alias]; ok { |
| 692 | delete(v.override, alias) |
| 693 | v.override[key] = val |
Nate Finch | 2b24bea | 2014-08-05 07:35:21 -0400 | [diff] [blame] | 694 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 695 | v.aliases[alias] = key |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 696 | } |
| 697 | } else { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 698 | jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 699 | } |
| 700 | } |
| 701 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 702 | func (v *Viper) realKey(key string) string { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 703 | newkey, exists := v.aliases[key] |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 704 | if exists { |
| 705 | jww.DEBUG.Println("Alias", key, "to", newkey) |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 706 | return v.realKey(newkey) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 707 | } else { |
| 708 | return key |
| 709 | } |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 710 | } |
| 711 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 712 | // Check to see if the given key (or an alias) is in the config file |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 713 | func InConfig(key string) bool { return v.InConfig(key) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 714 | func (v *Viper) InConfig(key string) bool { |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 715 | // if the requested key is an alias, then return the proper key |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 716 | key = v.realKey(key) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 717 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 718 | _, exists := v.config[key] |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 719 | return exists |
| 720 | } |
| 721 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 722 | // Set the default value for this key. |
| 723 | // Default only used when no value is provided by the user via flag, config or ENV. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 724 | func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 725 | func (v *Viper) SetDefault(key string, value interface{}) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 726 | // If alias passed in, then set the proper default |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 727 | key = v.realKey(strings.ToLower(key)) |
| 728 | v.defaults[key] = value |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 729 | } |
| 730 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 731 | // Sets the value for the key in the override regiser. |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 732 | // Will be used instead of values obtained via |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 733 | // flags, config file, ENV, default, or key/value store |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 734 | func Set(key string, value interface{}) { v.Set(key, value) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 735 | func (v *Viper) Set(key string, value interface{}) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 736 | // If alias passed in, then set the proper override |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 737 | key = v.realKey(strings.ToLower(key)) |
| 738 | v.override[key] = value |
Joshua Rubin | 1a2e68e | 2014-04-08 16:57:45 -0600 | [diff] [blame] | 739 | } |
| 740 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 741 | // Viper will discover and load the configuration file from disk |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 742 | // and key/value stores, searching in one of the defined paths. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 743 | func ReadInConfig() error { return v.ReadInConfig() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 744 | func (v *Viper) ReadInConfig() error { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 745 | jww.INFO.Println("Attempting to read in config file") |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 746 | if !stringInSlice(v.getConfigType(), SupportedExts) { |
| 747 | return UnsupportedConfigError(v.getConfigType()) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 748 | } |
| 749 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 750 | file, err := ioutil.ReadFile(v.getConfigFile()) |
Joshua Rubin | 1a2e68e | 2014-04-08 16:57:45 -0600 | [diff] [blame] | 751 | if err != nil { |
| 752 | return err |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 753 | } |
Joshua Rubin | 1a2e68e | 2014-04-08 16:57:45 -0600 | [diff] [blame] | 754 | |
Kiril Zvezdarov | 54e585a | 2015-04-26 15:08:10 -0400 | [diff] [blame] | 755 | v.config = make(map[string]interface{}) |
| 756 | |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 757 | return v.marshalReader(bytes.NewReader(file), v.config) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 758 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 759 | |
oliveagle | f3482af | 2015-05-14 17:40:59 +0800 | [diff] [blame] | 760 | func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } |
| 761 | func (v *Viper) ReadConfig(in io.Reader) error { |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 762 | v.config = make(map[string]interface{}) |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 763 | return v.marshalReader(in, v.config) |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 764 | } |
| 765 | |
oliveagle | f3482af | 2015-05-14 17:40:59 +0800 | [diff] [blame] | 766 | // func ReadBufConfig(buf *bytes.Buffer) error { return v.ReadBufConfig(buf) } |
| 767 | // func (v *Viper) ReadBufConfig(buf *bytes.Buffer) error { |
| 768 | // v.config = make(map[string]interface{}) |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 769 | // return v.marshalReader(buf, v.config) |
oliveagle | f3482af | 2015-05-14 17:40:59 +0800 | [diff] [blame] | 770 | // } |
| 771 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 772 | // Attempts to get configuration from a remote source |
| 773 | // and read it in the remote configuration registry. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 774 | func ReadRemoteConfig() error { return v.ReadRemoteConfig() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 775 | func (v *Viper) ReadRemoteConfig() error { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 776 | err := v.getKeyValueConfig() |
Brian Ketelsen | c33e690 | 2014-10-27 10:14:45 -0400 | [diff] [blame] | 777 | if err != nil { |
| 778 | return err |
| 779 | } |
| 780 | return nil |
| 781 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 782 | |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 783 | func WatchRemoteConfig() error { return v.WatchRemoteConfig() } |
| 784 | func (v *Viper) WatchRemoteConfig() error { |
| 785 | err := v.watchKeyValueConfig() |
| 786 | if err != nil { |
| 787 | return err |
| 788 | } |
| 789 | return nil |
| 790 | } |
| 791 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 792 | // Marshall a Reader into a map |
| 793 | // Should probably be an unexported function |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 794 | func marshalReader(in io.Reader, c map[string]interface{}) error { |
| 795 | return v.marshalReader(in, c) |
| 796 | } |
| 797 | |
| 798 | func (v *Viper) marshalReader(in io.Reader, c map[string]interface{}) error { |
| 799 | return marshallConfigReader(in, c, v.getConfigType()) |
spf13 | bcb02e2 | 2014-04-05 01:19:39 -0400 | [diff] [blame] | 800 | } |
| 801 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 802 | func (v *Viper) insensitiviseMaps() { |
Anthony Fok | 5b0b926 | 2015-01-22 00:43:42 -0700 | [diff] [blame] | 803 | insensitiviseMap(v.config) |
| 804 | insensitiviseMap(v.defaults) |
| 805 | insensitiviseMap(v.override) |
| 806 | insensitiviseMap(v.kvstore) |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 807 | } |
| 808 | |
| 809 | // retrieve the first found remote configuration |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 810 | func (v *Viper) getKeyValueConfig() error { |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 811 | if RemoteConfig == nil { |
| 812 | return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") |
| 813 | } |
| 814 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 815 | for _, rp := range v.remoteProviders { |
| 816 | val, err := v.getRemoteConfig(rp) |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 817 | if err != nil { |
Brian Ketelsen | a28bee1 | 2014-10-26 09:42:03 -0400 | [diff] [blame] | 818 | continue |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 819 | } |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 820 | v.kvstore = val |
Brian Ketelsen | a28bee1 | 2014-10-26 09:42:03 -0400 | [diff] [blame] | 821 | return nil |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 822 | } |
Brian Ketelsen | d2d8f6c | 2014-10-27 11:03:11 -0400 | [diff] [blame] | 823 | return RemoteConfigError("No Files Found") |
| 824 | } |
| 825 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 826 | func (v *Viper) getRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) { |
Brian Ketelsen | a28bee1 | 2014-10-26 09:42:03 -0400 | [diff] [blame] | 827 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 828 | reader, err := RemoteConfig.Get(provider) |
Brian Ketelsen | a28bee1 | 2014-10-26 09:42:03 -0400 | [diff] [blame] | 829 | if err != nil { |
| 830 | return nil, err |
| 831 | } |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 832 | err = v.marshalReader(reader, v.kvstore) |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 833 | return v.kvstore, err |
Brian Ketelsen | a28bee1 | 2014-10-26 09:42:03 -0400 | [diff] [blame] | 834 | } |
| 835 | |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 836 | // retrieve the first found remote configuration |
| 837 | func (v *Viper) watchKeyValueConfig() error { |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 838 | for _, rp := range v.remoteProviders { |
| 839 | val, err := v.watchRemoteConfig(rp) |
| 840 | if err != nil { |
| 841 | continue |
| 842 | } |
| 843 | v.kvstore = val |
| 844 | return nil |
| 845 | } |
| 846 | return RemoteConfigError("No Files Found") |
| 847 | } |
| 848 | |
bep | be5ff3e | 2015-05-30 21:28:33 +0200 | [diff] [blame] | 849 | func (v *Viper) watchRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) { |
| 850 | reader, err := RemoteConfig.Watch(provider) |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 851 | if err != nil { |
| 852 | return nil, err |
| 853 | } |
Vlad Didenko | fa13732 | 2015-08-01 20:32:35 -0500 | [diff] [blame] | 854 | err = v.marshalReader(reader, v.kvstore) |
oliveagle | 3492885 | 2015-05-08 17:13:33 +0800 | [diff] [blame] | 855 | return v.kvstore, err |
| 856 | } |
| 857 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 858 | // Return all keys regardless where they are set |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 859 | func AllKeys() []string { return v.AllKeys() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 860 | func (v *Viper) AllKeys() []string { |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 861 | m := map[string]struct{}{} |
| 862 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 863 | for key, _ := range v.defaults { |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 864 | m[key] = struct{}{} |
| 865 | } |
| 866 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 867 | for key, _ := range v.config { |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 868 | m[key] = struct{}{} |
| 869 | } |
| 870 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 871 | for key, _ := range v.kvstore { |
Brian Ketelsen | 3d81824 | 2014-10-24 15:38:01 -0400 | [diff] [blame] | 872 | m[key] = struct{}{} |
| 873 | } |
| 874 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 875 | for key, _ := range v.override { |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 876 | m[key] = struct{}{} |
| 877 | } |
| 878 | |
| 879 | a := []string{} |
| 880 | for x, _ := range m { |
| 881 | a = append(a, x) |
| 882 | } |
| 883 | |
| 884 | return a |
| 885 | } |
| 886 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 887 | // Return all settings as a map[string]interface{} |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 888 | func AllSettings() map[string]interface{} { return v.AllSettings() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 889 | func (v *Viper) AllSettings() map[string]interface{} { |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 890 | m := map[string]interface{}{} |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 891 | for _, x := range v.AllKeys() { |
| 892 | m[x] = v.Get(x) |
spf13 | aacc304 | 2014-09-27 14:00:51 -0700 | [diff] [blame] | 893 | } |
| 894 | |
| 895 | return m |
| 896 | } |
| 897 | |
spf13 | 38c6d9e | 2014-07-11 10:42:07 -0400 | [diff] [blame] | 898 | // Name for the config file. |
| 899 | // Does not include extension. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 900 | func SetConfigName(in string) { v.SetConfigName(in) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 901 | func (v *Viper) SetConfigName(in string) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 902 | if in != "" { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 903 | v.configName = in |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 904 | } |
| 905 | } |
| 906 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 907 | // Sets the type of the configuration returned by the |
| 908 | // remote source, e.g. "json". |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 909 | func SetConfigType(in string) { v.SetConfigType(in) } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 910 | func (v *Viper) SetConfigType(in string) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 911 | if in != "" { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 912 | v.configType = in |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 913 | } |
| 914 | } |
| 915 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 916 | func (v *Viper) getConfigType() string { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 917 | if v.configType != "" { |
| 918 | return v.configType |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 919 | } |
| 920 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 921 | cf := v.getConfigFile() |
Andrew Cohen | 5aa1437 | 2014-11-13 14:43:51 -0500 | [diff] [blame] | 922 | ext := filepath.Ext(cf) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 923 | |
| 924 | if len(ext) > 1 { |
| 925 | return ext[1:] |
| 926 | } else { |
| 927 | return "" |
| 928 | } |
| 929 | } |
| 930 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 931 | func (v *Viper) getConfigFile() string { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 932 | // if explicitly set, then use it |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 933 | if v.configFile != "" { |
| 934 | return v.configFile |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 935 | } |
| 936 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 937 | cf, err := v.findConfigFile() |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 938 | if err != nil { |
Joshua Rubin | 1a2e68e | 2014-04-08 16:57:45 -0600 | [diff] [blame] | 939 | return "" |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 940 | } |
Joshua Rubin | 1a2e68e | 2014-04-08 16:57:45 -0600 | [diff] [blame] | 941 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 942 | v.configFile = cf |
| 943 | return v.getConfigFile() |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 944 | } |
| 945 | |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 946 | func (v *Viper) searchInPath(in string) (filename string) { |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 947 | jww.DEBUG.Println("Searching for config in ", in) |
| 948 | for _, ext := range SupportedExts { |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 949 | jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) |
| 950 | if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { |
| 951 | jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) |
| 952 | return filepath.Join(in, v.configName+"."+ext) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 953 | } |
| 954 | } |
| 955 | |
| 956 | return "" |
| 957 | } |
| 958 | |
spf13 | 18a87c0 | 2014-12-05 17:04:40 +0100 | [diff] [blame] | 959 | // search all configPaths for any config file. |
| 960 | // Returns the first path that exists (and is a config file) |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 961 | func (v *Viper) findConfigFile() (string, error) { |
Vlad Didenko | 9fca101 | 2015-08-01 19:37:27 -0500 | [diff] [blame] | 962 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 963 | jww.INFO.Println("Searching for config in ", v.configPaths) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 964 | |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 965 | for _, cp := range v.configPaths { |
| 966 | file := v.searchInPath(cp) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 967 | if file != "" { |
| 968 | return file, nil |
| 969 | } |
| 970 | } |
Vlad Didenko | 9fca101 | 2015-08-01 19:37:27 -0500 | [diff] [blame] | 971 | return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)} |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 972 | } |
| 973 | |
Kiril Zvezdarov | 9a0a669 | 2015-04-01 17:08:42 -0400 | [diff] [blame] | 974 | // Prints all configuration registries for debugging |
| 975 | // purposes. |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 976 | func Debug() { v.Debug() } |
Kiril Zvezdarov | 700eefa | 2015-02-17 09:22:37 -0500 | [diff] [blame] | 977 | func (v *Viper) Debug() { |
spf13 | 541c1f8 | 2014-05-29 16:48:24 -0400 | [diff] [blame] | 978 | fmt.Println("Aliases:") |
spf13 | 29f1858 | 2014-12-05 03:55:51 +0100 | [diff] [blame] | 979 | pretty.Println(v.aliases) |
Kiril Zvezdarov | b22fa2b | 2015-05-01 15:14:41 -0400 | [diff] [blame] | 980 | fmt.Println("Override:") |
| 981 | pretty.Println(v.override) |
Kiril Zvezdarov | 19ed496 | 2015-04-01 21:39:09 -0400 | [diff] [blame] | 982 | fmt.Println("PFlags") |
| 983 | pretty.Println(v.pflags) |
Kiril Zvezdarov | b22fa2b | 2015-05-01 15:14:41 -0400 | [diff] [blame] | 984 | fmt.Println("Env:") |
| 985 | pretty.Println(v.env) |
| 986 | fmt.Println("Key/Value Store:") |
| 987 | pretty.Println(v.kvstore) |
| 988 | fmt.Println("Config:") |
| 989 | pretty.Println(v.config) |
| 990 | fmt.Println("Defaults:") |
| 991 | pretty.Println(v.defaults) |
spf13 | 98be071 | 2014-04-04 17:21:59 -0400 | [diff] [blame] | 992 | } |