github.com/eframework-cn/EP.GO.UTIL@v1.0.0/xconfig/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 xconfig 16 17 import ( 18 "fmt" 19 "os" 20 "reflect" 21 "time" 22 ) 23 24 // Configer defines how to get and set value from configuration raw data. 25 type Configer interface { 26 Set(key, val string) error //support section::key type in given key when using ini type. 27 String(key string) string //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. 28 Strings(key string) []string //get string slice 29 Int(key string) (int, error) 30 Int64(key string) (int64, error) 31 Bool(key string) (bool, error) 32 Float(key string) (float64, error) 33 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. 34 DefaultStrings(key string, defaultVal []string) []string //get string slice 35 DefaultInt(key string, defaultVal int) int 36 DefaultInt64(key string, defaultVal int64) int64 37 DefaultBool(key string, defaultVal bool) bool 38 DefaultFloat(key string, defaultVal float64) float64 39 DIY(key string) (interface{}, error) 40 GetSection(section string) (map[string]string, error) 41 SaveConfigFile(filename string) error 42 } 43 44 // Config is the adapter interface for parsing config file to get raw data to Configer. 45 type Config interface { 46 Parse(key string) (Configer, error) 47 ParseData(data []byte) (Configer, error) 48 } 49 50 var adapters = make(map[string]Config) 51 52 // Register makes a config adapter available by the adapter name. 53 // If Register is called twice with the same name or if driver is nil, 54 // it panics. 55 func Register(name string, adapter Config) { 56 if adapter == nil { 57 panic("config: Register adapter is nil") 58 } 59 if _, ok := adapters[name]; ok { 60 panic("config: Register called twice for adapter " + name) 61 } 62 adapters[name] = adapter 63 } 64 65 // NewConfig adapterName is ini/json/xml/yaml. 66 // filename is the config file path. 67 func NewConfig(adapterName, filename string) (Configer, error) { 68 adapter, ok := adapters[adapterName] 69 if !ok { 70 return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) 71 } 72 return adapter.Parse(filename) 73 } 74 75 // NewConfigData adapterName is ini/json/xml/yaml. 76 // data is the config data. 77 func NewConfigData(adapterName string, data []byte) (Configer, error) { 78 adapter, ok := adapters[adapterName] 79 if !ok { 80 return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) 81 } 82 return adapter.ParseData(data) 83 } 84 85 // ExpandValueEnvForMap convert all string value with environment variable. 86 func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} { 87 for k, v := range m { 88 switch value := v.(type) { 89 case string: 90 m[k] = ExpandValueEnv(value) 91 case map[string]interface{}: 92 m[k] = ExpandValueEnvForMap(value) 93 case map[string]string: 94 for k2, v2 := range value { 95 value[k2] = ExpandValueEnv(v2) 96 } 97 m[k] = value 98 } 99 } 100 return m 101 } 102 103 // ExpandValueEnv returns value of convert with environment variable. 104 // 105 // Return environment variable if value start with "${" and end with "}". 106 // Return default value if environment variable is empty or not exist. 107 // 108 // It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue". 109 // Examples: 110 // v1 := config.ExpandValueEnv("${GOPATH}") // return the GOPATH environment variable. 111 // v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}") // return the default value "/usr/local/go/". 112 // v3 := config.ExpandValueEnv("Astaxie") // return the value "Astaxie". 113 func ExpandValueEnv(value string) (realValue string) { 114 realValue = value 115 116 vLen := len(value) 117 // 3 = ${} 118 if vLen < 3 { 119 return 120 } 121 // Need start with "${" and end with "}", then return. 122 if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' { 123 return 124 } 125 126 key := "" 127 defaultV := "" 128 // value start with "${" 129 for i := 2; i < vLen; i++ { 130 if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') { 131 key = value[2:i] 132 defaultV = value[i+2 : vLen-1] // other string is default value. 133 break 134 } else if value[i] == '}' { 135 key = value[2:i] 136 break 137 } 138 } 139 140 realValue = os.Getenv(key) 141 if realValue == "" { 142 realValue = defaultV 143 } 144 145 return 146 } 147 148 // ParseBool returns the boolean value represented by the string. 149 // 150 // It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On, 151 // 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off. 152 // Any other value returns an error. 153 func ParseBool(val interface{}) (value bool, err error) { 154 if val != nil { 155 switch v := val.(type) { 156 case bool: 157 return v, nil 158 case string: 159 switch v { 160 case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On": 161 return true, nil 162 case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off": 163 return false, nil 164 } 165 case int8, int32, int64: 166 strV := fmt.Sprintf("%d", v) 167 if strV == "1" { 168 return true, nil 169 } else if strV == "0" { 170 return false, nil 171 } 172 case float64: 173 if v == 1.0 { 174 return true, nil 175 } else if v == 0.0 { 176 return false, nil 177 } 178 } 179 return false, fmt.Errorf("parsing %q: invalid syntax", val) 180 } 181 return false, fmt.Errorf("parsing <nil>: invalid syntax") 182 } 183 184 // ToString converts values of any type to string. 185 func ToString(x interface{}) string { 186 switch y := x.(type) { 187 188 // Handle dates with special logic 189 // This needs to come above the fmt.Stringer 190 // test since time.Time's have a .String() 191 // method 192 case time.Time: 193 return y.Format("A Monday") 194 195 // Handle type string 196 case string: 197 return y 198 199 // Handle type with .String() method 200 case fmt.Stringer: 201 return y.String() 202 203 // Handle type with .Error() method 204 case error: 205 return y.Error() 206 207 } 208 209 // Handle named string type 210 if v := reflect.ValueOf(x); v.Kind() == reflect.String { 211 return v.String() 212 } 213 214 // Fallback to fmt package for anything else like numeric types 215 return fmt.Sprint(x) 216 }