mirror of
https://github.com/spf13/viper
synced 2024-11-16 10:07:00 +00:00
Viper now supports multiple vipers. No API changes.
This commit is contained in:
parent
90193e564a
commit
29f1858f87
3 changed files with 373 additions and 304 deletions
112
util.go
Normal file
112
util.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
|
)
|
||||||
|
|
||||||
|
func insensativiseMap(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
|
||||||
|
}
|
549
viper.go
549
viper.go
|
@ -27,7 +27,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -41,6 +40,65 @@ import (
|
||||||
"gopkg.in/yaml.v1"
|
"gopkg.in/yaml.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var v *viper
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
v = New()
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnsupportedConfigError string
|
||||||
|
|
||||||
|
func (str UnsupportedConfigError) Error() string {
|
||||||
|
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnsupportedRemoteProviderError string
|
||||||
|
|
||||||
|
func (str UnsupportedRemoteProviderError) Error() string {
|
||||||
|
return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
type RemoteConfigError string
|
||||||
|
|
||||||
|
func (rce RemoteConfigError) Error() string {
|
||||||
|
return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
|
||||||
|
}
|
||||||
|
|
||||||
|
type viper struct {
|
||||||
|
// A set of paths to look for the config file in
|
||||||
|
configPaths []string
|
||||||
|
|
||||||
|
// A set of remote providers to search for the configuration
|
||||||
|
remoteProviders []*remoteProvider
|
||||||
|
|
||||||
|
// Name of file to look for inside the path
|
||||||
|
configName string
|
||||||
|
configFile string
|
||||||
|
configType string
|
||||||
|
|
||||||
|
config map[string]interface{}
|
||||||
|
override map[string]interface{}
|
||||||
|
defaults map[string]interface{}
|
||||||
|
kvstore map[string]interface{}
|
||||||
|
pflags map[string]*pflag.Flag
|
||||||
|
env map[string]string
|
||||||
|
aliases map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *viper {
|
||||||
|
v := new(viper)
|
||||||
|
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]*pflag.Flag)
|
||||||
|
v.env = make(map[string]string)
|
||||||
|
v.aliases = make(map[string]string)
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// remoteProvider stores the configuration necessary
|
// remoteProvider stores the configuration necessary
|
||||||
// to connect to a remote key/value store.
|
// to connect to a remote key/value store.
|
||||||
// Optional secretKeyring to unencrypt encrypted values
|
// Optional secretKeyring to unencrypt encrypted values
|
||||||
|
@ -52,50 +110,34 @@ type remoteProvider struct {
|
||||||
secretKeyring string
|
secretKeyring string
|
||||||
}
|
}
|
||||||
|
|
||||||
// A set of paths to look for the config file in
|
// universally supported extensions
|
||||||
var configPaths []string
|
|
||||||
|
|
||||||
// A set of remote providers to search for the configuration
|
|
||||||
var remoteProviders []*remoteProvider
|
|
||||||
|
|
||||||
// Name of file to look for inside the path
|
|
||||||
var configName string = "config"
|
|
||||||
|
|
||||||
// extensions Supported
|
|
||||||
var SupportedExts []string = []string{"json", "toml", "yaml", "yml"}
|
var SupportedExts []string = []string{"json", "toml", "yaml", "yml"}
|
||||||
var SupportedRemoteProviders []string = []string{"etcd", "consul"}
|
|
||||||
var configFile string
|
|
||||||
var configType string
|
|
||||||
|
|
||||||
var config map[string]interface{} = make(map[string]interface{})
|
// universally supported remote providers
|
||||||
var override map[string]interface{} = make(map[string]interface{})
|
var SupportedRemoteProviders []string = []string{"etcd", "consul"}
|
||||||
var env map[string]string = make(map[string]string)
|
|
||||||
var defaults map[string]interface{} = make(map[string]interface{})
|
|
||||||
var kvstore map[string]interface{} = make(map[string]interface{})
|
|
||||||
var pflags map[string]*pflag.Flag = make(map[string]*pflag.Flag)
|
|
||||||
var aliases map[string]string = make(map[string]string)
|
|
||||||
|
|
||||||
// Explicitly define the path, name and extension of the config file
|
// Explicitly define the path, name and extension of the config file
|
||||||
// Viper will use this and not check any of the config paths
|
// Viper will use this and not check any of the config paths
|
||||||
func SetConfigFile(in string) {
|
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
||||||
|
func (v *viper) SetConfigFile(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
configFile = in
|
v.configFile = in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConfigFileUsed() string {
|
// Return the config file used
|
||||||
return configFile
|
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.
|
// Add a path for viper to search for the config file in.
|
||||||
// Can be called multiple times to define multiple search paths.
|
// Can be called multiple times to define multiple search paths.
|
||||||
|
func AddConfigPath(in string) { v.AddConfigPath(in) }
|
||||||
func AddConfigPath(in string) {
|
func (v *viper) AddConfigPath(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
absin := absPathify(in)
|
absin := absPathify(in)
|
||||||
jww.INFO.Println("adding", absin, "to paths to search")
|
jww.INFO.Println("adding", absin, "to paths to search")
|
||||||
if !stringInSlice(absin, configPaths) {
|
if !stringInSlice(absin, v.configPaths) {
|
||||||
configPaths = append(configPaths, absin)
|
v.configPaths = append(v.configPaths, absin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +151,9 @@ func AddConfigPath(in string) {
|
||||||
// you should set path to /configs and set config name (SetConfigName()) to
|
// you should set path to /configs and set config name (SetConfigName()) to
|
||||||
// "myapp"
|
// "myapp"
|
||||||
func AddRemoteProvider(provider, endpoint, path string) error {
|
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) {
|
if !stringInSlice(provider, SupportedRemoteProviders) {
|
||||||
return UnsupportedRemoteProviderError(provider)
|
return UnsupportedRemoteProviderError(provider)
|
||||||
}
|
}
|
||||||
|
@ -119,8 +164,8 @@ func AddRemoteProvider(provider, endpoint, path string) error {
|
||||||
provider: provider,
|
provider: provider,
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
if !providerPathExists(rp) {
|
if !v.providerPathExists(rp) {
|
||||||
remoteProviders = append(remoteProviders, rp)
|
v.remoteProviders = append(v.remoteProviders, rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -137,6 +182,10 @@ func AddRemoteProvider(provider, endpoint, path string) error {
|
||||||
// "myapp"
|
// "myapp"
|
||||||
// Secure Remote Providers are implemented with github.com/xordataexchange/crypt
|
// Secure Remote Providers are implemented with github.com/xordataexchange/crypt
|
||||||
func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
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) {
|
if !stringInSlice(provider, SupportedRemoteProviders) {
|
||||||
return UnsupportedRemoteProviderError(provider)
|
return UnsupportedRemoteProviderError(provider)
|
||||||
}
|
}
|
||||||
|
@ -147,16 +196,15 @@ func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) err
|
||||||
provider: provider,
|
provider: provider,
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
if !providerPathExists(rp) {
|
if !v.providerPathExists(rp) {
|
||||||
remoteProviders = append(remoteProviders, rp)
|
v.remoteProviders = append(v.remoteProviders, rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func providerPathExists(p *remoteProvider) bool {
|
func (v *viper) providerPathExists(p *remoteProvider) bool {
|
||||||
|
for _, y := range v.remoteProviders {
|
||||||
for _, y := range remoteProviders {
|
|
||||||
if reflect.DeepEqual(y, p) {
|
if reflect.DeepEqual(y, p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -164,69 +212,73 @@ func providerPathExists(p *remoteProvider) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnsupportedRemoteProviderError string
|
func GetString(key string) string { return v.GetString(key) }
|
||||||
|
func (v *viper) GetString(key string) string {
|
||||||
func (str UnsupportedRemoteProviderError) Error() string {
|
|
||||||
return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetString(key string) string {
|
|
||||||
return cast.ToString(Get(key))
|
return cast.ToString(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBool(key string) bool {
|
func GetBool(key string) bool { return v.GetBool(key) }
|
||||||
|
func (v *viper) GetBool(key string) bool {
|
||||||
return cast.ToBool(Get(key))
|
return cast.ToBool(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetInt(key string) int {
|
func GetInt(key string) int { return v.GetInt(key) }
|
||||||
|
func (v *viper) GetInt(key string) int {
|
||||||
return cast.ToInt(Get(key))
|
return cast.ToInt(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFloat64(key string) float64 {
|
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
|
||||||
|
func (v *viper) GetFloat64(key string) float64 {
|
||||||
return cast.ToFloat64(Get(key))
|
return cast.ToFloat64(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTime(key string) time.Time {
|
func GetTime(key string) time.Time { return v.GetTime(key) }
|
||||||
|
func (v *viper) GetTime(key string) time.Time {
|
||||||
return cast.ToTime(Get(key))
|
return cast.ToTime(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStringSlice(key string) []string {
|
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
|
||||||
|
func (v *viper) GetStringSlice(key string) []string {
|
||||||
return cast.ToStringSlice(Get(key))
|
return cast.ToStringSlice(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStringMap(key string) map[string]interface{} {
|
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
|
||||||
|
func (v *viper) GetStringMap(key string) map[string]interface{} {
|
||||||
return cast.ToStringMap(Get(key))
|
return cast.ToStringMap(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStringMapString(key string) map[string]string {
|
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
|
||||||
|
func (v *viper) GetStringMapString(key string) map[string]string {
|
||||||
return cast.ToStringMapString(Get(key))
|
return cast.ToStringMapString(Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a single key and marshals it into a Struct
|
// Takes a single key and marshals it into a Struct
|
||||||
func MarshalKey(key string, rawVal interface{}) error {
|
func MarshalKey(key string, rawVal interface{}) error { return v.MarshalKey(key, rawVal) }
|
||||||
|
func (v *viper) MarshalKey(key string, rawVal interface{}) error {
|
||||||
return mapstructure.Decode(Get(key), rawVal)
|
return mapstructure.Decode(Get(key), rawVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshals the config into a Struct
|
// Marshals the config into a Struct
|
||||||
func Marshal(rawVal interface{}) error {
|
func Marshal(rawVal interface{}) error { return v.Marshal(rawVal) }
|
||||||
err := mapstructure.Decode(defaults, rawVal)
|
func (v *viper) Marshal(rawVal interface{}) error {
|
||||||
|
err := mapstructure.Decode(v.defaults, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mapstructure.Decode(config, rawVal)
|
err = mapstructure.Decode(v.config, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mapstructure.Decode(override, rawVal)
|
err = mapstructure.Decode(v.override, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mapstructure.Decode(kvstore, rawVal)
|
err = mapstructure.Decode(v.kvstore, rawVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
insensativiseMaps()
|
v.insensativiseMaps()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -236,11 +288,12 @@ func Marshal(rawVal interface{}) error {
|
||||||
// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
|
// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
|
||||||
// viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
// viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
||||||
//
|
//
|
||||||
func BindPFlag(key string, flag *pflag.Flag) (err error) {
|
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) {
|
||||||
if flag == nil {
|
if flag == nil {
|
||||||
return fmt.Errorf("flag for %q is nil", key)
|
return fmt.Errorf("flag for %q is nil", key)
|
||||||
}
|
}
|
||||||
pflags[strings.ToLower(key)] = flag
|
v.pflags[strings.ToLower(key)] = flag
|
||||||
|
|
||||||
switch flag.Value.Type() {
|
switch flag.Value.Type() {
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
|
@ -256,7 +309,8 @@ func BindPFlag(key string, flag *pflag.Flag) (err error) {
|
||||||
// Binds a viper key to a ENV variable
|
// Binds a viper key to a ENV variable
|
||||||
// ENV variables are case sensitive
|
// ENV variables are case sensitive
|
||||||
// If only a key is provided, it will use the env key matching the key, uppercased.
|
// If only a key is provided, it will use the env key matching the key, uppercased.
|
||||||
func BindEnv(input ...string) (err error) {
|
func BindEnv(input ...string) (err error) { return v.BindEnv(input...) }
|
||||||
|
func (v *viper) BindEnv(input ...string) (err error) {
|
||||||
var key, envkey string
|
var key, envkey string
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return fmt.Errorf("BindEnv missing key to bind to")
|
return fmt.Errorf("BindEnv missing key to bind to")
|
||||||
|
@ -270,20 +324,20 @@ func BindEnv(input ...string) (err error) {
|
||||||
envkey = input[1]
|
envkey = input[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
env[key] = envkey
|
v.env[key] = envkey
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func find(key string) interface{} {
|
func (v *viper) find(key string) interface{} {
|
||||||
var val interface{}
|
var val interface{}
|
||||||
var exists bool
|
var exists bool
|
||||||
|
|
||||||
// if the requested key is an alias, then return the proper key
|
// if the requested key is an alias, then return the proper key
|
||||||
key = realKey(key)
|
key = v.realKey(key)
|
||||||
|
|
||||||
// PFlag Override first
|
// PFlag Override first
|
||||||
flag, exists := pflags[key]
|
flag, exists := v.pflags[key]
|
||||||
if exists {
|
if exists {
|
||||||
if flag.Changed {
|
if flag.Changed {
|
||||||
jww.TRACE.Println(key, "found in override (via pflag):", val)
|
jww.TRACE.Println(key, "found in override (via pflag):", val)
|
||||||
|
@ -291,13 +345,13 @@ func find(key string) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val, exists = override[key]
|
val, exists = v.override[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "found in override:", val)
|
jww.TRACE.Println(key, "found in override:", val)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
envkey, exists := env[key]
|
envkey, exists := v.env[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "registered as env var", envkey)
|
jww.TRACE.Println(key, "registered as env var", envkey)
|
||||||
if val = os.Getenv(envkey); val != "" {
|
if val = os.Getenv(envkey); val != "" {
|
||||||
|
@ -308,19 +362,19 @@ func find(key string) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val, exists = config[key]
|
val, exists = v.config[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "found in config:", val)
|
jww.TRACE.Println(key, "found in config:", val)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
val, exists = kvstore[key]
|
val, exists = v.kvstore[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "found in key/value store:", val)
|
jww.TRACE.Println(key, "found in key/value store:", val)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
val, exists = defaults[key]
|
val, exists = v.defaults[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.TRACE.Println(key, "found in defaults:", val)
|
jww.TRACE.Println(key, "found in defaults:", val)
|
||||||
return val
|
return val
|
||||||
|
@ -331,151 +385,157 @@ func find(key string) interface{} {
|
||||||
|
|
||||||
// Get returns an interface..
|
// Get returns an interface..
|
||||||
// Must be typecast or used by something that will typecast
|
// Must be typecast or used by something that will typecast
|
||||||
func Get(key string) interface{} {
|
func Get(key string) interface{} { return v.Get(key) }
|
||||||
|
func (v *viper) Get(key string) interface{} {
|
||||||
key = strings.ToLower(key)
|
key = strings.ToLower(key)
|
||||||
v := find(key)
|
val := v.find(key)
|
||||||
|
|
||||||
if v == nil {
|
if val == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v.(type) {
|
switch val.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
return cast.ToBool(v)
|
return cast.ToBool(val)
|
||||||
case string:
|
case string:
|
||||||
return cast.ToString(v)
|
return cast.ToString(val)
|
||||||
case int64, int32, int16, int8, int:
|
case int64, int32, int16, int8, int:
|
||||||
return cast.ToInt(v)
|
return cast.ToInt(val)
|
||||||
case float64, float32:
|
case float64, float32:
|
||||||
return cast.ToFloat64(v)
|
return cast.ToFloat64(val)
|
||||||
case time.Time:
|
case time.Time:
|
||||||
return cast.ToTime(v)
|
return cast.ToTime(val)
|
||||||
case []string:
|
case []string:
|
||||||
return v
|
return val
|
||||||
}
|
}
|
||||||
return v
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsSet(key string) bool {
|
func IsSet(key string) bool { return v.IsSet(key) }
|
||||||
t := Get(key)
|
func (v *viper) IsSet(key string) bool {
|
||||||
|
t := v.Get(key)
|
||||||
return t != nil
|
return t != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have viper check ENV variables for all
|
// Have viper check ENV variables for all
|
||||||
// keys set in config, default & flags
|
// keys set in config, default & flags
|
||||||
func AutomaticEnv() {
|
func AutomaticEnv() { v.AutomaticEnv() }
|
||||||
for _, x := range AllKeys() {
|
func (v *viper) AutomaticEnv() {
|
||||||
BindEnv(x)
|
for _, x := range v.AllKeys() {
|
||||||
|
v.BindEnv(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aliases provide another accessor for the same key.
|
// Aliases provide another accessor for the same key.
|
||||||
// This enables one to change a name without breaking the application
|
// This enables one to change a name without breaking the application
|
||||||
func RegisterAlias(alias string, key string) {
|
func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) }
|
||||||
registerAlias(alias, strings.ToLower(key))
|
func (v *viper) RegisterAlias(alias string, key string) {
|
||||||
|
v.registerAlias(alias, strings.ToLower(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerAlias(alias string, key string) {
|
func (v *viper) registerAlias(alias string, key string) {
|
||||||
alias = strings.ToLower(alias)
|
alias = strings.ToLower(alias)
|
||||||
if alias != key && alias != realKey(key) {
|
if alias != key && alias != v.realKey(key) {
|
||||||
_, exists := aliases[alias]
|
_, exists := v.aliases[alias]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
// if we alias something that exists in one of the maps to another
|
// 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, we'll never be able to get that value using the original
|
||||||
// name, so move the config value to the new realkey.
|
// name, so move the config value to the new realkey.
|
||||||
if val, ok := config[alias]; ok {
|
if val, ok := v.config[alias]; ok {
|
||||||
delete(config, alias)
|
delete(v.config, alias)
|
||||||
config[key] = val
|
v.config[key] = val
|
||||||
}
|
}
|
||||||
if val, ok := kvstore[alias]; ok {
|
if val, ok := v.kvstore[alias]; ok {
|
||||||
delete(kvstore, alias)
|
delete(v.kvstore, alias)
|
||||||
kvstore[key] = val
|
v.kvstore[key] = val
|
||||||
}
|
}
|
||||||
if val, ok := defaults[alias]; ok {
|
if val, ok := v.defaults[alias]; ok {
|
||||||
delete(defaults, alias)
|
delete(v.defaults, alias)
|
||||||
defaults[key] = val
|
v.defaults[key] = val
|
||||||
}
|
}
|
||||||
if val, ok := override[alias]; ok {
|
if val, ok := v.override[alias]; ok {
|
||||||
delete(override, alias)
|
delete(v.override, alias)
|
||||||
override[key] = val
|
v.override[key] = val
|
||||||
}
|
}
|
||||||
aliases[alias] = key
|
v.aliases[alias] = key
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
jww.WARN.Println("Creating circular reference alias", alias, key, realKey(key))
|
jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func realKey(key string) string {
|
func (v *viper) realKey(key string) string {
|
||||||
newkey, exists := aliases[key]
|
newkey, exists := v.aliases[key]
|
||||||
if exists {
|
if exists {
|
||||||
jww.DEBUG.Println("Alias", key, "to", newkey)
|
jww.DEBUG.Println("Alias", key, "to", newkey)
|
||||||
return realKey(newkey)
|
return v.realKey(newkey)
|
||||||
} else {
|
} else {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InConfig(key string) bool {
|
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
|
// if the requested key is an alias, then return the proper key
|
||||||
key = realKey(key)
|
key = v.realKey(key)
|
||||||
|
|
||||||
_, exists := config[key]
|
_, exists := v.config[key]
|
||||||
return exists
|
return exists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the default value for this key.
|
// Set the default value for this key.
|
||||||
// Default only used when no value is provided by the user via flag, config or ENV.
|
// Default only used when no value is provided by the user via flag, config or ENV.
|
||||||
func SetDefault(key string, value interface{}) {
|
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
|
// If alias passed in, then set the proper default
|
||||||
key = realKey(strings.ToLower(key))
|
key = v.realKey(strings.ToLower(key))
|
||||||
defaults[key] = value
|
v.defaults[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// The user provided value (via flag)
|
// The user provided value (via flag)
|
||||||
// Will be used instead of values obtained via
|
// Will be used instead of values obtained via
|
||||||
// config file, ENV, default, or key/value store
|
// config file, ENV, default, or key/value store
|
||||||
func Set(key string, value interface{}) {
|
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
|
// If alias passed in, then set the proper override
|
||||||
key = realKey(strings.ToLower(key))
|
key = v.realKey(strings.ToLower(key))
|
||||||
override[key] = value
|
v.override[key] = value
|
||||||
}
|
|
||||||
|
|
||||||
type UnsupportedConfigError string
|
|
||||||
|
|
||||||
func (str UnsupportedConfigError) Error() string {
|
|
||||||
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viper will discover and load the configuration file from disk
|
// Viper will discover and load the configuration file from disk
|
||||||
// and key/value stores, searching in one of the defined paths.
|
// and key/value stores, searching in one of the defined paths.
|
||||||
func ReadInConfig() error {
|
func ReadInConfig() error { return v.ReadInConfig() }
|
||||||
|
func (v *viper) ReadInConfig() error {
|
||||||
jww.INFO.Println("Attempting to read in config file")
|
jww.INFO.Println("Attempting to read in config file")
|
||||||
if !stringInSlice(getConfigType(), SupportedExts) {
|
if !stringInSlice(v.getConfigType(), SupportedExts) {
|
||||||
return UnsupportedConfigError(getConfigType())
|
return UnsupportedConfigError(v.getConfigType())
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := ioutil.ReadFile(getConfigFile())
|
file, err := ioutil.ReadFile(v.getConfigFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
MarshallReader(bytes.NewReader(file), config)
|
v.MarshallReader(bytes.NewReader(file), v.config)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func ReadRemoteConfig() error {
|
|
||||||
err := getKeyValueConfig()
|
func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
|
||||||
|
func (v *viper) ReadRemoteConfig() error {
|
||||||
|
err := v.getKeyValueConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func MarshallReader(in io.Reader, c map[string]interface{}) {
|
|
||||||
|
func MarshallReader(in io.Reader, c map[string]interface{}) { v.MarshallReader(in, c) }
|
||||||
|
func (v *viper) MarshallReader(in io.Reader, c map[string]interface{}) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.ReadFrom(in)
|
buf.ReadFrom(in)
|
||||||
|
|
||||||
switch getConfigType() {
|
switch v.getConfigType() {
|
||||||
case "yaml", "yml":
|
case "yaml", "yml":
|
||||||
if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil {
|
if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil {
|
||||||
jww.ERROR.Fatalf("Error parsing config: %s", err)
|
jww.ERROR.Fatalf("Error parsing config: %s", err)
|
||||||
|
@ -495,33 +555,27 @@ func MarshallReader(in io.Reader, c map[string]interface{}) {
|
||||||
insensativiseMap(c)
|
insensativiseMap(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func insensativiseMaps() {
|
func (v *viper) insensativiseMaps() {
|
||||||
insensativiseMap(config)
|
insensativiseMap(v.config)
|
||||||
insensativiseMap(defaults)
|
insensativiseMap(v.defaults)
|
||||||
insensativiseMap(override)
|
insensativiseMap(v.override)
|
||||||
insensativiseMap(kvstore)
|
insensativiseMap(v.kvstore)
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the first found remote configuration
|
// retrieve the first found remote configuration
|
||||||
func getKeyValueConfig() error {
|
func (v *viper) getKeyValueConfig() error {
|
||||||
for _, rp := range remoteProviders {
|
for _, rp := range v.remoteProviders {
|
||||||
val, err := getRemoteConfig(rp)
|
val, err := v.getRemoteConfig(rp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
kvstore = val
|
v.kvstore = val
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return RemoteConfigError("No Files Found")
|
return RemoteConfigError("No Files Found")
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoteConfigError string
|
func (v *viper) getRemoteConfig(provider *remoteProvider) (map[string]interface{}, error) {
|
||||||
|
|
||||||
func (rce RemoteConfigError) Error() string {
|
|
||||||
return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRemoteConfig(provider *remoteProvider) (map[string]interface{}, error) {
|
|
||||||
var cm crypt.ConfigManager
|
var cm crypt.ConfigManager
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -551,36 +605,27 @@ func getRemoteConfig(provider *remoteProvider) (map[string]interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader := bytes.NewReader(b)
|
reader := bytes.NewReader(b)
|
||||||
MarshallReader(reader, kvstore)
|
v.MarshallReader(reader, v.kvstore)
|
||||||
return kvstore, err
|
return v.kvstore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func insensativiseMap(m map[string]interface{}) {
|
func AllKeys() []string { return v.AllKeys() }
|
||||||
for key, val := range m {
|
func (v *viper) AllKeys() []string {
|
||||||
lower := strings.ToLower(key)
|
|
||||||
if key != lower {
|
|
||||||
delete(m, key)
|
|
||||||
m[lower] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AllKeys() []string {
|
|
||||||
m := map[string]struct{}{}
|
m := map[string]struct{}{}
|
||||||
|
|
||||||
for key, _ := range defaults {
|
for key, _ := range v.defaults {
|
||||||
m[key] = struct{}{}
|
m[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, _ := range config {
|
for key, _ := range v.config {
|
||||||
m[key] = struct{}{}
|
m[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, _ := range kvstore {
|
for key, _ := range v.kvstore {
|
||||||
m[key] = struct{}{}
|
m[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, _ := range override {
|
for key, _ := range v.override {
|
||||||
m[key] = struct{}{}
|
m[key] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,10 +637,11 @@ func AllKeys() []string {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func AllSettings() map[string]interface{} {
|
func AllSettings() map[string]interface{} { return v.AllSettings() }
|
||||||
|
func (v *viper) AllSettings() map[string]interface{} {
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
for _, x := range AllKeys() {
|
for _, x := range v.AllKeys() {
|
||||||
m[x] = Get(x)
|
m[x] = v.Get(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
@ -603,24 +649,26 @@ func AllSettings() map[string]interface{} {
|
||||||
|
|
||||||
// Name for the config file.
|
// Name for the config file.
|
||||||
// Does not include extension.
|
// Does not include extension.
|
||||||
func SetConfigName(in string) {
|
func SetConfigName(in string) { v.SetConfigName(in) }
|
||||||
|
func (v *viper) SetConfigName(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
configName = in
|
v.configName = in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetConfigType(in string) {
|
func SetConfigType(in string) { v.SetConfigType(in) }
|
||||||
|
func (v *viper) SetConfigType(in string) {
|
||||||
if in != "" {
|
if in != "" {
|
||||||
configType = in
|
v.configType = in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfigType() string {
|
func (v *viper) getConfigType() string {
|
||||||
if configType != "" {
|
if v.configType != "" {
|
||||||
return configType
|
return v.configType
|
||||||
}
|
}
|
||||||
|
|
||||||
cf := getConfigFile()
|
cf := v.getConfigFile()
|
||||||
ext := filepath.Ext(cf)
|
ext := filepath.Ext(cf)
|
||||||
|
|
||||||
if len(ext) > 1 {
|
if len(ext) > 1 {
|
||||||
|
@ -630,169 +678,78 @@ func getConfigType() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfigFile() string {
|
func (v *viper) getConfigFile() string {
|
||||||
// if explicitly set, then use it
|
// if explicitly set, then use it
|
||||||
if configFile != "" {
|
if v.configFile != "" {
|
||||||
return configFile
|
return v.configFile
|
||||||
}
|
}
|
||||||
|
|
||||||
cf, err := findConfigFile()
|
cf, err := v.findConfigFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
configFile = cf
|
v.configFile = cf
|
||||||
return getConfigFile()
|
return v.getConfigFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchInPath(in string) (filename string) {
|
func (v *viper) searchInPath(in string) (filename string) {
|
||||||
jww.DEBUG.Println("Searching for config in ", in)
|
jww.DEBUG.Println("Searching for config in ", in)
|
||||||
for _, ext := range SupportedExts {
|
for _, ext := range SupportedExts {
|
||||||
|
jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext))
|
||||||
jww.DEBUG.Println("Checking for", filepath.Join(in, configName+"."+ext))
|
if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b {
|
||||||
if b, _ := exists(filepath.Join(in, configName+"."+ext)); b {
|
jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext))
|
||||||
jww.DEBUG.Println("Found: ", filepath.Join(in, configName+"."+ext))
|
return filepath.Join(in, v.configName+"."+ext)
|
||||||
return filepath.Join(in, configName+"."+ext)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func findConfigFile() (string, error) {
|
func (v *viper) findConfigFile() (string, error) {
|
||||||
jww.INFO.Println("Searching for config in ", configPaths)
|
jww.INFO.Println("Searching for config in ", v.configPaths)
|
||||||
|
|
||||||
for _, cp := range configPaths {
|
for _, cp := range v.configPaths {
|
||||||
file := searchInPath(cp)
|
file := v.searchInPath(cp)
|
||||||
if file != "" {
|
if file != "" {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd, _ := findCWD()
|
cwd, _ := findCWD()
|
||||||
file := searchInPath(cwd)
|
file := v.searchInPath(cwd)
|
||||||
if file != "" {
|
if file != "" {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// try the current working directory
|
// try the current working directory
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
file = searchInPath(wd)
|
file = v.searchInPath(wd)
|
||||||
if file != "" {
|
if file != "" {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("config file not found in: %s", configPaths)
|
return "", fmt.Errorf("config file not found in: %s", v.configPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findCWD() (string, error) {
|
func Debug() { v.Debug() }
|
||||||
serverFile, err := filepath.Abs(os.Args[0])
|
func (v *viper) Debug() {
|
||||||
|
|
||||||
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 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 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 ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug() {
|
|
||||||
fmt.Println("Config:")
|
fmt.Println("Config:")
|
||||||
pretty.Println(config)
|
pretty.Println(v.config)
|
||||||
fmt.Println("Key/Value Store:")
|
fmt.Println("Key/Value Store:")
|
||||||
pretty.Println(kvstore)
|
pretty.Println(v.kvstore)
|
||||||
fmt.Println("Env:")
|
fmt.Println("Env:")
|
||||||
pretty.Println(env)
|
pretty.Println(v.env)
|
||||||
fmt.Println("Defaults:")
|
fmt.Println("Defaults:")
|
||||||
pretty.Println(defaults)
|
pretty.Println(v.defaults)
|
||||||
fmt.Println("Override:")
|
fmt.Println("Override:")
|
||||||
pretty.Println(override)
|
pretty.Println(v.override)
|
||||||
fmt.Println("Aliases:")
|
fmt.Println("Aliases:")
|
||||||
pretty.Println(aliases)
|
pretty.Println(v.aliases)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intended for testing, will reset all to default settings.
|
||||||
func Reset() {
|
func Reset() {
|
||||||
configPaths = nil
|
v = New()
|
||||||
configName = "config"
|
|
||||||
|
|
||||||
// extensions Supported
|
|
||||||
SupportedExts = []string{"json", "toml", "yaml", "yml"}
|
SupportedExts = []string{"json", "toml", "yaml", "yml"}
|
||||||
configFile = ""
|
SupportedRemoteProviders = []string{"etcd", "consul"}
|
||||||
configType = ""
|
|
||||||
|
|
||||||
kvstore = make(map[string]interface{})
|
|
||||||
config = make(map[string]interface{})
|
|
||||||
override = make(map[string]interface{})
|
|
||||||
env = make(map[string]string)
|
|
||||||
defaults = make(map[string]interface{})
|
|
||||||
aliases = make(map[string]string)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ func (s *stringValue) String() string {
|
||||||
|
|
||||||
func TestBasics(t *testing.T) {
|
func TestBasics(t *testing.T) {
|
||||||
SetConfigFile("/tmp/config.yaml")
|
SetConfigFile("/tmp/config.yaml")
|
||||||
assert.Equal(t, "/tmp/config.yaml", getConfigFile())
|
assert.Equal(t, "/tmp/config.yaml", v.getConfigFile())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefault(t *testing.T) {
|
func TestDefault(t *testing.T) {
|
||||||
|
@ -95,7 +95,7 @@ func TestMarshalling(t *testing.T) {
|
||||||
SetConfigType("yaml")
|
SetConfigType("yaml")
|
||||||
r := bytes.NewReader(yamlExample)
|
r := bytes.NewReader(yamlExample)
|
||||||
|
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
assert.True(t, InConfig("name"))
|
assert.True(t, InConfig("name"))
|
||||||
assert.False(t, InConfig("state"))
|
assert.False(t, InConfig("state"))
|
||||||
assert.Equal(t, "steve", Get("name"))
|
assert.Equal(t, "steve", Get("name"))
|
||||||
|
@ -136,7 +136,7 @@ func TestYML(t *testing.T) {
|
||||||
SetConfigType("yml")
|
SetConfigType("yml")
|
||||||
r := bytes.NewReader(yamlExample)
|
r := bytes.NewReader(yamlExample)
|
||||||
|
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
assert.Equal(t, "steve", Get("name"))
|
assert.Equal(t, "steve", Get("name"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ func TestJSON(t *testing.T) {
|
||||||
SetConfigType("json")
|
SetConfigType("json")
|
||||||
r := bytes.NewReader(jsonExample)
|
r := bytes.NewReader(jsonExample)
|
||||||
|
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
assert.Equal(t, "0001", Get("id"))
|
assert.Equal(t, "0001", Get("id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +152,17 @@ func TestTOML(t *testing.T) {
|
||||||
SetConfigType("toml")
|
SetConfigType("toml")
|
||||||
r := bytes.NewReader(tomlExample)
|
r := bytes.NewReader(tomlExample)
|
||||||
|
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
assert.Equal(t, "TOML Example", Get("title"))
|
assert.Equal(t, "TOML Example", Get("title"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemotePrecedence(t *testing.T) {
|
func TestRemotePrecedence(t *testing.T) {
|
||||||
SetConfigType("json")
|
SetConfigType("json")
|
||||||
r := bytes.NewReader(jsonExample)
|
r := bytes.NewReader(jsonExample)
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
remote := bytes.NewReader(remoteExample)
|
remote := bytes.NewReader(remoteExample)
|
||||||
assert.Equal(t, "0001", Get("id"))
|
assert.Equal(t, "0001", Get("id"))
|
||||||
MarshallReader(remote, kvstore)
|
MarshallReader(remote, v.kvstore)
|
||||||
assert.Equal(t, "0001", Get("id"))
|
assert.Equal(t, "0001", Get("id"))
|
||||||
assert.NotEqual(t, "cronut", Get("type"))
|
assert.NotEqual(t, "cronut", Get("type"))
|
||||||
assert.Equal(t, "remote", Get("newkey"))
|
assert.Equal(t, "remote", Get("newkey"))
|
||||||
|
@ -175,7 +175,7 @@ func TestRemotePrecedence(t *testing.T) {
|
||||||
func TestEnv(t *testing.T) {
|
func TestEnv(t *testing.T) {
|
||||||
SetConfigType("json")
|
SetConfigType("json")
|
||||||
r := bytes.NewReader(jsonExample)
|
r := bytes.NewReader(jsonExample)
|
||||||
MarshallReader(r, config)
|
MarshallReader(r, v.config)
|
||||||
BindEnv("id")
|
BindEnv("id")
|
||||||
BindEnv("f", "FOOD")
|
BindEnv("f", "FOOD")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue