diff --git a/config/config.go b/config/config.go
index ef7738d9..59cc356b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package config is used to parse config
+// Package config is used to parse config.
// Usage:
-// import(
-// "github.com/astaxie/beego/config"
-// )
+// import "github.com/astaxie/beego/config"
+//Examples.
//
// cnf, err := config.NewConfig("ini", "config.conf")
//
@@ -38,8 +37,7 @@
// cnf.DIY(key string) (interface{}, error)
// cnf.GetSection(section string) (map[string]string, error)
// cnf.SaveConfigFile(filename string) error
-//
-// more docs http://beego.me/docs/module/config.md
+//More docs http://beego.me/docs/module/config.md
package config
import (
@@ -109,52 +107,61 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) {
return adapter.ParseData(data)
}
-const envKeySign = "$ENV_"
-
-// Getenv return environment variable if env has prefix "$ENV_".
-func Getenv(env interface{}) (string, bool) {
- if env == nil {
- return "", false
- }
-
- // Onley support string key.
- if key, ok := env.(string); ok {
-
- if envKey := strings.TrimPrefix(key, envKeySign); envKey != key {
- return os.Getenv(envKey), true
+// ChooseRealValueForMap convert all string value with environment variable.
+func ChooseRealValueForMap(m map[string]interface{}) map[string]interface{} {
+ for k, v := range m {
+ switch value := v.(type) {
+ case string:
+ m[k] = ChooseRealValue(value)
+ case map[string]interface{}:
+ m[k] = ChooseRealValueForMap(value)
+ case map[string]string:
+ for k2, v2 := range value {
+ value[k2] = ChooseRealValue(v2)
+ }
+ m[k] = value
}
}
- return "", false
+ return m
}
-// ConvertToStringMap convert interface to string config value only for map[string]interface{} config info.
-func ConvertToStringMap(m map[string]interface{}) map[string]string {
- items := make(map[string]string, len(m))
- if m == nil || len(m) == 0 {
- return items
+// ChooseRealValue returns value of convert with environment variable.
+//
+// Return environment variable if value start with "$$".
+// Return default value if environment variable is empty or not exist.
+//
+// It accept value formats "$$env" , "$$env||" , "$$env||defaultValue" , "defaultvalue".
+// Examples:
+// v1 := config.ChooseRealValue("$$GOROOT") // return the GOROOT environment variable.
+// v2 := config.ChooseRealValue("$$GOAsta||/usr/local/go/") // return the default value "/usr/local/go/".
+// v3 := config.ChooseRealValue("Astaxie") // return the value "Astaxie".
+func ChooseRealValue(value string) (realValue string) {
+ realValue = value
+
+ if value == "" {
+ return
}
- var s string
- for k, v := range m {
- s = ""
- if v == nil {
- s = ""
- } else if str, ok := v.(string); ok {
- s = str
- } else if m, ok := v.(map[string]interface{}); ok {
- s = fmt.Sprintf("%+v", ConvertToStringMap(m))
- } else {
- s = fmt.Sprintf("%+v", v)
- }
+ sign := "$$" // Environment variable identifier.
+ sep := "||" // Environment variable and default value separator.
- if len(s) > 0 {
- if env, ok := Getenv(s); ok {
- s = env
- }
- }
- items[k] = s
+ // Not use environment variable.
+ if strings.HasPrefix(value, sign) == false {
+ return
}
- return items
+
+ sepIndex := strings.Index(value, sep)
+ if sepIndex == -1 {
+ realValue = os.Getenv(string(value[len(sign):]))
+ } else {
+ realValue = os.Getenv(string(value[len(sign):sepIndex]))
+ // Find defalut value.
+ if realValue == "" {
+ realValue = string(value[sepIndex+len(sep):])
+ }
+ }
+
+ return
}
// ParseBool returns the boolean value represented by the string.
diff --git a/config/fake.go b/config/fake.go
index 347f1cfe..f5144598 100644
--- a/config/fake.go
+++ b/config/fake.go
@@ -25,15 +25,7 @@ type fakeConfigContainer struct {
}
func (c *fakeConfigContainer) getData(key string) string {
- if len(key) == 0 {
- return ""
- }
-
- v := c.data[strings.ToLower(key)]
- if env, ok := Getenv(v); ok {
- return env
- }
- return v
+ return c.data[strings.ToLower(key)]
}
func (c *fakeConfigContainer) Set(key, val string) error {
diff --git a/config/ini.go b/config/ini.go
index 0d8571e4..829901d8 100644
--- a/config/ini.go
+++ b/config/ini.go
@@ -162,7 +162,7 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
val = bytes.Trim(val, `"`)
}
- cfg.data[section][key] = string(val)
+ cfg.data[section][key] = ChooseRealValue(string(val))
if comment.Len() > 0 {
cfg.keyComment[section+"."+key] = comment.String()
comment.Reset()
@@ -291,17 +291,14 @@ func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []s
// GetSection returns map for the given section
func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) {
if v, ok := c.data[section]; ok {
- for k, vv := range v {
- if env, ok := Getenv(vv); ok {
- v[k] = env
- }
- }
return v, nil
}
return nil, errors.New("not exist setction")
}
-// SaveConfigFile save the config into file
+// SaveConfigFile save the config into file.
+//
+// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation.
func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
// Write configuration file by filename.
f, err := os.Create(filename)
@@ -458,9 +455,6 @@ func (c *IniConfigContainer) getdata(key string) string {
}
if v, ok := c.data[section]; ok {
if vv, ok := v[k]; ok {
- if env, ok := Getenv(vv); ok {
- return env
- }
return vv
}
}
diff --git a/config/ini_test.go b/config/ini_test.go
index 9396db5b..b3f57fbe 100644
--- a/config/ini_test.go
+++ b/config/ini_test.go
@@ -42,13 +42,20 @@ needlogin = ON
enableSession = Y
enableCookie = N
flag = 1
-path = $ENV_GOROOT
+path1 = $$GOROOT
+path2 = $$GOROOT||/home/go
+path3 = $$GOROOT$$GOPATH2||/home/go
+token1 = $$TOKEN
+token2 = $$TOKEN||
+token3 = $$TOKEN||astaxie
+token4 = token$$TOKEN
+token5 = $$TOKEN$$TOKEN||TOKEN
[demo]
key1="asta"
key2 = "xie"
CaseInsensitive = true
peers = one;two;three
-password = $ENV_GOROOT
+password = $$GOROOT
`
keyValue = map[string]interface{}{
@@ -66,7 +73,14 @@ password = $ENV_GOROOT
"enableSession": true,
"enableCookie": false,
"flag": true,
- "path": os.Getenv("GOROOT"),
+ "path1": os.Getenv("GOROOT"),
+ "path2": os.Getenv("GOROOT"),
+ "path3": "/home/go",
+ "token1": "",
+ "token2": "",
+ "token3": "astaxie",
+ "token4": "token$$TOKEN",
+ "token5": "TOKEN",
"demo::key1": "asta",
"demo::key2": "xie",
"demo::CaseInsensitive": true,
@@ -145,7 +159,6 @@ httpport = 8080
# db type name
# suport mysql,sqlserver
name = mysql
-path = $ENV_GOROOT
`
saveResult = `
@@ -162,7 +175,6 @@ httpport=8080
# db type name
# suport mysql,sqlserver
name=mysql
-path=$ENV_GOROOT
`
)
cfg, err := NewConfigData("ini", []byte(inicontext))
diff --git a/config/json.go b/config/json.go
index ecef9439..3b4569b8 100644
--- a/config/json.go
+++ b/config/json.go
@@ -57,6 +57,9 @@ func (js *JSONConfig) ParseData(data []byte) (Configer, error) {
}
x.data["rootArray"] = wrappingArray
}
+
+ x.data = ChooseRealValueForMap(x.data)
+
return x, nil
}
@@ -250,18 +253,11 @@ func (c *JSONConfigContainer) getData(key string) interface{} {
}
}
}
- if env, ok := Getenv(curValue); ok {
- return env
- }
return curValue
}
if v, ok := c.data[key]; ok {
- if env, ok := Getenv(v); ok {
- return env
- }
return v
}
-
return nil
}
diff --git a/config/json_test.go b/config/json_test.go
index 4ac2cdfc..6ff26dba 100644
--- a/config/json_test.go
+++ b/config/json_test.go
@@ -86,18 +86,25 @@ func TestJson(t *testing.T) {
"enableSession": "Y",
"enableCookie": "N",
"flag": 1,
-"path": "$ENV_GOROOT",
+"path1": "$$GOROOT",
+"path2": "$$GOROOT||/home/go",
+"path3": "$$GOROOT$$GOPATH2||/home/go",
+"token1": "$$TOKEN",
+"token2": "$$TOKEN||",
+"token3": "$$TOKEN||astaxie",
+"token4": "token$$TOKEN",
+"token5": "$$TOKEN$$TOKEN||TOKEN",
"database": {
"host": "host",
"port": "port",
"database": "database",
"username": "username",
- "password": "$ENV_GOROOT",
+ "password": "$$GOROOT",
"conns":{
"maxconnection":12,
"autoconnect":true,
"connectioninfo":"info",
- "root": "$ENV_GOROOT"
+ "root": "$$GOROOT"
}
}
}`
@@ -117,7 +124,14 @@ func TestJson(t *testing.T) {
"enableSession": true,
"enableCookie": false,
"flag": true,
- "path": os.Getenv("GOROOT"),
+ "path1": os.Getenv("GOROOT"),
+ "path2": os.Getenv("GOROOT"),
+ "path3": "/home/go",
+ "token1": "",
+ "token2": "",
+ "token3": "astaxie",
+ "token4": "token$$TOKEN",
+ "token5": "TOKEN",
"database::host": "host",
"database::port": "port",
"database::database": "database",
diff --git a/config/xml/xml.go b/config/xml/xml.go
index a9218b03..63f3cb23 100644
--- a/config/xml/xml.go
+++ b/config/xml/xml.go
@@ -12,21 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package xml for config provider
+// Package xml for config provider.
//
-// depend on github.com/beego/x2j
+// depend on github.com/beego/x2j.
//
-// go install github.com/beego/x2j
+// go install github.com/beego/x2j.
//
// Usage:
-// import(
-// _ "github.com/astaxie/beego/config/xml"
-// "github.com/astaxie/beego/config"
-// )
+// import(
+// _ "github.com/astaxie/beego/config/xml"
+// "github.com/astaxie/beego/config"
+// )
//
// cnf, err := config.NewConfig("xml", "config.xml")
//
-// more docs http://beego.me/docs/module/config.md
+//More docs http://beego.me/docs/module/config.md
package xml
import (
@@ -69,7 +69,7 @@ func (xc *Config) Parse(filename string) (config.Configer, error) {
return nil, err
}
- x.data = d["config"].(map[string]interface{})
+ x.data = config.ChooseRealValueForMap(d["config"].(map[string]interface{}))
return x, nil
}
@@ -92,7 +92,7 @@ type ConfigContainer struct {
// Bool returns the boolean value for a given key.
func (c *ConfigContainer) Bool(key string) (bool, error) {
- if v := c.getData(key); v != nil {
+ if v := c.data[key]; v != nil {
return config.ParseBool(v)
}
return false, fmt.Errorf("not exist key: %q", key)
@@ -110,7 +110,7 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
// Int returns the integer value for a given key.
func (c *ConfigContainer) Int(key string) (int, error) {
- return strconv.Atoi(c.getData(key).(string))
+ return strconv.Atoi(c.data[key].(string))
}
// DefaultInt returns the integer value for a given key.
@@ -125,7 +125,7 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
// Int64 returns the int64 value for a given key.
func (c *ConfigContainer) Int64(key string) (int64, error) {
- return strconv.ParseInt(c.getData(key).(string), 10, 64)
+ return strconv.ParseInt(c.data[key].(string), 10, 64)
}
// DefaultInt64 returns the int64 value for a given key.
@@ -141,7 +141,7 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
// Float returns the float value for a given key.
func (c *ConfigContainer) Float(key string) (float64, error) {
- return strconv.ParseFloat(c.getData(key).(string), 64)
+ return strconv.ParseFloat(c.data[key].(string), 64)
}
// DefaultFloat returns the float64 value for a given key.
@@ -156,7 +156,7 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
// String returns the string value for a given key.
func (c *ConfigContainer) String(key string) string {
- if v, ok := c.getData(key).(string); ok {
+ if v, ok := c.data[key].(string); ok {
return v
}
return ""
@@ -194,7 +194,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri
// GetSection returns map for the given section
func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
if v, ok := c.data[section]; ok {
- return config.ConvertToStringMap(v.(map[string]interface{})), nil
+ return v.(map[string]string), nil
}
return nil, errors.New("not exist setction")
}
@@ -231,18 +231,6 @@ func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
return nil, errors.New("not exist key")
}
-// Get Data
-func (c *ConfigContainer) getData(key string) interface{} {
- if v, ok := c.data[key]; ok {
- if env, ok := config.Getenv(v); ok {
- return env
- }
- return v
-
- }
- return nil
-}
-
func init() {
config.Register("xml", &Config{})
}
diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go
index 5ef43c9b..85c92e8b 100644
--- a/config/xml/xml_test.go
+++ b/config/xml/xml_test.go
@@ -15,8 +15,8 @@
package xml
import (
+ "fmt"
"os"
- "strings"
"testing"
"github.com/astaxie/beego/config"
@@ -24,8 +24,9 @@ import (
func TestXML(t *testing.T) {
- //xml parse should incluce in tags
- var xmlcontext = `
+ var (
+ //xml parse should incluce in tags
+ xmlcontext = `
beeapi
8080
@@ -34,23 +35,36 @@ func TestXML(t *testing.T) {
dev
false
true
-$ENV_GOROOT
-
- beego
- $ENV_GOROOT
- localhost
-
- value1
- $ENV_GOROOT
-
-
-
- 001
- gp2
-
-
+$$GOROOT
+$$GOROOT||/home/go
+$$GOROOT$$GOPATH2||/home/go
+$$TOKEN
+$$TOKEN||
+$$TOKEN||astaxie
+token$$TOKEN
+$$TOKEN$$TOKEN||TOKEN
`
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "PI": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "path1": os.Getenv("GOROOT"),
+ "path2": os.Getenv("GOROOT"),
+ "path3": "/home/go",
+ "token1": "",
+ "token2": "",
+ "token3": "astaxie",
+ "token4": "token$$TOKEN",
+ "token5": "TOKEN",
+ "error": "",
+ "emptystrings": []string{},
+ }
+ )
f, err := os.Create("testxml.conf")
if err != nil {
@@ -67,50 +81,42 @@ func TestXML(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if xmlconf.String("appname") != "beeapi" {
- t.Fatal("appname not equal to beeapi")
- }
- if port, err := xmlconf.Int("httpport"); err != nil || port != 8080 {
- t.Error(port)
- t.Fatal(err)
- }
- if port, err := xmlconf.Int64("mysqlport"); err != nil || port != 3600 {
- t.Error(port)
- t.Fatal(err)
- }
- if pi, err := xmlconf.Float("PI"); err != nil || pi != 3.1415976 {
- t.Error(pi)
- t.Fatal(err)
- }
- if xmlconf.String("runmode") != "dev" {
- t.Fatal("runmode not equal to dev")
- }
- if v, err := xmlconf.Bool("autorender"); err != nil || v != false {
- t.Error(v)
- t.Fatal(err)
- }
- if v, err := xmlconf.Bool("copyrequestbody"); err != nil || v != true {
- t.Error(v)
- t.Fatal(err)
+
+ for k, v := range keyValue {
+
+ var (
+ value interface{}
+ err error
+ )
+
+ switch v.(type) {
+ case int:
+ value, err = xmlconf.Int(k)
+ case int64:
+ value, err = xmlconf.Int64(k)
+ case float64:
+ value, err = xmlconf.Float(k)
+ case bool:
+ value, err = xmlconf.Bool(k)
+ case []string:
+ value = xmlconf.Strings(k)
+ case string:
+ value = xmlconf.String(k)
+ default:
+ value, err = xmlconf.DIY(k)
+ }
+ if err != nil {
+ t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+ } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+ t.Errorf("get key %q value, want %v got %v .", k, v, value)
+ }
+
}
+
if err = xmlconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
if xmlconf.String("name") != "astaxie" {
t.Fatal("get name error")
}
- if xmlconf.String("path") != os.Getenv("GOROOT") {
- t.Fatal("get path error")
- }
-
- if dbinfo, err := xmlconf.GetSection("dbinfo"); err != nil {
- t.Fatal(err)
- } else if dbinfo["pwd"] != os.Getenv("GOROOT") {
- t.Fatal("get pwd error")
- } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false {
- t.Fatal("get goroot path error")
- }
- if xmlconf.Strings("emptystrings") != nil {
- t.Fatal("get emtpy strings error")
- }
}
diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go
index e1dd7012..b94adbc1 100644
--- a/config/yaml/yaml.go
+++ b/config/yaml/yaml.go
@@ -19,14 +19,14 @@
// go install github.com/beego/goyaml2
//
// Usage:
-// import(
+// import(
// _ "github.com/astaxie/beego/config/yaml"
-// "github.com/astaxie/beego/config"
-// )
+// "github.com/astaxie/beego/config"
+// )
//
// cnf, err := config.NewConfig("yaml", "config.yaml")
//
-// more docs http://beego.me/docs/module/config.md
+//More docs http://beego.me/docs/module/config.md
package yaml
import (
@@ -110,6 +110,7 @@ func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
log.Println("Not a Map? >> ", string(buf), data)
cnf = nil
}
+ cnf = config.ChooseRealValueForMap(cnf)
return
}
@@ -248,7 +249,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri
func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
if v, ok := c.data[section]; ok {
- return config.ConvertToStringMap(v.(map[string]interface{})), nil
+ return v.(map[string]string), nil
}
return nil, errors.New("not exist setction")
}
@@ -285,11 +286,7 @@ func (c *ConfigContainer) getData(key string) (interface{}, error) {
}
if v, ok := c.data[key]; ok {
- if env, ok := config.Getenv(v); ok {
- return env, nil
- } else {
- return v, nil
- }
+ return v, nil
}
return nil, fmt.Errorf("not exist key %q", key)
}
diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go
index 4eb36619..30c79d0b 100644
--- a/config/yaml/yaml_test.go
+++ b/config/yaml/yaml_test.go
@@ -15,8 +15,8 @@
package yaml
import (
+ "fmt"
"os"
- "strings"
"testing"
"github.com/astaxie/beego/config"
@@ -33,21 +33,38 @@ func TestYaml(t *testing.T) {
"runmode": dev
"autorender": false
"copyrequestbody": true
-"path": $ENV_GOROOT
"PATH": GOROOT
-"dbinfo":
- "db": beego
- "pwd": $ENV_GOROOT
- "url": localhost
- "detail":
- "d1": value1
- "d2": $ENV_GOROOT
- "d3": ""
- "group":
- "id": 001
- "name": gp2
+"path1": $$GOROOT
+"path2": $$GOROOT||/home/go
+"path3": $$GOROOT$$GOPATH2||/home/go
+"token1": $$TOKEN
+"token2": $$TOKEN||
+"token3": $$TOKEN||astaxie
+"token4": token$$TOKEN
+"token5": $$TOKEN$$TOKEN||TOKEN
"empty": ""
`
+
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "PI": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "PATH": "GOROOT",
+ "path1": os.Getenv("GOROOT"),
+ "path2": os.Getenv("GOROOT"),
+ "path3": "/home/go",
+ "token1": "",
+ "token2": "",
+ "token3": "astaxie",
+ "token4": "token$$TOKEN",
+ "token5": "TOKEN",
+ "error": "",
+ "emptystrings": []string{},
+ }
)
f, err := os.Create("testyaml.conf")
if err != nil {
@@ -68,29 +85,38 @@ func TestYaml(t *testing.T) {
if yamlconf.String("appname") != "beeapi" {
t.Fatal("appname not equal to beeapi")
}
- if port, err := yamlconf.Int("httpport"); err != nil || port != 8080 {
- t.Error(port)
- t.Fatal(err)
- }
- if port, err := yamlconf.Int64("mysqlport"); err != nil || port != 3600 {
- t.Error(port)
- t.Fatal(err)
- }
- if pi, err := yamlconf.Float("PI"); err != nil || pi != 3.1415976 {
- t.Error(pi)
- t.Fatal(err)
- }
- if yamlconf.String("runmode") != "dev" {
- t.Fatal("runmode not equal to dev")
- }
- if v, err := yamlconf.Bool("autorender"); err != nil || v != false {
- t.Error(v)
- t.Fatal(err)
- }
- if v, err := yamlconf.Bool("copyrequestbody"); err != nil || v != true {
- t.Error(v)
- t.Fatal(err)
+
+ for k, v := range keyValue {
+
+ var (
+ value interface{}
+ err error
+ )
+
+ switch v.(type) {
+ case int:
+ value, err = yamlconf.Int(k)
+ case int64:
+ value, err = yamlconf.Int64(k)
+ case float64:
+ value, err = yamlconf.Float(k)
+ case bool:
+ value, err = yamlconf.Bool(k)
+ case []string:
+ value = yamlconf.Strings(k)
+ case string:
+ value = yamlconf.String(k)
+ default:
+ value, err = yamlconf.DIY(k)
+ }
+ if err != nil {
+ t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+ } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+ t.Errorf("get key %q value, want %v got %v .", k, v, value)
+ }
+
}
+
if err = yamlconf.Set("name", "astaxie"); err != nil {
t.Fatal(err)
}
@@ -98,15 +124,4 @@ func TestYaml(t *testing.T) {
t.Fatal("get name error")
}
- if dbinfo, err := yamlconf.GetSection("dbinfo"); err != nil {
- t.Fatal(err)
- } else if dbinfo["pwd"] != os.Getenv("GOROOT") {
- t.Fatal("get pwd error")
- } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false {
- t.Fatal("get GOROOT path error")
- }
-
- if yamlconf.Strings("emptystrings") != nil {
- t.Fatal("get emtpy strings error")
- }
}