diff --git a/third_party/github.com/ccding/go-config-reader/config/config.go b/third_party/github.com/ccding/go-config-reader/config/config.go index 97b899ef2..36ca20dec 100644 --- a/third_party/github.com/ccding/go-config-reader/config/config.go +++ b/third_party/github.com/ccding/go-config-reader/config/config.go @@ -13,23 +13,60 @@ // limitations under the License. // // author: Cong Ding -// + package config import ( "bufio" "errors" + "fmt" + "io/ioutil" "os" "strings" ) var commentPrefix = []string{"//", "#", ";"} -func Read(filename string) (map[string]string, error) { - var res = map[string]string{} - in, err := os.Open(filename) +// Config struct constructs a new configuration handler. +type Config struct { + filename string + config map[string]map[string]string +} + +// NewConfig function cnstructs a new Config struct with filename. You have to +// call Read() function to let it read from the file. Otherwise you will get +// empty string (i.e., "") when you are calling Get() function. Another usage +// is that you call NewConfig() function and then call Add()/Set() function to +// add new key-values to the configuration. Finally you can call Write() +// function to write the new configuration to the file. +func NewConfig(filename string) *Config { + c := new(Config) + c.filename = filename + c.config = make(map[string]map[string]string) + return c +} + +// Filename function returns the filename of the configuration. +func (c *Config) Filename() string { + return c.filename +} + +// SetFilename function sets the filename of the configuration. +func (c *Config) SetFilename(filename string) { + c.filename = filename +} + +// Reset function reset the map in the configuration. +func (c *Config) Reset() { + c.config = make(map[string]map[string]string) +} + +// Read function reads configurations from the file defined in +// Config.filename. +func (c *Config) Read() error { + in, err := os.Open(c.filename) if err != nil { - return res, err + return err } defer in.Close() scanner := bufio.NewScanner(in) @@ -40,9 +77,9 @@ func Read(filename string) (map[string]string, error) { continue } if line == "" { - sec := checkSection(scanner.Text()) - if sec != "" { - section = sec + "." + sec, ok := checkSection(scanner.Text()) + if ok { + section = sec continue } } @@ -54,40 +91,103 @@ func Read(filename string) (map[string]string, error) { line = line[:len(line)-1] continue } - key, value, err := checkLine(line) - if err != nil { - return res, errors.New("WRONG: " + line) + key, value, ok := checkLine(line) + if !ok { + return errors.New("WRONG: " + line) } - res[section+key] = value + c.Set(section, key, value) line = "" } - return res, nil + return nil } -func checkSection(line string) string { +// Get function returns the value of a key in the configuration. If the key +// does not exist, it returns empty string (i.e., ""). +func (c *Config) Get(section string, key string) string { + value, ok := c.config[section][key] + if !ok { + return "" + } + return value +} + +// Set function updates the value of a key in the configuration. Function +// Set() is exactly the same as function Add(). +func (c *Config) Set(section string, key string, value string) { + _, ok := c.config[section] + if !ok { + c.config[section] = make(map[string]string) + } + c.config[section][key] = value +} + +// Add function adds a new key to the configuration. Function Add() is exactly +// the same as function Set(). +func (c *Config) Add(section string, key string, value string) { + c.Set(section, key, value) +} + +// Del function deletes a key from the configuration. +func (c *Config) Del(section string, key string) { + _, ok := c.config[section] + if ok { + delete(c.config[section], key) + if len(c.config[section]) == 0 { + delete(c.config, section) + } + } +} + +// Write function writes the updated configuration back. +func (c *Config) Write() error { + return nil +} + +// WriteTo function writes the configuration to a new file. This function +// re-organizes the configuration and deletes all the comments. +func (c *Config) WriteTo(filename string) error { + content := "" + for k, v := range c.config { + format := "%v = %v\n" + if k != "" { + content += fmt.Sprintf("[%v]\n", k) + format = "\t" + format + } + for key, value := range v { + content += fmt.Sprintf(format, key, value) + } + } + return ioutil.WriteFile(filename, []byte(content), 0644) +} + +// To check this line is a section or not. If it is not a section, it returns +// "". +func checkSection(line string) (string, bool) { line = strings.TrimSpace(line) lineLen := len(line) if lineLen < 2 { - return "" + return "", false } if line[0] == '[' && line[lineLen-1] == ']' { - return line[1 : lineLen-1] + return line[1 : lineLen-1], true } - return "" + return "", false } -func checkLine(line string) (string, string, error) { +// To check this line is a valid key-value pair or not. +func checkLine(line string) (string, string, bool) { key := "" value := "" sp := strings.SplitN(line, "=", 2) if len(sp) != 2 { - return key, value, errors.New("WRONG: " + line) + return key, value, false } key = strings.TrimSpace(sp[0]) value = strings.TrimSpace(sp[1]) - return key, value, nil + return key, value, true } +// To check this line is a whole line comment or not. func checkComment(line string) bool { line = strings.TrimSpace(line) for p := range commentPrefix { diff --git a/third_party/github.com/ccding/go-config-reader/example.go b/third_party/github.com/ccding/go-config-reader/example.go index da49575f2..17587442b 100644 --- a/third_party/github.com/ccding/go-config-reader/example.go +++ b/third_party/github.com/ccding/go-config-reader/example.go @@ -13,7 +13,7 @@ // limitations under the License. // // author: Cong Ding -// + package main import ( @@ -22,9 +22,11 @@ import ( ) func main() { - res, err := config.Read("example.conf") + c := config.NewConfig("example.conf") + err := c.Read() fmt.Println(err) - fmt.Println(res) - fmt.Println(res["test.a"]) - fmt.Println(res["dd"]) + fmt.Println(c) + fmt.Println(c.Get("test", "a")) + fmt.Println(c.Get("", "dd")) + c.WriteTo("example2.conf") }