diff --git a/pkg/adapter/config/adapter.go b/pkg/adapter/config/adapter.go
new file mode 100644
index 00000000..f74b3ff9
--- /dev/null
+++ b/pkg/adapter/config/adapter.go
@@ -0,0 +1,193 @@
+// Copyright 2020
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+
+ "github.com/astaxie/beego/pkg/infrastructure/config"
+)
+
+type newToOldConfigerAdapter struct {
+ delegate config.Configer
+}
+
+func (c *newToOldConfigerAdapter) Set(key, val string) error {
+ return c.delegate.Set(context.Background(), key, val)
+}
+
+func (c *newToOldConfigerAdapter) String(key string) string {
+ res, _ := c.delegate.String(context.Background(), key)
+ return res
+}
+
+func (c *newToOldConfigerAdapter) Strings(key string) []string {
+ res, _ := c.delegate.Strings(context.Background(), key)
+ return res
+}
+
+func (c *newToOldConfigerAdapter) Int(key string) (int, error) {
+ return c.delegate.Int(context.Background(), key)
+}
+
+func (c *newToOldConfigerAdapter) Int64(key string) (int64, error) {
+ return c.delegate.Int64(context.Background(), key)
+}
+
+func (c *newToOldConfigerAdapter) Bool(key string) (bool, error) {
+ return c.delegate.Bool(context.Background(), key)
+}
+
+func (c *newToOldConfigerAdapter) Float(key string) (float64, error) {
+ return c.delegate.Float(context.Background(), key)
+}
+
+func (c *newToOldConfigerAdapter) DefaultString(key string, defaultVal string) string {
+ return c.delegate.DefaultString(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DefaultStrings(key string, defaultVal []string) []string {
+ return c.delegate.DefaultStrings(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DefaultInt(key string, defaultVal int) int {
+ return c.delegate.DefaultInt(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DefaultInt64(key string, defaultVal int64) int64 {
+ return c.delegate.DefaultInt64(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DefaultBool(key string, defaultVal bool) bool {
+ return c.delegate.DefaultBool(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DefaultFloat(key string, defaultVal float64) float64 {
+ return c.delegate.DefaultFloat(context.Background(), key, defaultVal)
+}
+
+func (c *newToOldConfigerAdapter) DIY(key string) (interface{}, error) {
+ return c.delegate.DIY(context.Background(), key)
+}
+
+func (c *newToOldConfigerAdapter) GetSection(section string) (map[string]string, error) {
+ return c.delegate.GetSection(context.Background(), section)
+}
+
+func (c *newToOldConfigerAdapter) SaveConfigFile(filename string) error {
+ return c.delegate.SaveConfigFile(context.Background(), filename)
+}
+
+type oldToNewConfigerAdapter struct {
+ delegate Configer
+}
+
+func (o *oldToNewConfigerAdapter) Set(ctx context.Context, key, val string) error {
+ return o.delegate.Set(key, val)
+}
+
+func (o *oldToNewConfigerAdapter) String(ctx context.Context, key string) (string, error) {
+ return o.delegate.String(key), nil
+}
+
+func (o *oldToNewConfigerAdapter) Strings(ctx context.Context, key string) ([]string, error) {
+ return o.delegate.Strings(key), nil
+}
+
+func (o *oldToNewConfigerAdapter) Int(ctx context.Context, key string) (int, error) {
+ return o.delegate.Int(key)
+}
+
+func (o *oldToNewConfigerAdapter) Int64(ctx context.Context, key string) (int64, error) {
+ return o.delegate.Int64(key)
+}
+
+func (o *oldToNewConfigerAdapter) Bool(ctx context.Context, key string) (bool, error) {
+ return o.delegate.Bool(key)
+}
+
+func (o *oldToNewConfigerAdapter) Float(ctx context.Context, key string) (float64, error) {
+ return o.delegate.Float(key)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultString(ctx context.Context, key string, defaultVal string) string {
+ return o.delegate.DefaultString(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultStrings(ctx context.Context, key string, defaultVal []string) []string {
+ return o.delegate.DefaultStrings(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultInt(ctx context.Context, key string, defaultVal int) int {
+ return o.delegate.DefaultInt(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultInt64(ctx context.Context, key string, defaultVal int64) int64 {
+ return o.delegate.DefaultInt64(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultBool(ctx context.Context, key string, defaultVal bool) bool {
+ return o.delegate.DefaultBool(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DefaultFloat(ctx context.Context, key string, defaultVal float64) float64 {
+ return o.delegate.DefaultFloat(key, defaultVal)
+}
+
+func (o *oldToNewConfigerAdapter) DIY(ctx context.Context, key string) (interface{}, error) {
+ return o.delegate.DIY(key)
+}
+
+func (o *oldToNewConfigerAdapter) GetSection(ctx context.Context, section string) (map[string]string, error) {
+ return o.delegate.GetSection(section)
+}
+
+func (o *oldToNewConfigerAdapter) Unmarshaler(ctx context.Context, prefix string, obj interface{}, opt ...config.DecodeOption) error {
+ return errors.New("unsupported operation, please use actual config.Configer")
+}
+
+func (o *oldToNewConfigerAdapter) Sub(ctx context.Context, key string) (config.Configer, error) {
+ return nil, errors.New("unsupported operation, please use actual config.Configer")
+}
+
+func (o *oldToNewConfigerAdapter) OnChange(ctx context.Context, key string, fn func(value string)) {
+ // do nothing
+}
+
+func (o *oldToNewConfigerAdapter) SaveConfigFile(ctx context.Context, filename string) error {
+ return o.delegate.SaveConfigFile(filename)
+}
+
+type oldToNewConfigAdapter struct {
+ delegate Config
+}
+
+func (o *oldToNewConfigAdapter) Parse(key string) (config.Configer, error) {
+ old, err := o.delegate.Parse(key)
+ if err != nil {
+ return nil, err
+ }
+ return &oldToNewConfigerAdapter{delegate: old}, nil
+}
+
+func (o *oldToNewConfigAdapter) ParseData(data []byte) (config.Configer, error) {
+ old, err := o.delegate.ParseData(data)
+ if err != nil {
+ return nil, err
+ }
+ return &oldToNewConfigerAdapter{delegate: old}, nil
+}
diff --git a/pkg/adapter/config/config.go b/pkg/adapter/config/config.go
new file mode 100644
index 00000000..c870a15a
--- /dev/null
+++ b/pkg/adapter/config/config.go
@@ -0,0 +1,151 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+// Package config is used to parse config.
+// Usage:
+// import "github.com/astaxie/beego/config"
+// Examples.
+//
+// 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)
+// 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
+// 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
+package config
+
+import (
+ "github.com/astaxie/beego/pkg/infrastructure/config"
+)
+
+// Configer defines how to get and set value from configuration raw data.
+type Configer interface {
+ 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.
+ Strings(key string) []string // get string slice
+ Int(key string) (int, error)
+ Int64(key string) (int64, error)
+ Bool(key string) (bool, error)
+ Float(key string) (float64, error)
+ 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
+}
+
+// Config is the adapter interface for parsing config file to get raw data to Configer.
+type Config interface {
+ Parse(key string) (Configer, error)
+ ParseData(data []byte) (Configer, error)
+}
+
+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) {
+ config.Register(name, &oldToNewConfigAdapter{delegate: adapter})
+}
+
+// NewConfig adapterName is ini/json/xml/yaml.
+// filename is the config file path.
+func NewConfig(adapterName, filename string) (Configer, error) {
+ cfg, err := config.NewConfig(adapterName, filename)
+ if err != nil {
+ return nil, err
+ }
+
+ // it was registered by using Register method
+ res, ok := cfg.(*oldToNewConfigerAdapter)
+ if ok {
+ return res.delegate, nil
+ }
+
+ return &newToOldConfigerAdapter{
+ delegate: cfg,
+ }, nil
+}
+
+// NewConfigData adapterName is ini/json/xml/yaml.
+// data is the config data.
+func NewConfigData(adapterName string, data []byte) (Configer, error) {
+ cfg, err := config.NewConfigData(adapterName, data)
+ if err != nil {
+ return nil, err
+ }
+
+ // it was registered by using Register method
+ res, ok := cfg.(*oldToNewConfigerAdapter)
+ if ok {
+ return res.delegate, nil
+ }
+
+ return &newToOldConfigerAdapter{
+ delegate: cfg,
+ }, nil
+}
+
+// ExpandValueEnvForMap convert all string value with environment variable.
+func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} {
+ return config.ExpandValueEnvForMap(m)
+}
+
+// ExpandValueEnv returns value of convert with environment variable.
+//
+// Return environment variable if value start with "${" and end with "}".
+// Return default value if environment variable is empty or not exist.
+//
+// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue".
+// Examples:
+// 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) string {
+ return config.ExpandValueEnv(value)
+}
+
+// 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) {
+ return config.ParseBool(val)
+}
+
+// ToString converts values of any type to string.
+func ToString(x interface{}) string {
+ return config.ToString(x)
+}
diff --git a/pkg/adapter/config/config_test.go b/pkg/adapter/config/config_test.go
new file mode 100644
index 00000000..15d6ffa6
--- /dev/null
+++ b/pkg/adapter/config/config_test.go
@@ -0,0 +1,55 @@
+// Copyright 2016 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ "os"
+ "testing"
+)
+
+func TestExpandValueEnv(t *testing.T) {
+
+ testCases := []struct {
+ item string
+ want string
+ }{
+ {"", ""},
+ {"$", "$"},
+ {"{", "{"},
+ {"{}", "{}"},
+ {"${}", ""},
+ {"${|}", ""},
+ {"${}", ""},
+ {"${{}}", ""},
+ {"${{||}}", "}"},
+ {"${pwd||}", ""},
+ {"${pwd||}", ""},
+ {"${pwd||}", ""},
+ {"${pwd||}}", "}"},
+ {"${pwd||{{||}}}", "{{||}}"},
+ {"${GOPATH}", os.Getenv("GOPATH")},
+ {"${GOPATH||}", os.Getenv("GOPATH")},
+ {"${GOPATH||root}", os.Getenv("GOPATH")},
+ {"${GOPATH_NOT||root}", "root"},
+ {"${GOPATH_NOT||||root}", "||root"},
+ }
+
+ for _, c := range testCases {
+ if got := ExpandValueEnv(c.item); got != c.want {
+ t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got)
+ }
+ }
+
+}
diff --git a/pkg/adapter/config/env/env.go b/pkg/adapter/config/env/env.go
new file mode 100644
index 00000000..77d7b53c
--- /dev/null
+++ b/pkg/adapter/config/env/env.go
@@ -0,0 +1,50 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+// Package env is used to parse environment.
+package env
+
+import (
+ "github.com/astaxie/beego/pkg/infrastructure/config/env"
+)
+
+// Get returns a value by key.
+// If the key does not exist, the default value will be returned.
+func Get(key string, defVal string) string {
+ return env.Get(key, defVal)
+}
+
+// MustGet returns a value by key.
+// If the key does not exist, it will return an error.
+func MustGet(key string) (string, error) {
+ return env.MustGet(key)
+}
+
+// Set sets a value in the ENV copy.
+// This does not affect the child process environment.
+func Set(key string, value string) {
+ env.Set(key, value)
+}
+
+// MustSet sets a value in the ENV copy and the child process environment.
+// It returns an error in case the set operation failed.
+func MustSet(key string, value string) error {
+ return env.MustSet(key, value)
+}
+
+// GetAll returns all keys/values in the current child process environment.
+func GetAll() map[string]string {
+ return env.GetAll()
+}
diff --git a/pkg/adapter/config/env/env_test.go b/pkg/adapter/config/env/env_test.go
new file mode 100644
index 00000000..3f1d4dba
--- /dev/null
+++ b/pkg/adapter/config/env/env_test.go
@@ -0,0 +1,75 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+package env
+
+import (
+ "os"
+ "testing"
+)
+
+func TestEnvGet(t *testing.T) {
+ gopath := Get("GOPATH", "")
+ if gopath != os.Getenv("GOPATH") {
+ t.Error("expected GOPATH not empty.")
+ }
+
+ noExistVar := Get("NOEXISTVAR", "foo")
+ if noExistVar != "foo" {
+ t.Errorf("expected NOEXISTVAR to equal foo, got %s.", noExistVar)
+ }
+}
+
+func TestEnvMustGet(t *testing.T) {
+ gopath, err := MustGet("GOPATH")
+ if err != nil {
+ t.Error(err)
+ }
+
+ if gopath != os.Getenv("GOPATH") {
+ t.Errorf("expected GOPATH to be the same, got %s.", gopath)
+ }
+
+ _, err = MustGet("NOEXISTVAR")
+ if err == nil {
+ t.Error("expected error to be non-nil")
+ }
+}
+
+func TestEnvSet(t *testing.T) {
+ Set("MYVAR", "foo")
+ myVar := Get("MYVAR", "bar")
+ if myVar != "foo" {
+ t.Errorf("expected MYVAR to equal foo, got %s.", myVar)
+ }
+}
+
+func TestEnvMustSet(t *testing.T) {
+ err := MustSet("FOO", "bar")
+ if err != nil {
+ t.Error(err)
+ }
+
+ fooVar := os.Getenv("FOO")
+ if fooVar != "bar" {
+ t.Errorf("expected FOO variable to equal bar, got %s.", fooVar)
+ }
+}
+
+func TestEnvGetAll(t *testing.T) {
+ envMap := GetAll()
+ if len(envMap) == 0 {
+ t.Error("expected environment not empty.")
+ }
+}
diff --git a/pkg/adapter/config/fake.go b/pkg/adapter/config/fake.go
new file mode 100644
index 00000000..fac96b41
--- /dev/null
+++ b/pkg/adapter/config/fake.go
@@ -0,0 +1,25 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ "github.com/astaxie/beego/pkg/infrastructure/config"
+)
+
+// NewFakeConfig return a fake Configer
+func NewFakeConfig() Configer {
+ new := config.NewFakeConfig()
+ return &newToOldConfigerAdapter{delegate: new}
+}
diff --git a/pkg/adapter/config/ini_test.go b/pkg/adapter/config/ini_test.go
new file mode 100644
index 00000000..ffcdb294
--- /dev/null
+++ b/pkg/adapter/config/ini_test.go
@@ -0,0 +1,190 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestIni(t *testing.T) {
+
+ var (
+ inicontext = `
+;comment one
+#comment two
+appname = beeapi
+httpport = 8080
+mysqlport = 3600
+PI = 3.1415976
+runmode = "dev"
+autorender = false
+copyrequestbody = true
+session= on
+cookieon= off
+newreg = OFF
+needlogin = ON
+enableSession = Y
+enableCookie = N
+flag = 1
+path1 = ${GOPATH}
+path2 = ${GOPATH||/home/go}
+[demo]
+key1="asta"
+key2 = "xie"
+CaseInsensitive = true
+peers = one;two;three
+password = ${GOPATH}
+`
+
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "pi": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "session": true,
+ "cookieon": false,
+ "newreg": false,
+ "needlogin": true,
+ "enableSession": true,
+ "enableCookie": false,
+ "flag": true,
+ "path1": os.Getenv("GOPATH"),
+ "path2": os.Getenv("GOPATH"),
+ "demo::key1": "asta",
+ "demo::key2": "xie",
+ "demo::CaseInsensitive": true,
+ "demo::peers": []string{"one", "two", "three"},
+ "demo::password": os.Getenv("GOPATH"),
+ "null": "",
+ "demo2::key1": "",
+ "error": "",
+ "emptystrings": []string{},
+ }
+ )
+
+ f, err := os.Create("testini.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(inicontext)
+ if err != nil {
+ f.Close()
+ t.Fatal(err)
+ }
+ f.Close()
+ defer os.Remove("testini.conf")
+ iniconf, err := NewConfig("ini", "testini.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for k, v := range keyValue {
+ var err error
+ var value interface{}
+ switch v.(type) {
+ case int:
+ value, err = iniconf.Int(k)
+ case int64:
+ value, err = iniconf.Int64(k)
+ case float64:
+ value, err = iniconf.Float(k)
+ case bool:
+ value, err = iniconf.Bool(k)
+ case []string:
+ value = iniconf.Strings(k)
+ case string:
+ value = iniconf.String(k)
+ default:
+ value, err = iniconf.DIY(k)
+ }
+ if err != nil {
+ t.Fatalf("get key %q value fail,err %s", k, err)
+ } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+ t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+ }
+
+ }
+ if err = iniconf.Set("name", "astaxie"); err != nil {
+ t.Fatal(err)
+ }
+ if iniconf.String("name") != "astaxie" {
+ t.Fatal("get name error")
+ }
+
+}
+
+func TestIniSave(t *testing.T) {
+
+ const (
+ inicontext = `
+app = app
+;comment one
+#comment two
+# comment three
+appname = beeapi
+httpport = 8080
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name = mysql
+`
+
+ saveResult = `
+app=app
+#comment one
+#comment two
+# comment three
+appname=beeapi
+httpport=8080
+
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name=mysql
+`
+ )
+ cfg, err := NewConfigData("ini", []byte(inicontext))
+ if err != nil {
+ t.Fatal(err)
+ }
+ name := "newIniConfig.ini"
+ if err := cfg.SaveConfigFile(name); err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(name)
+
+ if data, err := ioutil.ReadFile(name); err != nil {
+ t.Fatal(err)
+ } else {
+ cfgData := string(data)
+ datas := strings.Split(saveResult, "\n")
+ for _, line := range datas {
+ if !strings.Contains(cfgData, line+"\n") {
+ t.Fatalf("different after save ini config file. need contains %q", line)
+ }
+ }
+
+ }
+}
diff --git a/pkg/adapter/config/json.go b/pkg/adapter/config/json.go
new file mode 100644
index 00000000..d0fe4d09
--- /dev/null
+++ b/pkg/adapter/config/json.go
@@ -0,0 +1,19 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ _ "github.com/astaxie/beego/pkg/infrastructure/config/json"
+)
diff --git a/pkg/adapter/config/json_test.go b/pkg/adapter/config/json_test.go
new file mode 100644
index 00000000..16f42409
--- /dev/null
+++ b/pkg/adapter/config/json_test.go
@@ -0,0 +1,222 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package config
+
+import (
+ "fmt"
+ "os"
+ "testing"
+)
+
+func TestJsonStartsWithArray(t *testing.T) {
+
+ const jsoncontextwitharray = `[
+ {
+ "url": "user",
+ "serviceAPI": "http://www.test.com/user"
+ },
+ {
+ "url": "employee",
+ "serviceAPI": "http://www.test.com/employee"
+ }
+]`
+ f, err := os.Create("testjsonWithArray.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(jsoncontextwitharray)
+ if err != nil {
+ f.Close()
+ t.Fatal(err)
+ }
+ f.Close()
+ defer os.Remove("testjsonWithArray.conf")
+ jsonconf, err := NewConfig("json", "testjsonWithArray.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rootArray, err := jsonconf.DIY("rootArray")
+ if err != nil {
+ t.Error("array does not exist as element")
+ }
+ rootArrayCasted := rootArray.([]interface{})
+ if rootArrayCasted == nil {
+ t.Error("array from root is nil")
+ } else {
+ elem := rootArrayCasted[0].(map[string]interface{})
+ if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" {
+ t.Error("array[0] values are not valid")
+ }
+
+ elem2 := rootArrayCasted[1].(map[string]interface{})
+ if elem2["url"] != "employee" || elem2["serviceAPI"] != "http://www.test.com/employee" {
+ t.Error("array[1] values are not valid")
+ }
+ }
+}
+
+func TestJson(t *testing.T) {
+
+ var (
+ jsoncontext = `{
+"appname": "beeapi",
+"testnames": "foo;bar",
+"httpport": 8080,
+"mysqlport": 3600,
+"PI": 3.1415976,
+"runmode": "dev",
+"autorender": false,
+"copyrequestbody": true,
+"session": "on",
+"cookieon": "off",
+"newreg": "OFF",
+"needlogin": "ON",
+"enableSession": "Y",
+"enableCookie": "N",
+"flag": 1,
+"path1": "${GOPATH}",
+"path2": "${GOPATH||/home/go}",
+"database": {
+ "host": "host",
+ "port": "port",
+ "database": "database",
+ "username": "username",
+ "password": "${GOPATH}",
+ "conns":{
+ "maxconnection":12,
+ "autoconnect":true,
+ "connectioninfo":"info",
+ "root": "${GOPATH}"
+ }
+ }
+}`
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "testnames": []string{"foo", "bar"},
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "PI": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "session": true,
+ "cookieon": false,
+ "newreg": false,
+ "needlogin": true,
+ "enableSession": true,
+ "enableCookie": false,
+ "flag": true,
+ "path1": os.Getenv("GOPATH"),
+ "path2": os.Getenv("GOPATH"),
+ "database::host": "host",
+ "database::port": "port",
+ "database::database": "database",
+ "database::password": os.Getenv("GOPATH"),
+ "database::conns::maxconnection": 12,
+ "database::conns::autoconnect": true,
+ "database::conns::connectioninfo": "info",
+ "database::conns::root": os.Getenv("GOPATH"),
+ "unknown": "",
+ }
+ )
+
+ f, err := os.Create("testjson.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(jsoncontext)
+ if err != nil {
+ f.Close()
+ t.Fatal(err)
+ }
+ f.Close()
+ defer os.Remove("testjson.conf")
+ jsonconf, err := NewConfig("json", "testjson.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for k, v := range keyValue {
+ var err error
+ var value interface{}
+ switch v.(type) {
+ case int:
+ value, err = jsonconf.Int(k)
+ case int64:
+ value, err = jsonconf.Int64(k)
+ case float64:
+ value, err = jsonconf.Float(k)
+ case bool:
+ value, err = jsonconf.Bool(k)
+ case []string:
+ value = jsonconf.Strings(k)
+ case string:
+ value = jsonconf.String(k)
+ default:
+ value, err = jsonconf.DIY(k)
+ }
+ if err != nil {
+ t.Fatalf("get key %q value fatal,%v err %s", k, v, err)
+ } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+ t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+ }
+
+ }
+ if err = jsonconf.Set("name", "astaxie"); err != nil {
+ t.Fatal(err)
+ }
+ if jsonconf.String("name") != "astaxie" {
+ t.Fatal("get name error")
+ }
+
+ if db, err := jsonconf.DIY("database"); err != nil {
+ t.Fatal(err)
+ } else if m, ok := db.(map[string]interface{}); !ok {
+ t.Log(db)
+ t.Fatal("db not map[string]interface{}")
+ } else {
+ if m["host"].(string) != "host" {
+ t.Fatal("get host err")
+ }
+ }
+
+ if _, err := jsonconf.Int("unknown"); err == nil {
+ t.Error("unknown keys should return an error when expecting an Int")
+ }
+
+ if _, err := jsonconf.Int64("unknown"); err == nil {
+ t.Error("unknown keys should return an error when expecting an Int64")
+ }
+
+ if _, err := jsonconf.Float("unknown"); err == nil {
+ t.Error("unknown keys should return an error when expecting a Float")
+ }
+
+ if _, err := jsonconf.DIY("unknown"); err == nil {
+ t.Error("unknown keys should return an error when expecting an interface{}")
+ }
+
+ if val := jsonconf.String("unknown"); val != "" {
+ t.Error("unknown keys should return an empty string when expecting a String")
+ }
+
+ if _, err := jsonconf.Bool("unknown"); err == nil {
+ t.Error("unknown keys should return an error when expecting a Bool")
+ }
+
+ if !jsonconf.DefaultBool("unknown", true) {
+ t.Error("unknown keys with default value wrong")
+ }
+}
diff --git a/pkg/adapter/config/xml/xml.go b/pkg/adapter/config/xml/xml.go
new file mode 100644
index 00000000..f96cdcd6
--- /dev/null
+++ b/pkg/adapter/config/xml/xml.go
@@ -0,0 +1,34 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+// Package xml for config provider.
+//
+// depend on github.com/beego/x2j.
+//
+// go install github.com/beego/x2j.
+//
+// Usage:
+// 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
+package xml
+
+import (
+ _ "github.com/astaxie/beego/pkg/infrastructure/config/xml"
+)
diff --git a/pkg/adapter/config/xml/xml_test.go b/pkg/adapter/config/xml/xml_test.go
new file mode 100644
index 00000000..122c5027
--- /dev/null
+++ b/pkg/adapter/config/xml/xml_test.go
@@ -0,0 +1,125 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package xml
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/astaxie/beego/pkg/adapter/config"
+)
+
+func TestXML(t *testing.T) {
+
+ var (
+ //xml parse should incluce in tags
+ xmlcontext = `
+
+beeapi
+8080
+3600
+3.1415976
+dev
+false
+true
+${GOPATH}
+${GOPATH||/home/go}
+
+1
+MySection
+
+
+`
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "PI": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "path1": os.Getenv("GOPATH"),
+ "path2": os.Getenv("GOPATH"),
+ "error": "",
+ "emptystrings": []string{},
+ }
+ )
+
+ f, err := os.Create("testxml.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(xmlcontext)
+ if err != nil {
+ f.Close()
+ t.Fatal(err)
+ }
+ f.Close()
+ defer os.Remove("testxml.conf")
+
+ xmlconf, err := config.NewConfig("xml", "testxml.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var xmlsection map[string]string
+ xmlsection, err = xmlconf.GetSection("mysection")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(xmlsection) == 0 {
+ t.Error("section should not be empty")
+ }
+
+ 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")
+ }
+}
diff --git a/pkg/adapter/config/yaml/yaml.go b/pkg/adapter/config/yaml/yaml.go
new file mode 100644
index 00000000..bc2398e9
--- /dev/null
+++ b/pkg/adapter/config/yaml/yaml.go
@@ -0,0 +1,34 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+// Package yaml for config provider
+//
+// depend on github.com/beego/goyaml2
+//
+// go install github.com/beego/goyaml2
+//
+// Usage:
+// import(
+// _ "github.com/astaxie/beego/config/yaml"
+// "github.com/astaxie/beego/config"
+// )
+//
+// cnf, err := config.NewConfig("yaml", "config.yaml")
+//
+// More docs http://beego.me/docs/module/config.md
+package yaml
+
+import (
+ _ "github.com/astaxie/beego/pkg/infrastructure/config/yaml"
+)
diff --git a/pkg/adapter/config/yaml/yaml_test.go b/pkg/adapter/config/yaml/yaml_test.go
new file mode 100644
index 00000000..e4e309a2
--- /dev/null
+++ b/pkg/adapter/config/yaml/yaml_test.go
@@ -0,0 +1,115 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+package yaml
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/astaxie/beego/pkg/adapter/config"
+)
+
+func TestYaml(t *testing.T) {
+
+ var (
+ yamlcontext = `
+"appname": beeapi
+"httpport": 8080
+"mysqlport": 3600
+"PI": 3.1415976
+"runmode": dev
+"autorender": false
+"copyrequestbody": true
+"PATH": GOPATH
+"path1": ${GOPATH}
+"path2": ${GOPATH||/home/go}
+"empty": ""
+`
+
+ keyValue = map[string]interface{}{
+ "appname": "beeapi",
+ "httpport": 8080,
+ "mysqlport": int64(3600),
+ "PI": 3.1415976,
+ "runmode": "dev",
+ "autorender": false,
+ "copyrequestbody": true,
+ "PATH": "GOPATH",
+ "path1": os.Getenv("GOPATH"),
+ "path2": os.Getenv("GOPATH"),
+ "error": "",
+ "emptystrings": []string{},
+ }
+ )
+ f, err := os.Create("testyaml.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.WriteString(yamlcontext)
+ if err != nil {
+ f.Close()
+ t.Fatal(err)
+ }
+ f.Close()
+ defer os.Remove("testyaml.conf")
+ yamlconf, err := config.NewConfig("yaml", "testyaml.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if yamlconf.String("appname") != "beeapi" {
+ t.Fatal("appname not equal to beeapi")
+ }
+
+ 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)
+ }
+ if yamlconf.String("name") != "astaxie" {
+ t.Fatal("get name error")
+ }
+
+}