Initial Version
diff --git a/viper.go b/viper.go
new file mode 100644
index 0000000..bdfa5aa
--- /dev/null
+++ b/viper.go
@@ -0,0 +1,348 @@
+// 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.
+
+package viper
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "time"
+
+ "github.com/BurntSushi/toml"
+ "github.com/kr/pretty"
+ "github.com/spf13/cast"
+ jww "github.com/spf13/jwalterweatherman"
+ "gopkg.in/yaml.v1"
+)
+
+// A set of paths to look for the config file in
+var configPaths []string
+
+// Name of file to look for inside the path
+var configName string = "config"
+
+// extensions Supported
+var SupportedExts []string = []string{"json", "toml", "yaml"}
+var configFile string
+var configType string
+
+var config map[string]interface{} = make(map[string]interface{})
+var override map[string]interface{} = make(map[string]interface{})
+var defaults map[string]interface{} = make(map[string]interface{})
+var aliases map[string]string = make(map[string]string)
+
+func SetConfigFile(in string) {
+ if in != "" {
+ configFile = in
+ }
+}
+
+func AddConfigPath(in string) {
+ if in != "" {
+ absin := absPathify(in)
+ jww.INFO.Println("adding", absin, "to paths to search")
+ if !stringInSlice(absin, configPaths) {
+ configPaths = append(configPaths, absin)
+ }
+ }
+}
+
+func GetString(key string) string {
+ return cast.ToString(Get(key))
+}
+
+func GetBool(key string) bool {
+ return cast.ToBool(Get(key))
+}
+
+func GetInt(key string) int {
+ return cast.ToInt(Get(key))
+}
+
+func GetFloat64(key string) float64 {
+ return cast.ToFloat64(Get(key))
+}
+
+func GetTime(key string) time.Time {
+ return cast.ToTime(Get(key))
+}
+
+func GetStringArray(key string) []string {
+ return cast.ToStringArray(Get(key))
+}
+
+func find(key string) interface{} {
+ var val interface{}
+ var exists bool
+
+ // If the requested key is an alias, then return the proper key
+ newkey, exists := aliases[key]
+ if exists {
+ return find(newkey)
+ }
+
+ val, exists = override[key]
+ if exists {
+ jww.TRACE.Println(key, "found in override:", val)
+ return val
+ }
+
+ val, exists = config[key]
+ if exists {
+ jww.TRACE.Println(key, "found in config:", val)
+ return val
+ }
+
+ val, exists = defaults[key]
+ if exists {
+ jww.TRACE.Println(key, "found in defaults:", val)
+ return val
+ }
+
+ return nil
+}
+
+func Get(key string) interface{} {
+ v := find(key)
+
+ if v == nil {
+ return nil
+ }
+
+ switch v.(type) {
+ case bool:
+ return cast.ToBool(v)
+ case string:
+ return cast.ToString(v)
+ case int64, int32, int16, int8, int:
+ return cast.ToInt(v)
+ case float64, float32:
+ return cast.ToFloat64(v)
+ case time.Time:
+ return cast.ToTime(v)
+ case []string:
+ return v
+ }
+ return v
+}
+
+func IsSet(key string) bool {
+ t := Get(key)
+ return t != nil
+}
+
+func RegisterAlias(alias string, key string) {
+ aliases[alias] = key
+}
+
+func InConfig(key string) bool {
+ _, exists := config[key]
+ return exists
+}
+
+func SetDefault(key string, value interface{}) {
+ // If alias passed in, then set the proper default
+ newkey, exists := aliases[key]
+ if exists {
+ defaults[newkey] = value
+ } else {
+ defaults[key] = value
+ }
+}
+
+func Set(key string, value interface{}) {
+ // If alias passed in, then set the proper override
+ newkey, exists := aliases[key]
+ if exists {
+ override[newkey] = value
+ } else {
+ override[key] = value
+ }
+}
+
+func ReadInConfig() {
+ jww.INFO.Println("Attempting to read in config file")
+ if !stringInSlice(getConfigType(), SupportedExts) {
+ jww.ERROR.Fatalf("Unsupported Config Type %q", getConfigType())
+ }
+
+ file, err := ioutil.ReadFile(getConfigFile())
+ if err == nil {
+ MarshallReader(bytes.NewReader(file))
+ }
+}
+
+func MarshallReader(in io.Reader) {
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(in)
+
+ switch getConfigType() {
+ case "yaml":
+ if err := yaml.Unmarshal(buf.Bytes(), &config); err != nil {
+ jww.ERROR.Fatalf("Error parsing config: %s", err)
+ }
+
+ case "json":
+ if err := json.Unmarshal(buf.Bytes(), &config); err != nil {
+ jww.ERROR.Fatalf("Error parsing config: %s", err)
+ }
+
+ case "toml":
+ if _, err := toml.Decode(buf.String(), &config); err != nil {
+ jww.ERROR.Fatalf("Error parsing config: %s", err)
+ }
+ }
+}
+
+func SetConfigName(in string) {
+ if in != "" {
+ configName = in
+ }
+}
+
+func SetConfigType(in string) {
+ if in != "" {
+ configType = in
+ }
+}
+
+func getConfigType() string {
+ if configType != "" {
+ return configType
+ }
+
+ cf := getConfigFile()
+ ext := path.Ext(cf)
+
+ if len(ext) > 1 {
+ return ext[1:]
+ } else {
+ return ""
+ }
+}
+
+func getConfigFile() string {
+ // if explicitly set, then use it
+ if configFile != "" {
+ return configFile
+ }
+
+ cf, err := findConfigFile()
+ if err != nil {
+ jww.ERROR.Println(err)
+ } else {
+ configFile = cf
+ return getConfigFile()
+ }
+ return ""
+}
+
+func searchInPath(in string) (filename string) {
+ jww.DEBUG.Println("Searching for config in ", in)
+ for _, ext := range SupportedExts {
+
+ jww.DEBUG.Println("Checking for", path.Join(in, configName+"."+ext))
+ if b, _ := exists(path.Join(in, configName+"."+ext)); b {
+ jww.DEBUG.Println("Found: ", path.Join(in, configName+"."+ext))
+ return path.Join(in, configName+"."+ext)
+ }
+ }
+
+ return ""
+}
+
+func findConfigFile() (string, error) {
+ jww.INFO.Println("Searching for config in ", configPaths)
+
+ for _, cp := range configPaths {
+ file := searchInPath(cp)
+ if file != "" {
+ return file, nil
+ }
+ }
+ cwd, _ := findCWD()
+
+ file := searchInPath(cwd)
+ if file != "" {
+ return file, nil
+ }
+
+ return "", fmt.Errorf("config file not found in: %s", configPaths)
+}
+
+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
+}
+
+// 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 absPathify(inPath string) string {
+ jww.INFO.Println("Trying to resolve absolute path to", inPath)
+ 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 ""
+}
+
+func Debug() {
+ fmt.Println("Config:")
+ pretty.Println(config)
+ fmt.Println("Defaults:")
+ pretty.Println(defaults)
+ fmt.Println("Override:")
+ pretty.Println(override)
+}