diff --git a/config/config.go b/config/config.go index 61e3306193bf319053f82f911558bd0080fa3f37..744adb4b2dad47817e74f3892f04d50e668fd810 100644 --- a/config/config.go +++ b/config/config.go @@ -22,12 +22,21 @@ type ConfigContainer interface { 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 ConfigContainer. type Config interface { Parse(key string) (ConfigContainer, error) + ParseData(data []byte) (ConfigContainer, error) } var adapters = make(map[string]Config) @@ -54,3 +63,13 @@ func NewConfig(adapterName, fileaname string) (ConfigContainer, error) { } return adapter.Parse(fileaname) } + +// adapterName is ini/json/xml/yaml. +// data is the config data. +func NewConfigData(adapterName string, data []byte) (ConfigContainer, error) { + adapter, ok := adapters[adapterName] + if !ok { + return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) + } + return adapter.ParseData(data) +} diff --git a/config/fake.go b/config/fake.go index 561dcccaad3e3bd53fcd7e70b91a474936a4b483..fec4250d0c48d489a450eaddcc1fab4ebdf927dc 100644 --- a/config/fake.go +++ b/config/fake.go @@ -32,26 +32,74 @@ func (c *fakeConfigContainer) String(key string) string { return c.getData(key) } +func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.getData(key); v == "" { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Strings(key string) []string { return strings.Split(c.getData(key), ";") } +func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.getData(key)) } +func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.getData(key), 10, 64) } +func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Bool(key string) (bool, error) { return strconv.ParseBool(c.getData(key)) } +func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.getData(key), 64) } +func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) DIY(key string) (interface{}, error) { if v, ok := c.data[strings.ToLower(key)]; ok { return v, nil @@ -59,6 +107,14 @@ func (c *fakeConfigContainer) DIY(key string) (interface{}, error) { return nil, errors.New("key not find") } +func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) { + return nil, errors.New("not implement in the fakeConfigContainer") +} + +func (c *fakeConfigContainer) SaveConfigFile(filename string) error { + return errors.New("not implement in the fakeConfigContainer") +} + var _ ConfigContainer = new(fakeConfigContainer) func NewFakeConfig() ConfigContainer { diff --git a/config/ini.go b/config/ini.go index 262f688b87fac3d8b26f415b0a27757ddd7b2aa3..1a8e1a120eb25ce00220ba90cec2901b621731f6 100644 --- a/config/ini.go +++ b/config/ini.go @@ -13,11 +13,15 @@ import ( "bufio" "bytes" "errors" + "fmt" "io" + "io/ioutil" "os" + "path" "strconv" "strings" "sync" + "time" "unicode" ) @@ -30,6 +34,7 @@ var ( bDQuote = []byte{'"'} // quote signal sectionStart = []byte{'['} // section start signal sectionEnd = []byte{']'} // section end signal + lineBreak = "\n" ) // IniConfig implements Config to parse ini file. @@ -115,6 +120,16 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { return cfg, nil } +func (ini *IniConfig) ParseData(data []byte) (ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return ini.Parse(tmpName) +} + // A Config represents the ini configuration. // When set and get value, support key as section:name type. type IniConfigContainer struct { @@ -130,32 +145,154 @@ func (c *IniConfigContainer) Bool(key string) (bool, error) { return strconv.ParseBool(c.getdata(strings.ToLower(key))) } +// DefaultBool returns the boolean value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *IniConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.getdata(strings.ToLower(key))) } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *IniConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.getdata(strings.ToLower(key)), 10, 64) } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *IniConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.getdata(strings.ToLower(key)), 64) } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *IniConfigContainer) String(key string) string { key = strings.ToLower(key) return c.getdata(strings.ToLower(key)) } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *IniConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v, nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + buf := bytes.NewBuffer(nil) + for section, dt := range c.data { + // Write section comments. + if v, ok := c.sectionComment[section]; ok { + if _, err = buf.WriteString(string(bNumComment) + v + lineBreak); err != nil { + return err + } + } + + if section != DEFAULT_SECTION { + // Write section name. + if _, err = buf.WriteString(string(sectionStart) + section + string(sectionEnd) + lineBreak); err != nil { + return err + } + } + + for key, val := range dt { + if key != " " { + // Write key comments. + if v, ok := c.keyComment[key]; ok { + if _, err = buf.WriteString(string(bNumComment) + v + lineBreak); err != nil { + return err + } + } + + // Write key and value. + if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil { + return err + } + } + } + + // Put a line between sections. + if _, err = buf.WriteString(lineBreak); err != nil { + return err + } + } + + if _, err = buf.WriteTo(f); err != nil { + return err + } + return nil +} + // WriteValue writes a new value for key. // if write to one section, the key need be "section::key". // if the section is not existed, it panics. diff --git a/config/json.go b/config/json.go index 7214a6866f278a88194c90a5fb96f560a7f56141..0ddca1f08f125fa6f96f10bf3f76efee6a851a3e 100644 --- a/config/json.go +++ b/config/json.go @@ -12,10 +12,13 @@ package config import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" + "path" "strings" "sync" + "time" ) // JsonConfig is a json config parser and implements Config interface. @@ -48,6 +51,16 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { return x, nil } +func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return js.Parse(tmpName) +} + // A Config represents the json configuration. // Only when get value, support key as section:name type. type JsonConfigContainer struct { @@ -67,6 +80,16 @@ func (c *JsonConfigContainer) Bool(key string) (bool, error) { return false, errors.New("not exist key:" + key) } +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *JsonConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *JsonConfigContainer) Int(key string) (int, error) { val := c.getData(key) @@ -79,6 +102,16 @@ func (c *JsonConfigContainer) Int(key string) (int, error) { return 0, errors.New("not exist key:" + key) } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *JsonConfigContainer) Int64(key string) (int64, error) { val := c.getData(key) @@ -91,6 +124,16 @@ func (c *JsonConfigContainer) Int64(key string) (int64, error) { return 0, errors.New("not exist key:" + key) } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *JsonConfigContainer) Float(key string) (float64, error) { val := c.getData(key) @@ -103,6 +146,16 @@ func (c *JsonConfigContainer) Float(key string) (float64, error) { return 0.0, errors.New("not exist key:" + key) } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *JsonConfigContainer) String(key string) string { val := c.getData(key) @@ -114,11 +167,56 @@ func (c *JsonConfigContainer) String(key string) string { return "" } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *JsonConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *JsonConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *JsonConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + b, err := json.MarshalIndent(c.data, "", " ") + if err != nil { + return err + } + _, err = f.Write(b) + return err +} + // WriteValue writes a new value for key. func (c *JsonConfigContainer) Set(key, val string) error { c.Lock() diff --git a/config/xml/xml.go b/config/xml/xml.go index 5345f69c91b5381371bf05d61b51be324fc68f8f..6a8494cd05404e9c8e1771898b9b6c149eaca808 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -10,12 +10,16 @@ package xml import ( + "encoding/xml" "errors" + "fmt" "io/ioutil" "os" + "path" "strconv" "strings" "sync" + "time" "github.com/astaxie/beego/config" "github.com/beego/x2j" @@ -49,6 +53,16 @@ func (xc *XMLConfig) Parse(filename string) (config.ConfigContainer, error) { return x, nil } +func (x *XMLConfig) ParseData(data []byte) (config.ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return x.Parse(tmpName) +} + // A Config represents the xml configuration. type XMLConfigContainer struct { data map[string]interface{} @@ -60,21 +74,61 @@ func (c *XMLConfigContainer) Bool(key string) (bool, error) { return strconv.ParseBool(c.data[key].(string)) } +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *XMLConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *XMLConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.data[key].(string)) } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *XMLConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.data[key].(string), 10, 64) } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *XMLConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.data[key].(string), 64) } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *XMLConfigContainer) String(key string) string { if v, ok := c.data[key].(string); ok { @@ -83,11 +137,56 @@ func (c *XMLConfigContainer) String(key string) string { return "" } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *XMLConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *XMLConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *XMLConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + b, err := xml.MarshalIndent(c.data, " ", " ") + if err != nil { + return err + } + _, err = f.Write(b) + return err +} + // WriteValue writes a new value for key. func (c *XMLConfigContainer) Set(key, val string) error { c.Lock() diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index e948dae239d67735511bbc645fedae40341d34a0..89244e34cfb8f0773767da3859242854fe8210ef 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -13,11 +13,14 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "io/ioutil" "log" "os" + "path" "strings" "sync" + "time" "github.com/astaxie/beego/config" "github.com/beego/goyaml2" @@ -38,6 +41,16 @@ func (yaml *YAMLConfig) Parse(filename string) (y config.ConfigContainer, err er return } +func (yaml *YAMLConfig) ParseData(data []byte) (config.ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return yaml.Parse(tmpName) +} + // Read yaml file to map. // if json like, use json package, unless goyaml2 package. func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { @@ -93,6 +106,16 @@ func (c *YAMLConfigContainer) Bool(key string) (bool, error) { return false, errors.New("not bool value") } +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *YAMLConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *YAMLConfigContainer) Int(key string) (int, error) { if v, ok := c.data[key].(int64); ok { @@ -101,6 +124,16 @@ func (c *YAMLConfigContainer) Int(key string) (int, error) { return 0, errors.New("not int value") } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *YAMLConfigContainer) Int64(key string) (int64, error) { if v, ok := c.data[key].(int64); ok { @@ -109,6 +142,16 @@ func (c *YAMLConfigContainer) Int64(key string) (int64, error) { return 0, errors.New("not bool value") } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *YAMLConfigContainer) Float(key string) (float64, error) { if v, ok := c.data[key].(float64); ok { @@ -117,6 +160,16 @@ func (c *YAMLConfigContainer) Float(key string) (float64, error) { return 0.0, errors.New("not float64 value") } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *YAMLConfigContainer) String(key string) string { if v, ok := c.data[key].(string); ok { @@ -125,11 +178,52 @@ func (c *YAMLConfigContainer) String(key string) string { return "" } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *YAMLConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *YAMLConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *YAMLConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + err = goyaml2.Write(f, c.data) + return err +} + // WriteValue writes a new value for key. func (c *YAMLConfigContainer) Set(key, val string) error { c.Lock()