mynewt-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ccoll...@apache.org
Subject [6/7] incubator-mynewt-newt git commit: Replace LGPL-licensed yaml.v2 library with our own
Date Mon, 29 Feb 2016 22:48:52 GMT
Replace LGPL-licensed yaml.v2 library with our own


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/48051ebb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/48051ebb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/48051ebb

Branch: refs/heads/develop
Commit: 48051ebb4f283b62737af869402ebfee5c34e77d
Parents: 88b29b2
Author: Christopher Collins <ccollins476ad@gmail.com>
Authored: Mon Feb 29 14:34:55 2016 -0800
Committer: Christopher Collins <ccollins476ad@gmail.com>
Committed: Mon Feb 29 14:34:55 2016 -0800

----------------------------------------------------------------------
 newt/cli/pkglist.go    |    3 +-
 newt/cli/util.go       |    4 +-
 util/util.go           |    2 +-
 viper/LICENSE          |   21 +
 viper/README.md        |  620 ++++++++++
 viper/flags.go         |   57 +
 viper/flags_test.go    |   66 ++
 viper/remote/remote.go |   77 ++
 viper/util.go          |  223 ++++
 viper/viper.go         | 1305 +++++++++++++++++++++
 viper/viper_test.go    |  885 ++++++++++++++
 yaml/apic.go           |  767 ++++++++++++
 yaml/decode.go         |  274 +++++
 yaml/emitterc.go       | 1710 +++++++++++++++++++++++++++
 yaml/parserc.go        | 1121 ++++++++++++++++++
 yaml/readerc.go        |  419 +++++++
 yaml/scannerc.go       | 2735 +++++++++++++++++++++++++++++++++++++++++++
 yaml/shim.go           |   26 +
 yaml/writerc.go        |  114 ++
 yaml/yamlh.go          |  754 ++++++++++++
 yaml/yamlprivateh.go   |  198 ++++
 21 files changed, 11377 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/newt/cli/pkglist.go
