diff --git a/config/config.go b/config/config.go
index c0afec05..de2fb7f0 100644
--- a/config/config.go
+++ b/config/config.go
@@ -44,6 +44,8 @@ package config
import (
"fmt"
+ "os"
+ "strings"
)
// Configer defines how to get and set value from configuration raw data.
@@ -107,6 +109,24 @@ 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 len(key) > len(envKeySign) && strings.HasPrefix(key, envKeySign) {
+ key = strings.TrimLeft(key, envKeySign)
+ return os.Getenv(key), true
+ }
+ }
+ return "", false
+}
+
// 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,
diff --git a/config/fake.go b/config/fake.go
index 6daaca2c..baadd3c6 100644
--- a/config/fake.go
+++ b/config/fake.go
@@ -25,7 +25,15 @@ type fakeConfigContainer struct {
}
func (c *fakeConfigContainer) getData(key string) string {
- return c.data[strings.ToLower(key)]
+ if len(key) == 0 {
+ return ""
+ }
+
+ v := c.data[strings.ToLower(key)]
+ if env, ok := Getenv(v); ok {
+ return env
+ }
+ return v
}
func (c *fakeConfigContainer) Set(key, val string) error {
@@ -38,7 +46,7 @@ func (c *fakeConfigContainer) String(key string) string {
}
func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string {
- v := c.getData(key)
+ v := c.String(key)
if v == "" {
return defaultval
}
@@ -46,7 +54,7 @@ func (c *fakeConfigContainer) DefaultString(key string, defaultval string) strin
}
func (c *fakeConfigContainer) Strings(key string) []string {
- return strings.Split(c.getData(key), ";")
+ return strings.Split(c.String(key), ";")
}
func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string {
diff --git a/config/ini.go b/config/ini.go
index da6f2b3a..bbf71bed 100644
--- a/config/ini.go
+++ b/config/ini.go
@@ -286,6 +286,11 @@ 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")
@@ -448,6 +453,9 @@ 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 11063d99..1330e2ee 100644
--- a/config/ini_test.go
+++ b/config/ini_test.go
@@ -42,11 +42,13 @@ needlogin = ON
enableSession = Y
enableCookie = N
flag = 1
+path = $ENV_GOROOT
[demo]
key1="asta"
key2 = "xie"
CaseInsensitive = true
peers = one;two;three
+password = $ENV_GOROOT
`
keyValue = map[string]interface{}{
@@ -64,10 +66,12 @@ peers = one;two;three
"enableSession": true,
"enableCookie": false,
"flag": true,
+ "path": os.Getenv("GOROOT"),
"demo::key1": "asta",
"demo::key2": "xie",
"demo::CaseInsensitive": true,
"demo::peers": []string{"one", "two", "three"},
+ "demo::password": os.Getenv("GOROOT"),
"null": "",
"demo2::key1": "",
"error": "",
@@ -140,6 +144,7 @@ httpport = 8080
# db type name
# suport mysql,sqlserver
name = mysql
+path = $ENV_GOROOT
`
saveResult = `
@@ -156,6 +161,7 @@ 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 0bc1d456..82400270 100644
--- a/config/json.go
+++ b/config/json.go
@@ -250,11 +250,18 @@ 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 df663461..4ac2cdfc 100644
--- a/config/json_test.go
+++ b/config/json_test.go
@@ -86,16 +86,18 @@ func TestJson(t *testing.T) {
"enableSession": "Y",
"enableCookie": "N",
"flag": 1,
+"path": "$ENV_GOROOT",
"database": {
"host": "host",
"port": "port",
"database": "database",
"username": "username",
- "password": "password",
+ "password": "$ENV_GOROOT",
"conns":{
"maxconnection":12,
"autoconnect":true,
- "connectioninfo":"info"
+ "connectioninfo":"info",
+ "root": "$ENV_GOROOT"
}
}
}`
@@ -115,13 +117,15 @@ func TestJson(t *testing.T) {
"enableSession": true,
"enableCookie": false,
"flag": true,
+ "path": os.Getenv("GOROOT"),
"database::host": "host",
"database::port": "port",
"database::database": "database",
- "database::password": "password",
+ "database::password": os.Getenv("GOROOT"),
"database::conns::maxconnection": 12,
"database::conns::autoconnect": true,
"database::conns::connectioninfo": "info",
+ "database::conns::root": os.Getenv("GOROOT"),
"unknown": "",
}
)
diff --git a/config/xml/xml.go b/config/xml/xml.go
index ffb32862..d48cfd8e 100644
--- a/config/xml/xml.go
+++ b/config/xml/xml.go
@@ -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, ok := c.data[key]; ok {
+ if v := c.getData(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.data[key].(string))
+ return strconv.Atoi(c.getData(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.data[key].(string), 10, 64)
+ return strconv.ParseInt(c.getData(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.data[key].(string), 64)
+ return strconv.ParseFloat(c.getData(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.data[key].(string); ok {
+ if v, ok := c.getData(key).(string); ok {
return v
}
return ""
@@ -190,7 +190,28 @@ 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 v.(map[string]string), nil
+
+ var interfaceToStr func(map[string]interface{}) map[string]string
+
+ interfaceToStr = func(values map[string]interface{}) map[string]string {
+ strValues := make(map[string]string, len(values))
+ for k, vv := range values {
+ if vv == nil {
+ strValues[k] = ""
+ } else if env, ok := config.Getenv(vv); ok {
+ strValues[k] = env
+ } else if str, ok := vv.(string); ok {
+ strValues[k] = str
+ } else if m, ok := vv.(map[string]interface{}); ok {
+ strValues[k] = fmt.Sprintf("%v", interfaceToStr(m))
+ } else {
+ // TODO: no better.
+ strValues[k] = fmt.Sprintf("%v", vv)
+ }
+ }
+ return strValues
+ }
+ return interfaceToStr(v.(map[string]interface{})), nil
}
return nil, errors.New("not exist setction")
}
@@ -227,6 +248,18 @@ 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 fa3c17f1..29db80e9 100644
--- a/config/xml/xml_test.go
+++ b/config/xml/xml_test.go
@@ -16,13 +16,16 @@ package xml
import (
"os"
+ "strings"
"testing"
"github.com/astaxie/beego/config"
)
-//xml parse should incluce in tags
-var xmlcontext = `
+func TestXML(t *testing.T) {
+
+ //xml parse should incluce in tags
+ var xmlcontext = `
beeapi
8080
@@ -31,10 +34,24 @@ var xmlcontext = `
dev
false
true
+$ENV_GOROOT
+
+ beego
+ $ENV_GOROOT
+ localhost
+
+ value1
+ $ENV_GOROOT
+
+
+
+ 001
+ gp2
+
+
`
-func TestXML(t *testing.T) {
f, err := os.Create("testxml.conf")
if err != nil {
t.Fatal(err)
@@ -82,4 +99,16 @@ func TestXML(t *testing.T) {
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")
+ }
}
diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go
index 9a96ac92..a2ec299c 100644
--- a/config/yaml/yaml.go
+++ b/config/yaml/yaml.go
@@ -121,10 +121,12 @@ type ConfigContainer struct {
// Bool returns the boolean value for a given key.
func (c *ConfigContainer) Bool(key string) (bool, error) {
- if v, ok := c.data[key]; ok {
+
+ if v, err := c.getData(key); err != nil {
+ return false, err
+ } else {
return config.ParseBool(v)
}
- return false, fmt.Errorf("not exist key: %q", key)
}
// DefaultBool return the bool value if has no error
@@ -139,8 +141,12 @@ 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) {
- if v, ok := c.data[key].(int64); ok {
- return int(v), nil
+ if v, err := c.getData(key); err != nil {
+ return 0, err
+ } else if vv, ok := v.(int); ok {
+ return vv, nil
+ } else if vv, ok := v.(int64); ok {
+ return int(vv), nil
}
return 0, errors.New("not int value")
}
@@ -157,8 +163,10 @@ 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) {
- if v, ok := c.data[key].(int64); ok {
- return v, nil
+ if v, err := c.getData(key); err != nil {
+ return 0, err
+ } else if vv, ok := v.(int64); ok {
+ return vv, nil
}
return 0, errors.New("not bool value")
}
@@ -175,8 +183,14 @@ 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) {
- if v, ok := c.data[key].(float64); ok {
- return v, nil
+ if v, err := c.getData(key); err != nil {
+ return 0.0, err
+ } else if vv, ok := v.(float64); ok {
+ return vv, nil
+ } else if vv, ok := v.(int); ok {
+ return float64(vv), nil
+ } else if vv, ok := v.(int64); ok {
+ return float64(vv), nil
}
return 0.0, errors.New("not float64 value")
}
@@ -193,8 +207,10 @@ 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.data[key].(string); ok {
- return v
+ if v, err := c.getData(key); err == nil {
+ if vv, ok := v.(string); ok {
+ return vv
+ }
}
return ""
}
@@ -228,7 +244,27 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri
func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
v, ok := c.data[section]
if ok {
- return v.(map[string]string), nil
+ var interfaceToStr func(map[string]interface{}) map[string]string
+
+ interfaceToStr = func(values map[string]interface{}) map[string]string {
+ strValues := make(map[string]string, len(values))
+ for k, vv := range values {
+ if vv == nil {
+ strValues[k] = ""
+ } else if env, ok := config.Getenv(vv); ok {
+ strValues[k] = env
+ } else if str, ok := vv.(string); ok {
+ strValues[k] = str
+ } else if m, ok := vv.(map[string]interface{}); ok {
+ strValues[k] = fmt.Sprintf("%v", interfaceToStr(m))
+ } else {
+ // TODO: no better.
+ strValues[k] = fmt.Sprintf("%v", vv)
+ }
+ }
+ return strValues
+ }
+ return interfaceToStr(v.(map[string]interface{})), nil
}
return nil, errors.New("not exist setction")
}
@@ -255,10 +291,23 @@ func (c *ConfigContainer) Set(key, val string) error {
// DIY returns the raw value by a given key.
func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
- if v, ok := c.data[key]; ok {
- return v, nil
+ return c.getData(key)
+}
+
+func (c *ConfigContainer) getData(key string) (interface{}, error) {
+
+ if len(key) == 0 {
+ return nil, errors.New("key is emtpy")
}
- return nil, errors.New("not exist key")
+
+ if v, ok := c.data[key]; ok {
+ if env, ok := config.Getenv(v); ok {
+ return env, nil
+ } else {
+ return v, nil
+ }
+ }
+ return nil, fmt.Errorf("not exist key %q", key)
}
func init() {
diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go
index 19ecdca1..61d0e2a5 100644
--- a/config/yaml/yaml_test.go
+++ b/config/yaml/yaml_test.go
@@ -16,12 +16,16 @@ package yaml
import (
"os"
+ "strings"
"testing"
"github.com/astaxie/beego/config"
)
-var yamlcontext = `
+func TestYaml(t *testing.T) {
+
+ var (
+ yamlcontext = `
"appname": beeapi
"httpport": 8080
"mysqlport": 3600
@@ -29,9 +33,22 @@ var yamlcontext = `
"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
+"empty": ""
`
-
-func TestYaml(t *testing.T) {
+ )
f, err := os.Create("testyaml.conf")
if err != nil {
t.Fatal(err)
@@ -47,6 +64,7 @@ func TestYaml(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+
if yamlconf.String("appname") != "beeapi" {
t.Fatal("appname not equal to beeapi")
}
@@ -79,4 +97,12 @@ func TestYaml(t *testing.T) {
if yamlconf.String("name") != "astaxie" {
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")
+ }
}