github.com/astaxie/beego@v1.12.3/config/config.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package config is used to parse config.
    16  // Usage:
    17  //  import "github.com/astaxie/beego/config"
    18  //Examples.
    19  //
    20  //  cnf, err := config.NewConfig("ini", "config.conf")
    21  //
    22  //  cnf APIS:
    23  //
    24  //  cnf.Set(key, val string) error
    25  //  cnf.String(key string) string
    26  //  cnf.Strings(key string) []string
    27  //  cnf.Int(key string) (int, error)
    28  //  cnf.Int64(key string) (int64, error)
    29  //  cnf.Bool(key string) (bool, error)
    30  //  cnf.Float(key string) (float64, error)
    31  //  cnf.DefaultString(key string, defaultVal string) string
    32  //  cnf.DefaultStrings(key string, defaultVal []string) []string
    33  //  cnf.DefaultInt(key string, defaultVal int) int
    34  //  cnf.DefaultInt64(key string, defaultVal int64) int64
    35  //  cnf.DefaultBool(key string, defaultVal bool) bool
    36  //  cnf.DefaultFloat(key string, defaultVal float64) float64
    37  //  cnf.DIY(key string) (interface{}, error)
    38  //  cnf.GetSection(section string) (map[string]string, error)
    39  //  cnf.SaveConfigFile(filename string) error
    40  //More docs http://beego.me/docs/module/config.md
    41  package config
    42  
    43  import (
    44  	"fmt"
    45  	"os"
    46  	"reflect"
    47  	"time"
    48  )
    49  
    50  // Configer defines how to get and set value from configuration raw data.
    51  type Configer interface {
    52  	Set(key, val string) error   //support section::key type in given key when using ini type.
    53  	String(key string) string    //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
    54  	Strings(key string) []string //get string slice
    55  	Int(key string) (int, error)
    56  	Int64(key string) (int64, error)
    57  	Bool(key string) (bool, error)
    58  	Float(key string) (float64, error)
    59  	DefaultString(key string, defaultVal string) string      // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
    60  	DefaultStrings(key string, defaultVal []string) []string //get string slice
    61  	DefaultInt(key string, defaultVal int) int
    62  	DefaultInt64(key string, defaultVal int64) int64
    63  	DefaultBool(key string, defaultVal bool) bool
    64  	DefaultFloat(key string, defaultVal float64) float64
    65  	DIY(key string) (interface{}, error)
    66  	GetSection(section string) (map[string]string, error)
    67  	SaveConfigFile(filename string) error
    68  }
    69  
    70  // Config is the adapter interface for parsing config file to get raw data to Configer.
    71  type Config interface {
    72  	Parse(key string) (Configer, error)
    73  	ParseData(data []byte) (Configer, error)
    74  }
    75  
    76  var adapters = make(map[string]Config)
    77  
    78  // Register makes a config adapter available by the adapter name.
    79  // If Register is called twice with the same name or if driver is nil,
    80  // it panics.
    81  func Register(name string, adapter Config) {
    82  	if adapter == nil {
    83  		panic("config: Register adapter is nil")
    84  	}
    85  	if _, ok := adapters[name]; ok {
    86  		panic("config: Register called twice for adapter " + name)
    87  	}
    88  	adapters[name] = adapter
    89  }
    90  
    91  // NewConfig adapterName is ini/json/xml/yaml.
    92  // filename is the config file path.
    93  func NewConfig(adapterName, filename string) (Configer, error) {
    94  	adapter, ok := adapters[adapterName]
    95  	if !ok {
    96  		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
    97  	}
    98  	return adapter.Parse(filename)
    99  }
   100  
   101  // NewConfigData adapterName is ini/json/xml/yaml.
   102  // data is the config data.
   103  func NewConfigData(adapterName string, data []byte) (Configer, error) {
   104  	adapter, ok := adapters[adapterName]
   105  	if !ok {
   106  		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
   107  	}
   108  	return adapter.ParseData(data)
   109  }
   110  
   111  // ExpandValueEnvForMap convert all string value with environment variable.
   112  func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} {
   113  	for k, v := range m {
   114  		switch value := v.(type) {
   115  		case string:
   116  			m[k] = ExpandValueEnv(value)
   117  		case map[string]interface{}:
   118  			m[k] = ExpandValueEnvForMap(value)
   119  		case map[string]string:
   120  			for k2, v2 := range value {
   121  				value[k2] = ExpandValueEnv(v2)
   122  			}
   123  			m[k] = value
   124  		}
   125  	}
   126  	return m
   127  }
   128  
   129  // ExpandValueEnv returns value of convert with environment variable.
   130  //
   131  // Return environment variable if value start with "${" and end with "}".
   132  // Return default value if environment variable is empty or not exist.
   133  //
   134  // It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue".
   135  // Examples:
   136  //	v1 := config.ExpandValueEnv("${GOPATH}")			// return the GOPATH environment variable.
   137  //	v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}")	// return the default value "/usr/local/go/".
   138  //	v3 := config.ExpandValueEnv("Astaxie")				// return the value "Astaxie".
   139  func ExpandValueEnv(value string) (realValue string) {
   140  	realValue = value
   141  
   142  	vLen := len(value)
   143  	// 3 = ${}
   144  	if vLen < 3 {
   145  		return
   146  	}
   147  	// Need start with "${" and end with "}", then return.
   148  	if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' {
   149  		return
   150  	}
   151  
   152  	key := ""
   153  	defaultV := ""
   154  	// value start with "${"
   155  	for i := 2; i < vLen; i++ {
   156  		if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') {
   157  			key = value[2:i]
   158  			defaultV = value[i+2 : vLen-1] // other string is default value.
   159  			break
   160  		} else if value[i] == '}' {
   161  			key = value[2:i]
   162  			break
   163  		}
   164  	}
   165  
   166  	realValue = os.Getenv(key)
   167  	if realValue == "" {
   168  		realValue = defaultV
   169  	}
   170  
   171  	return
   172  }
   173  
   174  // ParseBool returns the boolean value represented by the string.
   175  //
   176  // It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On,
   177  // 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
   178  // Any other value returns an error.
   179  func ParseBool(val interface{}) (value bool, err error) {
   180  	if val != nil {
   181  		switch v := val.(type) {
   182  		case bool:
   183  			return v, nil
   184  		case string:
   185  			switch v {
   186  			case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On":
   187  				return true, nil
   188  			case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off":
   189  				return false, nil
   190  			}
   191  		case int8, int32, int64:
   192  			strV := fmt.Sprintf("%d", v)
   193  			if strV == "1" {
   194  				return true, nil
   195  			} else if strV == "0" {
   196  				return false, nil
   197  			}
   198  		case float64:
   199  			if v == 1.0 {
   200  				return true, nil
   201  			} else if v == 0.0 {
   202  				return false, nil
   203  			}
   204  		}
   205  		return false, fmt.Errorf("parsing %q: invalid syntax", val)
   206  	}
   207  	return false, fmt.Errorf("parsing <nil>: invalid syntax")
   208  }
   209  
   210  // ToString converts values of any type to string.
   211  func ToString(x interface{}) string {
   212  	switch y := x.(type) {
   213  
   214  	// Handle dates with special logic
   215  	// This needs to come above the fmt.Stringer
   216  	// test since time.Time's have a .String()
   217  	// method
   218  	case time.Time:
   219  		return y.Format("A Monday")
   220  
   221  	// Handle type string
   222  	case string:
   223  		return y
   224  
   225  	// Handle type with .String() method
   226  	case fmt.Stringer:
   227  		return y.String()
   228  
   229  	// Handle type with .Error() method
   230  	case error:
   231  		return y.Error()
   232  
   233  	}
   234  
   235  	// Handle named string type
   236  	if v := reflect.ValueOf(x); v.Kind() == reflect.String {
   237  		return v.String()
   238  	}
   239  
   240  	// Fallback to fmt package for anything else like numeric types
   241  	return fmt.Sprint(x)
   242  }