----------------------------------------------------------------------
diff --git a/newt/cli/pkglist.go b/newt/cli/pkglist.go
index b88354c..3b377b6 100644
--- a/newt/cli/pkglist.go
+++ b/newt/cli/pkglist.go
@@ -29,8 +29,7 @@ import (
 	"strings"
 
 	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/util"
-
-	"github.com/spf13/viper"
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/viper"
 )
 
 type PkgList struct {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/newt/cli/util.go
----------------------------------------------------------------------
diff --git a/newt/cli/util.go b/newt/cli/util.go
index 8872adb..0c77049 100644
--- a/newt/cli/util.go
+++ b/newt/cli/util.go
@@ -23,8 +23,9 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/viper"
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/yaml"
 	"github.com/hashicorp/logutils"
-	"github.com/spf13/viper"
 	"io/ioutil"
 	"log"
 	"os"
@@ -115,6 +116,7 @@ func ReadConfig(path string, name string) (*viper.Viper, error) {
 	v.SetConfigType("yaml")
 	v.SetConfigName(name)
 	v.AddConfigPath(path)
+	yaml.SetFilename(path + "/" + name + ".yml")
 
 	err := v.ReadInConfig()
 	if err != nil {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/util/util.go
----------------------------------------------------------------------
diff --git a/util/util.go b/util/util.go
index e1a8ddd..7645f6b 100644
--- a/util/util.go
+++ b/util/util.go
@@ -20,8 +20,8 @@
 package util
 
 import (
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/viper"
 	"github.com/hashicorp/logutils"
-	"github.com/spf13/viper"
 	"log"
 	"os"
 	"runtime"

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/LICENSE
----------------------------------------------------------------------
diff --git a/viper/LICENSE b/viper/LICENSE
new file mode 100644
index 0000000..4527efb
--- /dev/null
+++ b/viper/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Steve Francia
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/README.md
----------------------------------------------------------------------
diff --git a/viper/README.md b/viper/README.md
new file mode 100644
index 0000000..cad242d
--- /dev/null
+++ b/viper/README.md
@@ -0,0 +1,620 @@
+![viper logo](https://cloud.githubusercontent.com/assets/173412/10886745/998df88a-8151-11e5-9448-4736db51020d.png)
+
+Go configuration with fangs!
+
+Many Go projects are built using Viper including:
+
+* [Hugo](http://gohugo.io)
+* [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
+* [Imgur's Incus](https://github.com/Imgur/incus)
+* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
+* [Docker Notary](https://github.com/docker/Notary)
+* [BloomApi](https://www.bloomapi.com/)
+* [DOIt](https://github.com/bryanl/doit)
+
+ [![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+
+## What is Viper?
+
+Viper is a complete configuration solution for go applications including 12 factor apps. It is designed
+to work within an application, and can handle all types of configuration needs
+and formats. It supports:
+
+* setting defaults
+* reading from JSON, TOML, YAML, HCL, and Java properties config files
+* live watching and re-reading of config files (optional)
+* reading from environment variables
+* reading from remote config systems (etcd or Consul), and watching changes
+* reading from command line flags
+* reading from buffer
+* setting explicit values
+
+Viper can be thought of as a registry for all of your applications
+configuration needs.
+
+## Why Viper?
+
+When building a modern application, you don’t want to worry about
+configuration file formats; you want to focus on building awesome software.
+Viper is here to help with that.
+
+Viper does the following for you:
+
+1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, or Java properties formats.
+2. Provide a mechanism to set default values for your different
+   configuration options.
+3. Provide a mechanism to set override values for options specified through
+   command line flags.
+4. Provide an alias system to easily rename parameters without breaking existing
+   code.
+5. Make it easy to tell the difference between when a user has provided a
+   command line or config file which is the same as the default.
+
+Viper uses the following precedence order. Each item takes precedence over the
+item below it:
+
+ * explicit call to Set
+ * flag
+ * env
+ * config
+ * key/value store
+ * default
+
+Viper configuration keys are case insensitive.
+
+## Putting Values into Viper
+
+### Establishing Defaults
+
+A good configuration system will support default values. A default value is not
+required for a key, but it's useful in the event that a key hasn’t been set via
+config file, environment variable, remote configuration or flag.
+
+Examples:
+
+```go
+viper.SetDefault("ContentDir", "content")
+viper.SetDefault("LayoutDir", "layouts")
+viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
+```
+
+### Reading Config Files
+
+Viper requires minimal configuration so it knows where to look for config files.
+Viper supports JSON, TOML, YAML, HCL, and Java Properties files. Viper can search multiple paths, but
+currently a single Viper instance only supports a single configuration file.
+Viper does not default to any configuration search paths leaving defaults decision
+to an application.
+
+Here is an example of how to use Viper to search for and read a configuration file.
+None of the specific paths are required, but at least one path should be provided
+where a configuration file is expected.
+
+```go
+viper.SetConfigName("config") // name of config file (without extension)
+viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
+viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
+viper.AddConfigPath(".")               // optionally look for config in the working directory
+err := viper.ReadInConfig() // Find and read the config file
+if err != nil { // Handle errors reading the config file
+	panic(fmt.Errorf("Fatal error config file: %s \n", err))
+}
+```
+
+### Watching and re-reading config files
+
+Viper supports the ability to have your application live read a config file while running.
+
+Gone are the days of needing to restart a server to have a config take effect,
+viper powered applications can read an update to a config file while running and
+not miss a beat.
+
+Simply tell the viper instance to watchConfig. 
+Optionally you can provide a function for Viper to run each time a change occurs.
+
+**Make sure you add all of the configPaths prior to calling `WatchConfig()`**
+
+```go
+		viper.WatchConfig()
+		viper.OnConfigChange(func(e fsnotify.Event) {
+			fmt.Println("Config file changed:", e.Name)
+		})
+```
+
+### Reading Config from io.Reader
+
+Viper predefines many configuration sources such as files, environment
+variables, flags, and remote K/V store, but you are not bound to them. You can
+also implement your own required configuration source and feed it to viper.
+
+```go
+viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
+
+// any approach to require this configuration into your program.
+var yamlExample = []byte(`
+Hacker: true
+name: steve
+hobbies:
+- skateboarding
+- snowboarding
+- go
+clothing:
+  jacket: leather
+  trousers: denim
+age: 35
+eyes : brown
+beard: true
+`)
+
+viper.ReadConfig(bytes.NewBuffer(yamlExample))
+
+viper.Get("name") // this would be "steve"
+```
+
+### Setting Overrides
+
+These could be from a command line flag, or from your own application logic.
+
+```go
+viper.Set("Verbose", true)
+viper.Set("LogFile", LogFile)
+```
+
+### Registering and Using Aliases
+
+Aliases permit a single value to be referenced by multiple keys
+
+```go
+viper.RegisterAlias("loud", "Verbose")
+
+viper.Set("verbose", true) // same result as next line
+viper.Set("loud", true)   // same result as prior line
+
+viper.GetBool("loud") // true
+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
+with ENV:
+
+ * `AutomaticEnv()`
+ * `BindEnv(string...) : error`
+ * `SetEnvPrefix(string)`
+ * `SetEnvReplacer(string...) *strings.Replacer`
+
+_When working with ENV variables, it’s important to recognize that Viper
+treats ENV variables as case sensitive._
+
+Viper provides a mechanism to try to ensure that ENV variables are unique. By
+using `SetEnvPrefix`, you can tell Viper to use add a prefix while reading from
+the environment variables. Both `BindEnv` and `AutomaticEnv` will use this
+prefix.
+
+`BindEnv` takes one or two parameters. The first parameter is the key name, the
+second is the name of the environment variable. The name of the environment
+variable is case sensitive. If the ENV variable name is not provided, then
+Viper will automatically assume that the key name matches the ENV variable name,
+but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV
+variable name, it **does not** automatically add the prefix.
+
+One important thing to recognize when working with ENV variables is that the
+value will be read each time it is accessed. Viper does not fix the value when
+the `BindEnv` is called.
+
+`AutomaticEnv` is a powerful helper especially when combined with
+`SetEnvPrefix`. When called, Viper will check for an environment variable any
+time a `viper.Get` request is made. It will apply the following rules. It will
+check for a environment variable with a name matching the key uppercased and
+prefixed with the `EnvPrefix` if set.
+
+`SetEnvReplacer` allows you to use a `strings.Replacer` object to rewrite Env
+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`.
+
+#### Env example
+
+```go
+SetEnvPrefix("spf") // will be uppercased automatically
+BindEnv("id")
+
+os.Setenv("SPF_ID", "13") // typically done outside of the app
+
+id := Get("id") // 13
+```
+
+### Working with Flags
+
+Viper has the ability to bind to flags. Specifically, Viper supports `Pflags`
+as used in the [Cobra](https://github.com/spf13/cobra) library.
+
+Like `BindEnv`, the value is not set when the binding method is called, but when
+it is accessed. This means you can bind as early as you want, even in an
+`init()` function.
+
+The `BindPFlag()` method provides this functionality.
+
+Example:
+
+```go
+serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
+viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
+```
+
+The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude
+the use of other packages that use the [flag](https://golang.org/pkg/flag/)
+package from the standard library. The pflag package can handle the flags
+defined for the flag package by importing these flags. This is accomplished
+by a calling a convenience function provided by the pflag package called
+AddGoFlagSet().
+
+Example:
+
+```go
+package main
+
+import (
+	"flag"
+	"github.com/spf13/pflag"
+)
+
+func main() {
+	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
+	pflag.Parse()
+    ...
+}
+```
+
+#### Flag interfaces
+
+Viper provides two Go interfaces to bind other flag systems if you don't use `Pflags`.
+
+`FlagValue` represents a single flag. This is a very simple example on how to implement this interface:
+
+```go
+type myFlag struct {}
+func (f myFlag) IsChanged() { return false }
+func (f myFlag) Name() { return "my-flag-name" }
+func (f myFlag) ValueString() { return "my-flag-value" }
+func (f myFlag) ValueType() { return "string" }
+```
+
+Once your flag implements this interface, you can simply tell Viper to bind it:
+
+```go
+viper.BindFlagValue("my-flag-name", myFlag{})
+```
+
+`FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface:
+
+```go
+type myFlagSet struct {
+	flags []myFlag
+}
+
+func (f myFlagSet) VisitAll(fn func(FlagValue)) {
+	for _, flag := range flags {
+		fn(flag)	
+	}
+}
+```
+
+Once your flag set implements this interface, you can simply tell Viper to bind it:
+
+```go
+fSet := myFlagSet{
+	flags: []myFlag{myFlag{}, myFlag{}},
+}
+viper.BindFlagValues("my-flags", fSet)
+```
+
+### Remote Key/Value Store Support
+
+To enable remote support in Viper, do a blank import of the `viper/remote`
+package:
+
+`import _ "github.com/spf13/viper/remote"`
+
+Viper will read a config string (as JSON, TOML, YAML or HCL) retrieved from a path
+in a Key/Value store such as etcd or Consul.  These values take precedence over
+default values, but are overridden by configuration values retrieved from disk,
+flags, or environment variables.
+
+Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve
+configuration from the K/V store, which means that you can store your
+configuration values encrypted and have them automatically decrypted if you have
+the correct gpg keyring.  Encryption is optional.
+
+You can use remote configuration in conjunction with local configuration, or
+independently of it.
+
+`crypt` has a command-line helper that you can use to put configurations in your
+K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001.
+
+```bash
+$ go get github.com/xordataexchange/crypt/bin/crypt
+$ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json
+```
+
+Confirm that your value was set:
+
+```bash
+$ crypt get -plaintext /config/hugo.json
+```
+
+See the `crypt` documentation for examples of how to set encrypted values, or
+how to use Consul.
+
+### Remote Key/Value Store Example - Unencrypted
+
+```go
+viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
+viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+err := viper.ReadRemoteConfig()
+```
+
+### Remote Key/Value Store Example - Encrypted
+
+```go
+viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
+viper.SetConfigType("json") // because there is no file extension in a stream of bytes,  supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+err := viper.ReadRemoteConfig()
+```
+
+### Watching Changes in etcd - Unencrypted
+
+```go
+// alternatively, you can create a new viper instance.
+var runtime_viper = viper.New()
+
+runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
+runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+
+// read from remote config the first time.
+err := runtime_viper.ReadRemoteConfig()
+
+// unmarshal config
+runtime_viper.Unmarshal(&runtime_conf)
+
+// open a goroutine to watch remote changes forever
+go func(){
+	for {
+	    time.Sleep(time.Second * 5) // delay after each request
+
+	    // currently, only tested with etcd support
+	    err := runtime_viper.WatchRemoteConfig()
+	    if err != nil {
+	        log.Errorf("unable to read remote config: %v", err)
+	        continue
+	    }
+
+	    // unmarshal new config into our runtime config struct. you can also use channel
+	    // to implement a signal to notify the system of the changes
+	    runtime_viper.Unmarshal(&runtime_conf)
+	}
+}()
+```
+
+## Getting Values From Viper
+
+In Viper, there are a few ways to get a value depending on the value's type.
+The following functions and methods exist:
+
+ * `Get(key string) : interface{}`
+ * `GetBool(key string) : bool`
+ * `GetFloat64(key string) : float64`
+ * `GetInt(key string) : int`
+ * `GetString(key string) : string`
+ * `GetStringMap(key string) : map[string]interface{}`
+ * `GetStringMapString(key string) : map[string]string`
+ * `GetStringSlice(key string) : []string`
+ * `GetTime(key string) : time.Time`
+ * `GetDuration(key string) : time.Duration`
+ * `IsSet(key string) : bool`
+
+One important thing to recognize is that each Get function will return a zero
+value if it’s not found. To check if a given key exists, the `IsSet()` method
+has been provided.
+
+Example:
+```go
+viper.GetString("logfile") // case-insensitive Setting & Getting
+if viper.GetBool("verbose") {
+    fmt.Println("verbose enabled")
+}
+```
+### Accessing nested keys
+
+The accessor methods also accept formatted paths to deeply nested keys. For
+example, if the following JSON file is loaded:
+
+```json
+{
+    "host": {
+        "address": "localhost",
+        "port": 5799
+    },
+    "datastore": {
+        "metric": {
+            "host": "127.0.0.1",
+            "port": 3099
+        },
+        "warehouse": {
+            "host": "198.0.0.1",
+            "port": 2112
+        }
+    }
+}
+
+```
+
+Viper can access a nested field by passing a `.` delimited path of keys:
+
+```go
+GetString("datastore.metric.host") // (returns "127.0.0.1")
+```
+
+This obeys the precedence rules established above; the search for the root key
+(in this example, `datastore`) will cascade through the remaining configuration
+registries until found. The search for the sub-keys (`metric` and `host`),
+however, will not.
+
+For example, if the `metric` key was not defined in the configuration loaded
+from file, but was defined in the defaults, Viper would return the zero value.
+
+On the other hand, if the primary key was not defined, Viper would go through
+the remaining registries looking for it.
+
+Lastly, if there exists a key that matches the delimited key path, its value
+will be returned instead. E.g.
+
+```json
+{
+    "datastore.metric.host": "0.0.0.0",
+    "host": {
+        "address": "localhost",
+        "port": 5799
+    },
+    "datastore": {
+        "metric": {
+            "host": "127.0.0.1",
+            "port": 3099
+        },
+        "warehouse": {
+            "host": "198.0.0.1",
+            "port": 2112
+        }
+    }
+}
+
+GetString("datastore.metric.host") //returns "0.0.0.0"
+```
+
+### Extract sub-tree
+
+Extract sub-tree from Viper.
+
+For example, `viper` represents:
+
+```json
+app:
+  cache1:
+    max-items: 100
+    item-size: 64
+  cache2:
+    max-items: 200
+    item-size: 80
+```
+
+After executing:
+
+```go
+subv := viper.Sub("app.cache1")
+```
+
+`subv` represents:
+
+```json
+max-items: 100
+item-size: 64
+```
+
+Suppose we have:
+
+```go
+func NewCache(cfg *Viper) *Cache {...}
+```
+
+which creates a cache based on config information formatted as `subv`.
+Now it's easy to create these 2 caches separately as:
+
+```go
+cfg1 := viper.Sub("app.cache1")
+cache1 := NewCache(cfg1)
+
+cfg2 := viper.Sub("app.cache2")
+cache2 := NewCache(cfg2)
+```
+
+### Unmarshaling
+
+You also have the option of Unmarshaling all or a specific value to a struct, map,
+etc.
+
+There are two methods to do this:
+
+ * `Unmarshal(rawVal interface{}) : error`
+ * `UnmarshalKey(key string, rawVal interface{}) : error`
+
+Example:
+
+```go
+type config struct {
+	Port int
+	Name string
+	PathMap string `mapstructure:"path_map"`
+}
+
+var C config
+
+err := Unmarshal(&C)
+if err != nil {
+	t.Fatalf("unable to decode into struct, %v", err)
+}
+```
+
+## Viper or Vipers?
+
+Viper comes ready to use out of the box. There is no configuration or
+initialization needed to begin using Viper. Since most applications will want
+to use a single central repository for their configuration, the viper package
+provides this. It is similar to a singleton.
+
+In all of the examples above, they demonstrate using viper in it's singleton
+style approach.
+
+### Working with multiple vipers
+
+You can also create many different vipers for use in your application. Each will
+have it’s own unique set of configurations and values. Each can read from a
+different config file, key value store, etc. All of the functions that viper
+package supports are mirrored as methods on a viper.
+
+Example:
+
+```go
+x := viper.New()
+y := viper.New()
+
+x.SetDefault("ContentDir", "content")
+y.SetDefault("ContentDir", "foobar")
+
+//...
+```
+
+When working with multiple vipers, it is up to the user to keep track of the
+different vipers.
+
+## Q & A
+
+Q: Why not INI files?
+
+A: Ini files are pretty awful. There’s no standard format, and they are hard to
+validate. Viper is designed to work with JSON, TOML or YAML files. If someone
+really wants to add this feature, I’d be happy to merge it. It’s easy to specify
+which formats your application will permit.
+
+Q: Why is it called “Viper”?
+
+A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
+to [Cobra](https://github.com/spf13/cobra). While both can operate completely
+independently, together they make a powerful pair to handle much of your
+application foundation needs.
+
+Q: Why is it called “Cobra”?
+
+A: Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)?

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/flags.go
----------------------------------------------------------------------
diff --git a/viper/flags.go b/viper/flags.go
new file mode 100644
index 0000000..dd32f4e
--- /dev/null
+++ b/viper/flags.go
@@ -0,0 +1,57 @@
+package viper
+
+import "github.com/spf13/pflag"
+
+// FlagValueSet is an interface that users can implement
+// to bind a set of flags to viper.
+type FlagValueSet interface {
+	VisitAll(fn func(FlagValue))
+}
+
+// FlagValue is an interface that users can implement
+// to bind different flags to viper.
+type FlagValue interface {
+	HasChanged() bool
+	Name() string
+	ValueString() string
+	ValueType() string
+}
+
+// pflagValueSet is a wrapper around *pflag.ValueSet
+// that implements FlagValueSet.
+type pflagValueSet struct {
+	flags *pflag.FlagSet
+}
+
+// VisitAll iterates over all *pflag.Flag inside the *pflag.FlagSet.
+func (p pflagValueSet) VisitAll(fn func(flag FlagValue)) {
+	p.flags.VisitAll(func(flag *pflag.Flag) {
+		fn(pflagValue{flag})
+	})
+}
+
+// pflagValue is a wrapper aroung *pflag.flag
+// that implements FlagValue
+type pflagValue struct {
+	flag *pflag.Flag
+}
+
+// HasChanges returns whether the flag has changes or not.
+func (p pflagValue) HasChanged() bool {
+	return p.flag.Changed
+}
+
+// Name returns the name of the flag.
+func (p pflagValue) Name() string {
+	return p.flag.Name
+}
+
+// ValueString returns the value of the flag as a string.
+func (p pflagValue) ValueString() string {
+	return p.flag.Value.String()
+}
+
+// ValueType returns the type of the flag as a string.
+func (p pflagValue) ValueType() string {
+	return p.flag.Value.Type()
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/flags_test.go
----------------------------------------------------------------------
diff --git a/viper/flags_test.go b/viper/flags_test.go
new file mode 100644
index 0000000..5489278
--- /dev/null
+++ b/viper/flags_test.go
@@ -0,0 +1,66 @@
+package viper
+
+import (
+	"testing"
+
+	"github.com/spf13/pflag"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestBindFlagValueSet(t *testing.T) {
+	flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
+
+	var testValues = map[string]*string{
+		"host":     nil,
+		"port":     nil,
+		"endpoint": nil,
+	}
+
+	var mutatedTestValues = map[string]string{
+		"host":     "localhost",
+		"port":     "6060",
+		"endpoint": "/public",
+	}
+
+	for name, _ := range testValues {
+		testValues[name] = flagSet.String(name, "", "test")
+	}
+
+	flagValueSet := pflagValueSet{flagSet}
+
+	err := BindFlagValues(flagValueSet)
+	if err != nil {
+		t.Fatalf("error binding flag set, %v", err)
+	}
+
+	flagSet.VisitAll(func(flag *pflag.Flag) {
+		flag.Value.Set(mutatedTestValues[flag.Name])
+		flag.Changed = true
+	})
+
+	for name, expected := range mutatedTestValues {
+		assert.Equal(t, Get(name), expected)
+	}
+}
+
+func TestBindFlagValue(t *testing.T) {
+	var testString = "testing"
+	var testValue = newStringValue(testString, &testString)
+
+	flag := &pflag.Flag{
+		Name:    "testflag",
+		Value:   testValue,
+		Changed: false,
+	}
+
+	flagValue := pflagValue{flag}
+	BindFlagValue("testvalue", flagValue)
+
+	assert.Equal(t, testString, Get("testvalue"))
+
+	flag.Value.Set("testing_mutate")
+	flag.Changed = true //hack for pflag usage
+
+	assert.Equal(t, "testing_mutate", Get("testvalue"))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/remote/remote.go
----------------------------------------------------------------------
diff --git a/viper/remote/remote.go b/viper/remote/remote.go
new file mode 100644
index 0000000..3c86afe
--- /dev/null
+++ b/viper/remote/remote.go
@@ -0,0 +1,77 @@
+// Copyright © 2015 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+// Package remote integrates the remote features of Viper.
+package remote
+
+import (
+	"bytes"
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/viper"
+	crypt "github.com/xordataexchange/crypt/config"
+	"io"
+	"os"
+)
+
+type remoteConfigProvider struct{}
+
+func (rc remoteConfigProvider) Get(rp viper.RemoteProvider) (io.Reader, error) {
+	cm, err := getConfigManager(rp)
+	if err != nil {
+		return nil, err
+	}
+	b, err := cm.Get(rp.Path())
+	if err != nil {
+		return nil, err
+	}
+	return bytes.NewReader(b), nil
+}
+
+func (rc remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error) {
+	cm, err := getConfigManager(rp)
+	if err != nil {
+		return nil, err
+	}
+	resp := <-cm.Watch(rp.Path(), nil)
+	err = resp.Error
+	if err != nil {
+		return nil, err
+	}
+
+	return bytes.NewReader(resp.Value), nil
+}
+
+func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
+
+	var cm crypt.ConfigManager
+	var err error
+
+	if rp.SecretKeyring() != "" {
+		kr, err := os.Open(rp.SecretKeyring())
+		defer kr.Close()
+		if err != nil {
+			return nil, err
+		}
+		if rp.Provider() == "etcd" {
+			cm, err = crypt.NewEtcdConfigManager([]string{rp.Endpoint()}, kr)
+		} else {
+			cm, err = crypt.NewConsulConfigManager([]string{rp.Endpoint()}, kr)
+		}
+	} else {
+		if rp.Provider() == "etcd" {
+			cm, err = crypt.NewStandardEtcdConfigManager([]string{rp.Endpoint()})
+		} else {
+			cm, err = crypt.NewStandardConsulConfigManager([]string{rp.Endpoint()})
+		}
+	}
+	if err != nil {
+		return nil, err
+	}
+	return cm, nil
+
+}
+
+func init() {
+	viper.RemoteConfig = &remoteConfigProvider{}
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/util.go
----------------------------------------------------------------------
diff --git a/viper/util.go b/viper/util.go
new file mode 100644
index 0000000..8039778
--- /dev/null
+++ b/viper/util.go
@@ -0,0 +1,223 @@
+// This file has been changed slightly from the original.  The change is to use
+// the mynewt yaml library rather than yaml.v2.  This file retains the original
+// copyright and license.
+//
+// Copyright © 2014 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style license that can be
+// found in the LICENSE file.
+
+// Viper is a application configuration system.
+// It believes that applications can be configured a variety of ways
+// via flags, ENVIRONMENT variables, configuration files retrieved
+// from the file system, or a remote key/value store.
+
+package viper
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"unicode"
+
+	"git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/yaml"
+	"github.com/BurntSushi/toml"
+	"github.com/hashicorp/hcl"
+	"github.com/magiconair/properties"
+	"github.com/spf13/cast"
+	jww "github.com/spf13/jwalterweatherman"
+)
+
+// Denotes failing to parse configuration file.
+type ConfigParseError struct {
+	err error
+}
+
+// Returns the formatted configuration error.
+func (pe ConfigParseError) Error() string {
+	return fmt.Sprintf("While parsing config: %s", pe.err.Error())
+}
+
+func insensitiviseMap(m map[string]interface{}) {
+	for key, val := range m {
+		lower := strings.ToLower(key)
+		if key != lower {
+			delete(m, key)
+			m[lower] = val
+		}
+	}
+}
+
+func absPathify(inPath string) string {
+	jww.INFO.Println("Trying to resolve absolute path to", inPath)
+
+	if strings.HasPrefix(inPath, "$HOME") {
+		inPath = userHomeDir() + inPath[5:]
+	}
+
+	if strings.HasPrefix(inPath, "$") {
+		end := strings.Index(inPath, string(os.PathSeparator))
+		inPath = os.Getenv(inPath[1:end]) + inPath[end:]
+	}
+
+	if filepath.IsAbs(inPath) {
+		return filepath.Clean(inPath)
+	}
+
+	p, err := filepath.Abs(inPath)
+	if err == nil {
+		return filepath.Clean(p)
+	} else {
+		jww.ERROR.Println("Couldn't discover absolute path")
+		jww.ERROR.Println(err)
+	}
+	return ""
+}
+
+// Check if File / Directory Exists
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+func stringInSlice(a string, list []string) bool {
+	for _, b := range list {
+		if b == a {
+			return true
+		}
+	}
+	return false
+}
+
+func userHomeDir() string {
+	if runtime.GOOS == "windows" {
+		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+		if home == "" {
+			home = os.Getenv("USERPROFILE")
+		}
+		return home
+	}
+	return os.Getenv("HOME")
+}
+
+func findCWD() (string, error) {
+	serverFile, err := filepath.Abs(os.Args[0])
+
+	if err != nil {
+		return "", fmt.Errorf("Can't get absolute path for executable: %v", err)
+	}
+
+	path := filepath.Dir(serverFile)
+	realFile, err := filepath.EvalSymlinks(serverFile)
+
+	if err != nil {
+		if _, err = os.Stat(serverFile + ".exe"); err == nil {
+			realFile = filepath.Clean(serverFile + ".exe")
+		}
+	}
+
+	if err == nil && realFile != serverFile {
+		path = filepath.Dir(realFile)
+	}
+
+	return path, nil
+}
+
+func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType string) error {
+	buf := new(bytes.Buffer)
+	buf.ReadFrom(in)
+
+	switch strings.ToLower(configType) {
+	case "yaml", "yml":
+		if err := yaml.Unmarshal(buf.Bytes(), c); err != nil {
+			return ConfigParseError{err}
+		}
+
+	case "json":
+		if err := json.Unmarshal(buf.Bytes(), &c); err != nil {
+			return ConfigParseError{err}
+		}
+
+	case "hcl":
+		obj, err := hcl.Parse(string(buf.Bytes()))
+		if err != nil {
+			return ConfigParseError{err}
+		}
+		if err = hcl.DecodeObject(&c, obj); err != nil {
+			return ConfigParseError{err}
+		}
+
+	case "toml":
+		if _, err := toml.Decode(buf.String(), &c); err != nil {
+			return ConfigParseError{err}
+		}
+
+	case "properties", "props", "prop":
+		var p *properties.Properties
+		var err error
+		if p, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil {
+			return ConfigParseError{err}
+		}
+		for _, key := range p.Keys() {
+			value, _ := p.Get(key)
+			c[key] = value
+		}
+	}
+
+	insensitiviseMap(c)
+	return nil
+}
+
+func safeMul(a, b uint) uint {
+	c := a * b
+	if a > 1 && b > 1 && c/b != a {
+		return 0
+	}
+	return c
+}
+
+// parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes
+func parseSizeInBytes(sizeStr string) uint {
+	sizeStr = strings.TrimSpace(sizeStr)
+	lastChar := len(sizeStr) - 1
+	multiplier := uint(1)
+
+	if lastChar > 0 {
+		if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' {
+			if lastChar > 1 {
+				switch unicode.ToLower(rune(sizeStr[lastChar-1])) {
+				case 'k':
+					multiplier = 1 << 10
+					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
+				case 'm':
+					multiplier = 1 << 20
+					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
+				case 'g':
+					multiplier = 1 << 30
+					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
+				default:
+					multiplier = 1
+					sizeStr = strings.TrimSpace(sizeStr[:lastChar])
+				}
+			}
+		}
+	}
+
+	size := cast.ToInt(sizeStr)
+	if size < 0 {
+		size = 0
+	}
+
+	return safeMul(uint(size), multiplier)
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/48051ebb/viper/viper.go
----------------------------------------------------------------------
diff --git a/viper/viper.go b/viper/viper.go
new file mode 100644
index 0000000..b95c132
--- /dev/null
+++ b/viper/viper.go
@@ -0,0 +1,1305 @@
+// Copyright © 2014 Steve Francia <spf@spf13.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+// Viper is a application configuration system.
+// It believes that applications can be configured a variety of ways
+// via flags, ENVIRONMENT variables, configuration files retrieved
+// from the file system, or a remote key/value store.
+
+// Each item takes precedence over the item below it:
+
+// overrides
+// flag
+// env
+// config
+// key/value store
+// default
+
+package viper
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"time"
+
+	"github.com/kr/pretty"
+	"github.com/mitchellh/mapstructure"
+	"github.com/spf13/cast"
+	jww "github.com/spf13/jwalterweatherman"
+	"github.com/spf13/pflag"
+	"gopkg.in/fsnotify.v1"
+)
+
+var v *Viper
+
+func init() {
+	v = New()
+}
+
+type remoteConfigFactory interface {
+	Get(rp RemoteProvider) (io.Reader, error)
+	Watch(rp RemoteProvider) (io.Reader, error)
+}
+
+// RemoteConfig is optional, see the remote package
+var RemoteConfig remoteConfigFactory
+
+// Denotes encountering an unsupported
+// configuration filetype.
+type UnsupportedConfigError string
+
+// Returns the formatted configuration error.
+func (str UnsupportedConfigError) Error() string {
+	return fmt.Sprintf("Unsupported Config Type %q", string(str))
+}
+
+// Denotes encountering an unsupported remote
+// provider. Currently only etcd and Consul are
+// supported.
+type UnsupportedRemoteProviderError string
+
+// Returns the formatted remote provider error.
+func (str UnsupportedRemoteProviderError) Error() string {
+	return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
+}
+
+// Denotes encountering an error while trying to
+// pull the configuration from the remote provider.
+type RemoteConfigError string
+
+// Returns the formatted remote provider error
+func (rce RemoteConfigError) Error() string {
+	return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
+}
+
+// Denotes failing to find configuration file.
+type ConfigFileNotFoundError struct {
+	name, locations string
+}
+
+// Returns the formatted configuration error.
+func (fnfe ConfigFileNotFoundError) Error() string {
+	return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
+}
+
+// Viper is a prioritized configuration registry. It
+// maintains a set of configuration sources, fetches
+// values to populate those, and provides them according
+// to the source's priority.
+// The priority of the sources is the following:
+// 1. overrides
+// 2. flags
+// 3. env. variables
+// 4. config file
+// 5. key/value store
+// 6. defaults
+//
+// For example, if values from the following sources were loaded:
+//
+//  Defaults : {
+//  	"secret": "",
+//  	"user": "default",
+// 	"endpoint": "https://localhost"
+//  }
+//  Config : {
+//  	"user": "root"
+//	"secret": "defaultsecret"
+//  }
+//  Env : {
+//  	"secret": "somesecretkey"
+//  }
+//
+// The resulting config will have the following values:
+//
+//	{
+//		"secret": "somesecretkey",
+//		"user": "root",
+//		"endpoint": "https://localhost"
+//	}
+type Viper struct {
+	// Delimiter that separates a list of keys
+	// used to access a nested value in one go
+	keyDelim string
+
+	// A set of paths to look for the config file in
+	configPaths []string
+
+	// A set of remote providers to search for the configuration
+	remoteProviders []*defaultRemoteProvider
+
+	// Name of file to look for inside the path
+	configName string
+	configFile string
+	configType string
+	envPrefix  string
+
+	automaticEnvApplied bool
+	envKeyReplacer      *strings.Replacer
+
+	config         map[string]interface{}
+	override       map[string]interface{}
+	defaults       map[string]interface{}
+	kvstore        map[string]interface{}
+	pflags         map[string]FlagValue
+	env            map[string]string
+	aliases        map[string]string
+	typeByDefValue bool
+
+	onConfigChange func(fsnotify.Event)
+}
+
+// Returns an initialized Viper instance.
+func New() *Viper {
+	v := new(Viper)
+	v.keyDelim = "."
+	v.configName = "config"
+	v.config = make(map[string]interface{})
+	v.override = make(map[string]interface{})
+	v.defaults = make(map[string]interface{})
+	v.kvstore = make(map[string]interface{})
+	v.pflags = make(map[string]FlagValue)
+	v.env = make(map[string]string)
+	v.aliases = make(map[string]string)
+	v.typeByDefValue = false
+
+	return v
+}
+
+// Intended for testing, will reset all to default settings.
+// In the public interface for the viper package so applications
+// can use it in their testing as well.
+func Reset() {
+	v = New()
+	SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"}
+	SupportedRemoteProviders = []string{"etcd", "consul"}
+}
+
+type defaultRemoteProvider struct {
+	provider      string
+	endpoint      string
+	path          string
+	secretKeyring string
+}
+
+func (rp defaultRemoteProvider) Provider() string {
+	return rp.provider
+}
+
+func (rp defaultRemoteProvider) Endpoint() string {
+	return rp.endpoint
+}
+
+func (rp defaultRemoteProvider) Path() string {
+	return rp.path
+}
+
+func (rp defaultRemoteProvider) SecretKeyring() string {
+	return rp.secretKeyring
+}
+
+// RemoteProvider stores the configuration necessary
+// to connect to a remote key/value store.
+// Optional secretKeyring to unencrypt encrypted values
+// can be provided.
+type RemoteProvider interface {
+	Provider() string
+	Endpoint() string
+	Path() string
+	SecretKeyring() string
+}
+
+// Universally supported extensions.
+var SupportedExts []string = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"}
+
+// Universally supported remote providers.
+var SupportedRemoteProviders []string = []string{"etcd", "consul"}
+
+func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
+func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
+	v.onConfigChange = run
+}
+
+func WatchConfig() { v.WatchConfig() }
+func (v *Viper) WatchConfig() {
+	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
+		configFile := filepath.Clean(v.getConfigFile())
+		configDir, _ := filepath.Split(configFile)
+
+		done := make(chan bool)
+		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)
+							}
+							v.onConfigChange(event)
+						}
+					}
+				case err := <-watcher.Errors:
+					log.Println("error:", err)
+				}
+			}
+		}()
+
+		watcher.Add(configDir)
+		<-done
+	}()
+}
+
+// Explicitly define the path, name and extension of the config file
+// Viper will use this and not check any of the config paths
+func SetConfigFile(in string) { v.SetConfigFile(in) }
+func (v *Viper) SetConfigFile(in string) {
+	if in != "" {
+		v.configFile = in
+	}
+}
+
+// Define a prefix that ENVIRONMENT variables will use.
+// E.g. if your prefix is "spf", the env registry
+// will look for env. variables that start with "SPF_"
+func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
+func (v *Viper) SetEnvPrefix(in string) {
+	if in != "" {
+		v.envPrefix = in
+	}
+}
+
+func (v *Viper) mergeWithEnvPrefix(in string) string {
+	if v.envPrefix != "" {
+		return strings.ToUpper(v.envPrefix + "_" + in)
+	}
+
+	return strings.ToUpper(in)
+}
+
+// TODO: should getEnv logic be moved into find(). Can generalize the use of
+// rewriting keys many things, Ex: Get('someKey') -> some_key
+// (cammel case to snake case for JSON keys perhaps)
+
+// getEnv s a wrapper around os.Getenv which replaces characters in the original
+// key. This allows env vars which have different keys then the config object
+// keys
+func (v *Viper) getEnv(key string) string {
+	if v.envKeyReplacer != nil {
+		key = v.envKeyReplacer.Replace(key)
+	}
+	return os.Getenv(key)
+}
+
+// Return the file used to populate the config registry
+func ConfigFileUsed() string            { return v.ConfigFileUsed() }
+func (v *Viper) ConfigFileUsed() string { return v.configFile }
+
+// Add a path for Viper to search for the config file in.
+// Can be called multiple times to define multiple search paths.
+func AddConfigPath(in string) { v.AddConfigPath(in) }
+func (v *Viper) AddConfigPath(in string) {
+	if in != "" {
+		absin := absPathify(in)
+		jww.INFO.Println("adding", absin, "to paths to search")
+		if !stringInSlice(absin, v.configPaths) {
+			v.configPaths = append(v.configPaths, absin)
+		}
+	}
+}
+
+// AddRemoteProvider adds a remote configuration source.
+// Remote Providers are searched in the order they are added.
+// provider is a string value, "etcd" or "consul" are currently supported.
+// endpoint is the url.  etcd requires http://ip:port  consul requires ip:port
+// path is the path in the k/v store to retrieve configuration
+// To retrieve a config file called myapp.json from /configs/myapp.json
+// you should set path to /configs and set config name (SetConfigName()) to
+// "myapp"
+func AddRemoteProvider(provider, endpoint, path string) error {
+	return v.AddRemoteProvider(provider, endpoint, path)
+}
+func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
+	if !stringInSlice(provider, SupportedRemoteProviders) {
+		return UnsupportedRemoteProviderError(provider)
+	}
+	if provider != "" && endpoint != "" {
+		jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
+		rp := &defaultRemoteProvider{
+			endpoint: endpoint,
+			provider: provider,
+			path:     path,
+		}
+		if !v.providerPathExists(rp) {
+			v.remoteProviders = append(v.remoteProviders, rp)
+		}
+	}
+	return nil
+}
+
+// AddSecureRemoteProvider adds a remote configuration source.
+// Secure Remote Providers are searched in the order they are added.
+// provider is a string value, "etcd" or "consul" are currently supported.
+// endpoint is the url.  etcd requires http://ip:port  consul requires ip:port
+// secretkeyring is the filepath to your openpgp secret keyring.  e.g. /etc/secrets/myring.gpg
+// path is the path in the k/v store to retrieve configuration
+// To retrieve a config file called myapp.json from /configs/myapp.json
+// you should set path to /configs and set config name (SetConfigName()) to
+// "myapp"
+// Secure Remote Providers are implemented with github.com/xordataexchange/crypt
+func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
+	return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
+}
+
+func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
+	if !stringInSlice(provider, SupportedRemoteProviders) {
+		return UnsupportedRemoteProviderError(provider)
+	}
+	if provider != "" && endpoint != "" {
+		jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
+		rp := &defaultRemoteProvider{
+			endpoint:      endpoint,
+			provider:      provider,
+			path:          path,
+			secretKeyring: secretkeyring,
+		}
+		if !v.providerPathExists(rp) {
+			v.remoteProviders = append(v.remoteProviders, rp)
+		}
+	}
+	return nil
+}
+
+func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
+	for _, y := range v.remoteProviders {
+		if reflect.DeepEqual(y, p) {
+			return true
+		}
+	}
+	return false
+}
+
+func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
+
+	if len(path) == 0 {
+		return source
+	}
+
+	var ok bool
+	var next interface{}
+	for k, v := range source {
+		if strings.ToLower(k) == strings.ToLower(path[0]) {
+			ok = true
+			next = v
+			break
+		}
+	}
+
+	if ok {
+		switch next.(type) {
+		case map[interface{}]interface{}:
+			return v.searchMap(cast.ToStringMap(next), path[1:])
+		case map[string]interface{}:
+			// Type assertion is safe here since it is only reached
+			// if the type of `next` is the same as the type being asserted
+			return v.searchMap(next.(map[string]interface{}), path[1:])
+		default:
+			return next
+		}
+	} else {
+		return nil
+	}
+}
+
+// SetTypeByDefaultValue enables or disables the inference of a key value's
+// type when the Get function is used based upon a key's default value as
+// opposed to the value returned based on the normal fetch logic.
+//
+// For example, if a key has a default value of []string{} and the same key
+// is set via an environment variable to "a b c", a call to the Get function
+// would return a string slice for the key if the key's type is inferred by
+// the default value and the Get function would return:
+//
+//   []string {"a", "b", "c"}
+//
+// Otherwise the Get function would return:
+//
+//   "a b c"
+func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
+func (v *Viper) SetTypeByDefaultValue(enable bool) {
+	v.typeByDefValue = enable
+}
+
+// Viper is essentially repository for configurations
+// Get can retrieve any value given the key to use
+// Get has the behavior of returning the value associated with the first
+// place from where it is set. Viper will check in the following order:
+// override, flag, env, config file, key/value store, default
+//
+// Get returns an interface. For a specific value use one of the Get____ methods.
+func Get(key string) interface{} { return v.Get(key) }
+func (v *Viper) Get(key string) interface{} {
+	path := strings.Split(key, v.keyDelim)
+
+	lcaseKey := strings.ToLower(key)
+	val := v.find(lcaseKey)
+
+	if val == nil {
+		source := v.find(strings.ToLower(path[0]))
+		if source != nil {
+			if reflect.TypeOf(source).Kind() == reflect.Map {
+				val = v.searchMap(cast.ToStringMap(source), path[1:])
+			}
+		}
+	}
+
+	// if no other value is returned and a flag does exist for the value,
+	// get the flag's value even if the flag's value has not changed
+	if val == nil {
+		if flag, exists := v.pflags[lcaseKey]; exists {
+			jww.TRACE.Println(key, "get pflag default", val)
+			switch flag.ValueType() {
+			case "int", "int8", "int16", "int32", "int64":
+				val = cast.ToInt(flag.ValueString())
+			case "bool":
+				val = cast.ToBool(flag.ValueString())
+			default:
+				val = flag.ValueString()
+			}
+		}
+	}
+
+	if val == nil {
+		return nil
+	}
+
+	var valType interface{}
+	if !v.typeByDefValue {
+		valType = val
+	} else {
+		defVal, defExists := v.defaults[lcaseKey]
+		if defExists {
+			valType = defVal
+		} else {
+			valType = val
+		}
+	}
+
+	switch valType.(type) {
+	case bool:
+		return cast.ToBool(val)
+	case string:
+		return cast.ToString(val)
+	case int64, int32, int16, int8, int:
+		return cast.ToInt(val)
+	case float64, float32:
+		return cast.ToFloat64(val)
+	case time.Time:
+		return cast.ToTime(val)
+	case time.Duration:
+		return cast.ToDuration(val)
+	case []string:
+		return cast.ToStringSlice(val)
+	}
+	return val
+}
+
+// Returns new Viper instance representing a sub tree of this instance
+func Sub(key string) *Viper { return v.Sub(key) }
+func (v *Viper) Sub(key string) *Viper {
+	subv := New()
+	data := v.Get(key)
+	if reflect.TypeOf(data).Kind() == reflect.Map {
+		subv.config = cast.ToStringMap(data)
+		return subv
+	} else {
+		return nil
+	}
+}
+
+// Returns the value associated with the key as a string
+func GetString(key string) string { return v.GetString(key) }
+func (v *Viper) GetString(key string) string {
+	return cast.ToString(v.Get(key))
+}
+
+// Returns the value associated with the key asa boolean
+func GetBool(key string) bool { return v.GetBool(key) }
+func (v *Viper) GetBool(key string) bool {
+	return cast.ToBool(v.Get(key))
+}
+
+// Returns the value associated with the key as an integer
+func GetInt(key string) int { return v.GetInt(key) }
+func (v *Viper) GetInt(key string) int {
+	return cast.ToInt(v.Get(key))
+}
+
+// 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 {
+	return cast.ToFloat64(v.Get(key))
+}
+
+// Returns the value associated with the key as time
+func GetTime(key string) time.Time { return v.GetTime(key) }
+func (v *Viper) GetTime(key string) time.Time {
+	return cast.ToTime(v.Get(key))
+}
+
+// Returns the value associated with the key as a duration
+func GetDuration(key string) time.Duration { return v.GetDuration(key) }
+func (v *Viper) GetDuration(key string) time.Duration {
+	return cast.ToDuration(v.Get(key))
+}
+
+// Returns the value associated with the key as a slice of strings
+func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
+func (v *Viper) GetStringSlice(key string) []string {
+	return cast.ToStringSlice(v.Get(key))
+}
+
+// Returns the value associated with the key as a map of interfaces
+func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
+func (v *Viper) GetStringMap(key string) map[string]interface{} {
+	return cast.ToStringMap(v.Get(key))
+}
+
+// Returns the value associated with the key as a map of strings
+func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
+func (v *Viper) GetStringMapString(key string) map[string]string {
+	return cast.ToStringMapString(v.Get(key))
+}
+
+// Returns the value associated with the key as a map to a slice of strings.
+func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
+func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
+	return cast.ToStringMapStringSlice(v.Get(key))
+}
+
+// Returns the size of the value associated with the given key
+// in bytes.
+func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) }
+func (v *Viper) GetSizeInBytes(key string) uint {
+	sizeStr := cast.ToString(v.Get(key))
+	return parseSizeInBytes(sizeStr)
+}
+
+// Takes a single key and unmarshals it into a Struct
+func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) }
+func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error {
+	return mapstructure.Decode(v.Get(key), rawVal)
+}
+
+// Unmarshals the config into a Struct. Make sure that the tags
+// on the fields of the structure are properly set.
+func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) }
+func (v *Viper) Unmarshal(rawVal interface{}) error {
+	err := mapstructure.WeakDecode(v.AllSettings(), rawVal)
+
+	if err != nil {
+		return err
+	}
+
+	v.insensitiviseMaps()
+
+	return nil
+}
+
+// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
+// while erroring on non existing vals in the destination struct
+func weakDecodeExact(input, output interface{}) error {
+	config := &mapstructure.DecoderConfig{
+		ErrorUnused:      true,
+		Metadata:         nil,
+		Result:           output,
+		WeaklyTypedInput: true,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return err
+	}
+	return decoder.Decode(input)
+}
+
+// Unmarshals the config into a Struct, erroring if a field is non-existant
+// in the destination struct
+func (v *Viper) UnmarshalExact(rawVal interface{}) error {
+	err := weakDecodeExact(v.AllSettings(), rawVal)
+
+	if err != nil {
+		return err
+	}
+
+	v.insensitiviseMaps()
+
+	return nil
+}
+
+// Bind a full flag set to the configuration, using each flag's long
+// name as the config key.
+func BindPFlags(flags *pflag.FlagSet) (err error) { return v.BindPFlags(flags) }
+func (v *Viper) BindPFlags(flags *pflag.FlagSet) (err error) {
+	return v.BindFlagValues(pflagValueSet{flags})
+}
+
+// Bind a specific key to a pflag (as used by cobra)
+// Example(where serverCmd is a Cobra instance):
+//
+//	 serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
+//	 Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
+//
+func BindPFlag(key string, flag *pflag.Flag) (err error) { return v.BindPFlag(key, flag) }
+func (v *Viper) BindPFlag(key string, flag *pflag.Flag) (err error) {
+	return v.BindFlagValue(key, pflagValue{flag})
+}
+
+// Bind a full FlagValue set to the configuration, using each flag's long
+// name as the config key.
+func BindFlagValues(flags FlagValueSet) (err error) { return v.BindFlagValues(flags) }
+func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
+	flags.VisitAll(func(flag FlagValue) {
+		if err = v.BindFlagValue(flag.Name(), flag); err != nil {
+			return
+		}
+	})
+	return nil
+}
+
+// Bind a specific key to a FlagValue.
+// Example(where serverCmd is a Cobra instance):
+//
+//	 serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
+//	 Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port"))
+//
+func BindFlagValue(key string, flag FlagValue) (err error) { return v.BindFlagValue(key, flag) }
+func (v *Viper) BindFlagValue(key string, flag FlagValue) (err error) {
+	if flag == nil {
+		return fmt.Errorf("flag for %q is nil", key)
+	}
+	v.pflags[strings.ToLower(key)] = flag
+	return nil
+}
+
+// Binds a Viper key to a ENV variable
+// ENV variables are case sensitive
+// If only a key is provided, it will use the env key matching the key, uppercased.
+// EnvPrefix will be used when set when env name is not provided.
+func BindEnv(input ...string) (err error) { return v.BindEnv(input...) }
+func (v *Viper) BindEnv(input ...string) (err error) {
+	var key, envkey string
+	if len(input) == 0 {
+		return fmt.Errorf("BindEnv missing key to bind to")
+	}
+
+	key = strings.ToLower(input[0])
+
+	if len(input) == 1 {
+		envkey = v.mergeWithEnvPrefix(key)
+	} else {
+		envkey = input[1]
+	}
+
+	v.env[key] = envkey
+
+	return nil
+}
+
+// Given a key, find the value
+// Viper will check in the following order:
+// flag, env, config file, key/value store, default
+// Viper will check to see if an alias exists first
+func (v *Viper) find(key string) interface{} {
+	var val interface{}
+	var exists bool
+
+	// if the requested key is an alias, then return the proper key
+	key = v.realKey(key)
+
+	// PFlag Override first
+	flag, exists := v.pflags[key]
+	if exists && flag.HasChanged() {
+		jww.TRACE.Println(key, "found in override (via pflag):", flag.ValueString())
+		switch flag.ValueType() {
+		case "int", "int8", "int16", "int32", "int64":
+			return cast.ToInt(flag.ValueString())
+		case "bool":
+			return cast.ToBool(flag.ValueString())
+		default:
+			return flag.ValueString()
+		}
+	}
+
+	val, exists = v.override[key]
+	if exists {
+		jww.TRACE.Println(key, "found in override:", val)
+		return val
+	}
+
+	if v.automaticEnvApplied {
+		// even if it hasn't been registered, if automaticEnv is used,
+		// check any Get request
+		if val = v.getEnv(v.mergeWithEnvPrefix(key)); val != "" {
+			jww.TRACE.Println(key, "found in environment with val:", val)
+			return val
+		}
+	}
+
+	envkey, exists := v.env[key]
+	if exists {
+		jww.TRACE.Println(key, "registered as env var", envkey)
+		if val = v.getEnv(envkey); val != "" {
+			jww.TRACE.Println(envkey, "found in environment with val:", val)
+			return val
+		} else {
+			jww.TRACE.Println(envkey, "env value unset:")
+		}
+	}
+
+	val, exists = v.config[key]
+	if exists {
+		jww.TRACE.Println(key, "found in config:", val)
+		return val
+	}
+
+	// Test for nested config parameter
+	if strings.Contains(key, v.keyDelim) {
+		path := strings.Split(key, v.keyDelim)
+
+		source := v.find(path[0])
+		if source != nil {
+			if reflect.TypeOf(source).Kind() == reflect.Map {
+				val := v.searchMap(cast.ToStringMap(source), path[1:])
+				jww.TRACE.Println(key, "found in nested config:", val)
+				return val
+			}
+		}
+	}
+
+	val, exists = v.kvstore[key]
+	if exists {
+		jww.TRACE.Println(key, "found in key/value store:", val)
+		return val
+	}
+
+	val, exists = v.defaults[key]
+	if exists {
+		jww.TRACE.Println(key, "found in defaults:", val)
+		return val
+	}
+
+	return nil
+}
+
+// Check to see if the key has been set in any of the data locations
+func IsSet(key string) bool { return v.IsSet(key) }
+func (v *Viper) IsSet(key string) bool {
+	path := strings.Split(key, v.keyDelim)
+
+	lcaseKey := strings.ToLower(key)
+	val := v.find(lcaseKey)
+
+	if val == nil {
+		source := v.find(strings.ToLower(path[0]))
+		if source != nil {
+			if reflect.TypeOf(source).Kind() == reflect.Map {
+				val = v.searchMap(cast.ToStringMap(source), path[1:])
+			}
+		}
+	}
+
+	return val != nil
+}
+
+// Have Viper check ENV variables for all
+// keys set in config, default & flags
+func AutomaticEnv() { v.AutomaticEnv() }
+func (v *Viper) AutomaticEnv() {
+	v.automaticEnvApplied = true
+}
+
+// SetEnvKeyReplacer sets the strings.Replacer on the viper object
+// Useful for mapping an environmental variable to a key that does
+// not match it.
+func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) }
+func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
+	v.envKeyReplacer = r
+}
+
+// Aliases provide another accessor for the same key.
+// This enables one to change a name without breaking the application
+func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) }
+func (v *Viper) RegisterAlias(alias string, key string) {
+	v.registerAlias(alias, strings.ToLower(key))
+}
+
+func (v *Viper) registerAlias(alias string, key string) {
+	alias = strings.ToLower(alias)
+	if alias != key && alias != v.realKey(key) {
+		_, exists := v.aliases[alias]
+
+		if !exists {
+			// if we alias something that exists in one of the maps to another
+			// name, we'll never be able to get that value using the original
+			// name, so move the config value to the new realkey.
+			if val, ok := v.config[alias]; ok {
+				delete(v.config, alias)
+				v.config[key] = val
+			}
+			if val, ok := v.kvstore[alias]; ok {
+				delete(v.kvstore, alias)
+				v.kvstore[key] = val
+			}
+			if val, ok := v.defaults[alias]; ok {
+				delete(v.defaults, alias)
+				v.defaults[key] = val
+			}
+			if val, ok := v.override[alias]; ok {
+				delete(v.override, alias)
+				v.override[key] = val
+			}
+			v.aliases[alias] = key
+		}
+	} else {
+		jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key))
+	}
+}
+
+func (v *Viper) realKey(key string) string {
+	newkey, exists := v.aliases[key]
+	if exists {
+		jww.DEBUG.Println("Alias", key, "to", newkey)
+		return v.realKey(newkey)
+	} else {
+		return key
+	}
+}
+
+// Check to see if the given key (or an alias) is in the config file
+func InConfig(key string) bool { return v.InConfig(key) }
+func (v *Viper) InConfig(key string) bool {
+	// if the requested key is an alias, then return the proper key
+	key = v.realKey(key)
+
+	_, exists := v.config[key]
+	return exists
+}
+
+// Set the default value for this key.
+// Default only used when no value is provided by the user via flag, config or ENV.
+func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
+func (v *Viper) SetDefault(key string, value interface{}) {
+	// If alias passed in, then set the proper default
+	key = v.realKey(strings.ToLower(key))
+	v.defaults[key] = value
+}
+
+// Sets the value for the key in the override regiser.
+// Will be used instead of values obtained via
+// flags, config file, ENV, default, or key/value store
+func Set(key string, value interface{}) { v.Set(key, value) }
+func (v *Viper) Set(key string, value interface{}) {
+	// If alias passed in, then set the proper override
+	key = v.realKey(strings.ToLower(key))
+	v.override[key] = value
+}
+
+// Viper will discover and load the configuration file from disk
+// and key/value stores, searching in one of the defined paths.
+func ReadInConfig() error { return v.ReadInConfig() }
+func (v *Viper) ReadInConfig() error {
+	jww.INFO.Println("Attempting to read in config file")
+	if !stringInSlice(v.getConfigType(), SupportedExts) {
+		return UnsupportedConfigError(v.getConfigType())
+	}
+
+	file, err := ioutil.ReadFile(v.getConfigFile())
+	if err != nil {
+		return err
+	}
+
+	v.config = make(map[string]interface{})
+
+	err = v.unmarshalReader(bytes.NewReader(file), v.config)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// MergeInConfig merges a new configuration with an existing config.
+func MergeInConfig() error { return v.MergeInConfig() }
+func (v *Viper) MergeInConfig() error {
+	jww.INFO.Println("Attempting to merge in config file")
+	if !stringInSlice(v.getConfigType(), SupportedExts) {
+		return UnsupportedConfigError(v.getConfigType())
+	}
+
+	file, err := ioutil.ReadFile(v.getConfigFile())
+	if err != nil {
+		return err
+	}
+
+	return v.MergeConfig(bytes.NewReader(file))
+}
+
+// Viper will read a configuration file, setting existing keys to nil if the
+// key does not exist in the file.
+func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
+func (v *Viper) ReadConfig(in io.Reader) error {
+	v.config = make(map[string]interface{})
+	return v.unmarshalReader(in, v.config)
+}
+
+// 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
+	}
+	mergeMaps(cfg, v.config, nil)
+	return nil
+}
+
+func keyExists(k string, m map[string]interface{}) string {
+	lk := strings.ToLower(k)
+	for mk := range m {
+		lmk := strings.ToLower(mk)
+		if lmk == lk {
+			return mk
+		}
+	}
+	return ""
+}
+
+func castToMapStringInterface(
+	src map[interface{}]interface{}) map[string]interface{} {
+	tgt := map[string]interface{}{}
+	for k, v := range src {
+		tgt[fmt.Sprintf("%v", k)] = v
+	}
+	return tgt
+}
+
+// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
+// insistence on parsing nested structures as `map[interface{}]interface{}`
+// instead of using a `string` as the key for nest structures beyond one level
+// deep. Both map types are supported as there is a go-yaml fork that uses
+// `map[string]interface{}` instead.
+func mergeMaps(
+	src, tgt map[string]interface{}, itgt map[interface{}]interface{}) {
+	for sk, sv := range src {
+		tk := keyExists(sk, tgt)
+		if tk == "" {
+			jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv)
+			tgt[sk] = sv
+			if itgt != nil {
+				itgt[sk] = sv
+			}
+			continue
+		}
+
+		tv, ok := tgt[tk]
+		if !ok {
+			jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv)
+			tgt[sk] = sv
+			if itgt != nil {
+				itgt[sk] = sv
+			}
+			continue
+		}
+
+		svType := reflect.TypeOf(sv)
+		tvType := reflect.TypeOf(tv)
+		if svType != tvType {
+			jww.ERROR.Printf(
+				"svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v",
+				sk, svType, tvType, sv, tv)
+			continue
+		}
+
+		jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v",
+			sk, svType, tvType, sv, tv)
+
+		switch ttv := tv.(type) {
+		case map[interface{}]interface{}:
+			jww.TRACE.Printf("merging maps (must convert)")
+			tsv := sv.(map[interface{}]interface{})
+			ssv := castToMapStringInterface(tsv)
+			stv := castToMapStringInterface(ttv)
+			mergeMaps(ssv, stv, ttv)
+		case map[string]interface{}:
+			jww.TRACE.Printf("merging maps")
+			mergeMaps(sv.(map[string]interface{}), ttv, nil)
+		default:
+			jww.TRACE.Printf("setting value")
+			tgt[tk] = sv
+			if itgt != nil {
+				itgt[tk] = sv
+			}
+		}
+	}
+}
+
+// func ReadBufConfig(buf *bytes.Buffer) error { return v.ReadBufConfig(buf) }
+// func (v *Viper) ReadBufConfig(buf *bytes.Buffer) error {
+// 	v.config = make(map[string]interface{})
+// 	return v.unmarshalReader(buf, v.config)
+// }
+
+// Attempts to get configuration from a remote source
+// and read it in the remote configuration registry.
+func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
+func (v *Viper) ReadRemoteConfig() error {
+	err := v.getKeyValueConfig()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
+func (v *Viper) WatchRemoteConfig() error {
+	err := v.watchKeyValueConfig()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Unmarshall a Reader into a map
+// Should probably be an unexported function
+func unmarshalReader(in io.Reader, c map[string]interface{}) error {
+	return v.unmarshalReader(in, c)
+}
+
+func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
+	return unmarshallConfigReader(in, c, v.getConfigType())
+}
+
+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 {
+		return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
+	}
+
+	for _, rp := range v.remoteProviders {
+		val, err := v.getRemoteConfig(rp)
+		if err != nil {
+			continue
+		}
+		v.kvstore = val
+		return nil
+	}
+	return RemoteConfigError("No Files Found")
+}
+
+func (v *Viper) getRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) {
+
+	reader, err := RemoteConfig.Get(provider)
+	if err != nil {
+		return nil, err
+	}
+	err = v.unmarshalReader(reader, v.kvstore)
+	return v.kvstore, err
+}
+
+// retrieve the first found remote configuration
+func (v *Viper) watchKeyValueConfig() error {
+	for _, rp := range v.remoteProviders {
+		val, err := v.watchRemoteConfig(rp)
+		if err != nil {
+			continue
+		}
+		v.kvstore = val
+		return nil
+	}
+	return RemoteConfigError("No Files Found")
+}
+
+func (v *Viper) watchRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) {
+	reader, err := RemoteConfig.Watch(provider)
+	if err != nil {
+		return nil, err
+	}
+	err = v.unmarshalReader(reader, v.kvstore)
+	return v.kvstore, err
+}
+
+// Return all keys regardless where they are set
+func AllKeys() []string { return v.AllKeys() }
+func (v *Viper) AllKeys() []string {
+	m := map[string]struct{}{}
+
+	for key, _ := range v.defaults {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.pflags {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.env {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.config {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.kvstore {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.override {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	for key, _ := range v.aliases {
+		m[strings.ToLower(key)] = struct{}{}
+	}
+
+	a := []string{}
+	for x, _ := range m {
+		a = append(a, x)
+	}
+
+	return a
+}
+
+// Return all settings as a map[string]interface{}
+func AllSettings() map[string]interface{} { return v.AllSettings() }
+func (v *Viper) AllSettings() map[string]interface{} {
+	m := map[string]interface{}{}
+	for _, x := range v.AllKeys() {
+		m[x] = v.Get(x)
+	}
+
+	return m
+}
+
+// Name for the config file.
+// Does not include extension.
+func SetConfigName(in string) { v.SetConfigName(in) }
+func (v *Viper) SetConfigName(in string) {
+	if in != "" {
+		v.configName = in
+	}
+}
+
+// Sets the type of the configuration returned by the
+// remote source, e.g. "json".
+func SetConfigType(in string) { v.SetConfigType(in) }
+func (v *Viper) SetConfigType(in string) {
+	if in != "" {
+		v.configType = in
+	}
+}
+
+func (v *Viper) getConfigType() string {
+	if v.configType != "" {
+		return v.configType
+	}
+
+	cf := v.getConfigFile()
+	ext := filepath.Ext(cf)
+
+	if len(ext) > 1 {
+		return ext[1:]
+	} else {
+		return ""
+	}
+}
+
+func (v *Viper) getConfigFile() string {
+	// if explicitly set, then use it
+	if v.configFile != "" {
+		return v.configFile
+	}
+
+	cf, err := v.findConfigFile()
+	if err != nil {
+		return ""
+	}
+
+	v.configFile = cf
+	return v.getConfigFile()
+}
+
+func (v *Viper) searchInPath(in string) (filename string) {
+	jww.DEBUG.Println("Searching for config in ", in)
+	for _, ext := range SupportedExts {
+		jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext))
+		if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b {
+			jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext))
+			return filepath.Join(in, v.configName+"."+ext)
+		}
+	}
+
+	return ""
+}
+
+// search all configPaths for any config file.
+// Returns the first path that exists (and is a config file)
+func (v *Viper) findConfigFile() (string, error) {
+
+	jww.INFO.Println("Searching for config in ", v.configPaths)
+
+	for _, cp := range v.configPaths {
+		file := v.searchInPath(cp)
+		if file != "" {
+			return file, nil
+		}
+	}
+	return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
+}
+
+// Prints all configuration registries for debugging
+// purposes.
+func Debug() { v.Debug() }
+func (v *Viper) Debug() {
+	fmt.Println("Aliases:")
+	pretty.Println(v.aliases)
+	fmt.Println("Override:")
+	pretty.Println(v.override)
+	fmt.Println("PFlags")
+	pretty.Println(v.pflags)
+	fmt.Println("Env:")
+	pretty.Println(v.env)
+	fmt.Println("Key/Value Store:")
+	pretty.Println(v.kvstore)
+	fmt.Println("Config:")
+	pretty.Println(v.config)
+	fmt.Println("Defaults:")
+	pretty.Println(v.defaults)
+}


Mime
View raw message