2014-08-18 08:41:43 +00:00
// Copyright 2014 beego Author. All Rights Reserved.
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2016-03-12 06:32:39 +00:00
// Package config is used to parse config.
2014-08-18 08:41:43 +00:00
// Usage:
2016-03-12 06:32:39 +00:00
// import "github.com/astaxie/beego/config"
//Examples.
2014-08-18 08:41:43 +00:00
//
// cnf, err := config.NewConfig("ini", "config.conf")
//
// cnf APIS:
//
// cnf.Set(key, val string) error
// cnf.String(key string) string
// cnf.Strings(key string) []string
// cnf.Int(key string) (int, error)
// cnf.Int64(key string) (int64, error)
// cnf.Bool(key string) (bool, error)
// cnf.Float(key string) (float64, error)
2016-01-15 06:07:37 +00:00
// cnf.DefaultString(key string, defaultVal string) string
// cnf.DefaultStrings(key string, defaultVal []string) []string
// cnf.DefaultInt(key string, defaultVal int) int
// cnf.DefaultInt64(key string, defaultVal int64) int64
// cnf.DefaultBool(key string, defaultVal bool) bool
// cnf.DefaultFloat(key string, defaultVal float64) float64
2014-08-18 08:41:43 +00:00
// cnf.DIY(key string) (interface{}, error)
// cnf.GetSection(section string) (map[string]string, error)
// cnf.SaveConfigFile(filename string) error
2016-03-12 06:32:39 +00:00
//More docs http://beego.me/docs/module/config.md
2013-08-21 16:07:33 +00:00
package config
import (
"fmt"
2016-01-27 12:46:30 +00:00
"os"
2016-11-29 13:38:40 +00:00
"reflect"
"time"
2013-08-21 16:07:33 +00:00
)
2015-09-10 06:53:19 +00:00
// Configer defines how to get and set value from configuration raw data.
type Configer interface {
2016-01-15 06:07:37 +00:00
Set ( key , val string ) error //support section::key type in given key when using ini type.
String ( key string ) string //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
2014-01-15 09:19:03 +00:00
Strings ( key string ) [ ] string //get string slice
2013-08-21 16:07:33 +00:00
Int ( key string ) ( int , error )
Int64 ( key string ) ( int64 , error )
Bool ( key string ) ( bool , error )
Float ( key string ) ( float64 , error )
2016-01-15 06:07:37 +00:00
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.
DefaultStrings ( key string , defaultVal [ ] string ) [ ] string //get string slice
DefaultInt ( key string , defaultVal int ) int
DefaultInt64 ( key string , defaultVal int64 ) int64
DefaultBool ( key string , defaultVal bool ) bool
DefaultFloat ( key string , defaultVal float64 ) float64
2013-08-21 16:07:33 +00:00
DIY ( key string ) ( interface { } , error )
config: add more method
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.
DefaultStrings(key string, defaultval []string) []string //get string
slice
DefaultInt(key string, defaultval int) int
DefaultInt64(key string, defaultval int64) int64
DefaultBool(key string, defaultval bool) bool
DefaultFloat(key string, defaultval float64) float64
DIY(key string) (interface{}, error)
GetSection(section string) (map[string]string, error)
SaveConfigFile(filename string) error
2014-08-07 09:24:21 +00:00
GetSection ( section string ) ( map [ string ] string , error )
SaveConfigFile ( filename string ) error
2013-08-21 16:07:33 +00:00
}
2015-09-10 06:53:19 +00:00
// Config is the adapter interface for parsing config file to get raw data to Configer.
2013-08-21 16:07:33 +00:00
type Config interface {
2015-09-10 06:53:19 +00:00
Parse ( key string ) ( Configer , error )
ParseData ( data [ ] byte ) ( Configer , error )
2013-08-21 16:07:33 +00:00
}
var adapters = make ( map [ string ] Config )
// Register makes a config adapter available by the adapter name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register ( name string , adapter Config ) {
if adapter == nil {
panic ( "config: Register adapter is nil" )
}
2014-07-12 08:03:14 +00:00
if _ , ok := adapters [ name ] ; ok {
2013-08-21 16:07:33 +00:00
panic ( "config: Register called twice for adapter " + name )
}
adapters [ name ] = adapter
}
2015-09-10 06:53:19 +00:00
// NewConfig adapterName is ini/json/xml/yaml.
2013-12-24 13:57:33 +00:00
// filename is the config file path.
2015-09-10 06:53:19 +00:00
func NewConfig ( adapterName , filename string ) ( Configer , error ) {
2013-08-21 16:07:33 +00:00
adapter , ok := adapters [ adapterName ]
if ! ok {
return nil , fmt . Errorf ( "config: unknown adaptername %q (forgotten import?)" , adapterName )
}
2015-08-26 08:57:28 +00:00
return adapter . Parse ( filename )
2013-08-21 16:07:33 +00:00
}
config: add more method
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.
DefaultStrings(key string, defaultval []string) []string //get string
slice
DefaultInt(key string, defaultval int) int
DefaultInt64(key string, defaultval int64) int64
DefaultBool(key string, defaultval bool) bool
DefaultFloat(key string, defaultval float64) float64
DIY(key string) (interface{}, error)
GetSection(section string) (map[string]string, error)
SaveConfigFile(filename string) error
2014-08-07 09:24:21 +00:00
2015-09-10 06:53:19 +00:00
// NewConfigData adapterName is ini/json/xml/yaml.
config: add more method
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.
DefaultStrings(key string, defaultval []string) []string //get string
slice
DefaultInt(key string, defaultval int) int
DefaultInt64(key string, defaultval int64) int64
DefaultBool(key string, defaultval bool) bool
DefaultFloat(key string, defaultval float64) float64
DIY(key string) (interface{}, error)
GetSection(section string) (map[string]string, error)
SaveConfigFile(filename string) error
2014-08-07 09:24:21 +00:00
// data is the config data.
2015-09-10 06:53:19 +00:00
func NewConfigData ( adapterName string , data [ ] byte ) ( Configer , error ) {
config: add more method
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.
DefaultStrings(key string, defaultval []string) []string //get string
slice
DefaultInt(key string, defaultval int) int
DefaultInt64(key string, defaultval int64) int64
DefaultBool(key string, defaultval bool) bool
DefaultFloat(key string, defaultval float64) float64
DIY(key string) (interface{}, error)
GetSection(section string) (map[string]string, error)
SaveConfigFile(filename string) error
2014-08-07 09:24:21 +00:00
adapter , ok := adapters [ adapterName ]
if ! ok {
return nil , fmt . Errorf ( "config: unknown adaptername %q (forgotten import?)" , adapterName )
}
return adapter . ParseData ( data )
}
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
2016-03-29 13:47:33 +00:00
// ExpandValueEnvForMap convert all string value with environment variable.
func ExpandValueEnvForMap ( m map [ string ] interface { } ) map [ string ] interface { } {
2016-03-12 06:32:39 +00:00
for k , v := range m {
switch value := v . ( type ) {
case string :
2016-03-29 13:47:33 +00:00
m [ k ] = ExpandValueEnv ( value )
2016-03-12 06:32:39 +00:00
case map [ string ] interface { } :
2016-03-29 13:47:33 +00:00
m [ k ] = ExpandValueEnvForMap ( value )
2016-03-12 06:32:39 +00:00
case map [ string ] string :
for k2 , v2 := range value {
2016-03-29 13:47:33 +00:00
value [ k2 ] = ExpandValueEnv ( v2 )
2016-03-12 06:32:39 +00:00
}
m [ k ] = value
2016-01-27 12:46:30 +00:00
}
}
2016-03-12 06:32:39 +00:00
return m
2016-01-27 12:46:30 +00:00
}
2016-03-29 13:47:33 +00:00
// ExpandValueEnv returns value of convert with environment variable.
2016-03-12 06:32:39 +00:00
//
2016-03-29 13:47:33 +00:00
// Return environment variable if value start with "${" and end with "}".
2016-03-12 06:32:39 +00:00
// Return default value if environment variable is empty or not exist.
//
2016-03-29 13:47:33 +00:00
// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue".
2016-03-12 06:32:39 +00:00
// Examples:
2016-03-29 13:47:33 +00:00
// v1 := config.ExpandValueEnv("${GOPATH}") // return the GOPATH environment variable.
// v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}") // return the default value "/usr/local/go/".
// v3 := config.ExpandValueEnv("Astaxie") // return the value "Astaxie".
func ExpandValueEnv ( value string ) ( realValue string ) {
2016-03-12 06:32:39 +00:00
realValue = value
2016-03-29 13:47:33 +00:00
vLen := len ( value )
// 3 = ${}
if vLen < 3 {
2016-03-12 06:32:39 +00:00
return
2016-02-04 12:15:37 +00:00
}
2016-03-29 13:47:33 +00:00
// Need start with "${" and end with "}", then return.
if value [ 0 ] != '$' || value [ 1 ] != '{' || value [ vLen - 1 ] != '}' {
2016-03-12 06:32:39 +00:00
return
}
2016-03-29 13:47:33 +00:00
key := ""
2018-03-27 15:29:13 +00:00
defaultV := ""
2016-03-29 13:47:33 +00:00
// value start with "${"
for i := 2 ; i < vLen ; i ++ {
if value [ i ] == '|' && ( i + 1 < vLen && value [ i + 1 ] == '|' ) {
key = value [ 2 : i ]
2018-03-27 15:29:13 +00:00
defaultV = value [ i + 2 : vLen - 1 ] // other string is default value.
2016-03-29 13:47:33 +00:00
break
} else if value [ i ] == '}' {
key = value [ 2 : i ]
break
2016-02-04 12:15:37 +00:00
}
}
2016-03-12 06:32:39 +00:00
2016-03-29 13:47:33 +00:00
realValue = os . Getenv ( key )
if realValue == "" {
2018-03-27 15:29:13 +00:00
realValue = defaultV
2016-03-29 13:47:33 +00:00
}
2016-03-12 06:32:39 +00:00
return
2016-02-04 12:15:37 +00:00
}
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
// ParseBool returns the boolean value represented by the string.
//
// It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On,
// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
// Any other value returns an error.
func ParseBool ( val interface { } ) ( value bool , err error ) {
if val != nil {
switch v := val . ( type ) {
case bool :
return v , nil
case string :
switch v {
case "1" , "t" , "T" , "true" , "TRUE" , "True" , "YES" , "yes" , "Yes" , "Y" , "y" , "ON" , "on" , "On" :
return true , nil
case "0" , "f" , "F" , "false" , "FALSE" , "False" , "NO" , "no" , "No" , "N" , "n" , "OFF" , "off" , "Off" :
return false , nil
}
case int8 , int32 , int64 :
2017-07-04 03:03:49 +00:00
strV := fmt . Sprintf ( "%d" , v )
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
if strV == "1" {
return true , nil
} else if strV == "0" {
return false , nil
}
case float64 :
2017-07-04 03:03:49 +00:00
if v == 1.0 {
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
return true , nil
2017-07-04 03:03:49 +00:00
} else if v == 0.0 {
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
return false , nil
}
}
return false , fmt . Errorf ( "parsing %q: invalid syntax" , val )
}
2016-01-25 12:57:41 +00:00
return false , fmt . Errorf ( "parsing <nil>: invalid syntax" )
Support Parse Bool with more diffrent values
ParseBool returns the boolean value represented by the string.
It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on,
On,
0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
Any other value returns an error.
2016-01-23 03:02:40 +00:00
}
2016-11-29 13:38:40 +00:00
// ToString converts values of any type to string.
func ToString ( x interface { } ) string {
switch y := x . ( type ) {
// Handle dates with special logic
// This needs to come above the fmt.Stringer
// test since time.Time's have a .String()
// method
case time . Time :
return y . Format ( "A Monday" )
// Handle type string
case string :
return y
// Handle type with .String() method
case fmt . Stringer :
return y . String ( )
// Handle type with .Error() method
case error :
return y . Error ( )
}
// Handle named string type
if v := reflect . ValueOf ( x ) ; v . Kind ( ) == reflect . String {
return v . String ( )
}
// Fallback to fmt package for anything else like numeric types
return fmt . Sprint ( x )
}