2014-08-18 08:41:43 +00:00
|
|
|
// Copyright 2014 beego Author. All Rights Reserved.
|
2014-07-03 15:40:21 +00:00
|
|
|
//
|
2014-08-18 08:41:43 +00:00
|
|
|
// 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
|
2014-07-03 15:40:21 +00:00
|
|
|
//
|
2014-08-18 08:41:43 +00:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2014-07-03 15:40:21 +00:00
|
|
|
//
|
2014-08-18 08:41:43 +00:00
|
|
|
// 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.
|
|
|
|
|
2013-08-21 16:07:33 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"io"
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
"io/ioutil"
|
2013-08-21 16:07:33 +00:00
|
|
|
"os"
|
2017-04-19 11:50:11 +00:00
|
|
|
"os/user"
|
2016-10-14 08:52:03 +00:00
|
|
|
"path/filepath"
|
2013-08-21 16:07:33 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2015-09-10 06:53:19 +00:00
|
|
|
defaultSection = "default" // default section means if some ini items not in a section, make them in default section,
|
|
|
|
bNumComment = []byte{'#'} // number signal
|
|
|
|
bSemComment = []byte{';'} // semicolon signal
|
|
|
|
bEmpty = []byte{}
|
|
|
|
bEqual = []byte{'='} // equal signal
|
|
|
|
bDQuote = []byte{'"'} // quote signal
|
|
|
|
sectionStart = []byte{'['} // section start signal
|
|
|
|
sectionEnd = []byte{']'} // section end signal
|
|
|
|
lineBreak = "\n"
|
2013-08-21 16:07:33 +00:00
|
|
|
)
|
|
|
|
|
2013-12-24 13:57:33 +00:00
|
|
|
// IniConfig implements Config to parse ini file.
|
2013-08-21 16:07:33 +00:00
|
|
|
type IniConfig struct {
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:53:19 +00:00
|
|
|
// Parse creates a new Config and parses the file configuration from the named file.
|
|
|
|
func (ini *IniConfig) Parse(name string) (Configer, error) {
|
2014-10-24 11:03:27 +00:00
|
|
|
return ini.parseFile(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
|
2017-01-09 13:04:11 +00:00
|
|
|
data, err := ioutil.ReadFile(name)
|
2013-08-21 16:07:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-01-11 10:55:53 +00:00
|
|
|
return ini.parseData(filepath.Dir(name), data)
|
2017-01-09 13:04:11 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 10:55:53 +00:00
|
|
|
func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) {
|
2013-08-21 16:07:33 +00:00
|
|
|
cfg := &IniConfigContainer{
|
2017-01-09 13:04:11 +00:00
|
|
|
data: make(map[string]map[string]string),
|
|
|
|
sectionComment: make(map[string]string),
|
|
|
|
keyComment: make(map[string]string),
|
|
|
|
RWMutex: sync.RWMutex{},
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
cfg.Lock()
|
|
|
|
defer cfg.Unlock()
|
|
|
|
|
|
|
|
var comment bytes.Buffer
|
2017-01-09 13:04:11 +00:00
|
|
|
buf := bufio.NewReader(bytes.NewBuffer(data))
|
2014-10-24 11:03:27 +00:00
|
|
|
// check the BOM
|
2014-10-24 05:45:00 +00:00
|
|
|
head, err := buf.Peek(3)
|
|
|
|
if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
|
|
|
|
for i := 1; i <= 3; i++ {
|
|
|
|
buf.ReadByte()
|
|
|
|
}
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
section := defaultSection
|
2013-11-27 15:55:26 +00:00
|
|
|
for {
|
2013-08-21 16:07:33 +00:00
|
|
|
line, _, err := buf.ReadLine()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
2016-03-11 23:20:19 +00:00
|
|
|
//It might be a good idea to throw a error on all unknonw errors?
|
|
|
|
if _, ok := err.(*os.PathError); ok {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-06-01 11:58:35 +00:00
|
|
|
line = bytes.TrimSpace(line)
|
2013-08-21 16:07:33 +00:00
|
|
|
if bytes.Equal(line, bEmpty) {
|
|
|
|
continue
|
|
|
|
}
|
2013-11-28 03:56:13 +00:00
|
|
|
var bComment []byte
|
|
|
|
switch {
|
|
|
|
case bytes.HasPrefix(line, bNumComment):
|
|
|
|
bComment = bNumComment
|
|
|
|
case bytes.HasPrefix(line, bSemComment):
|
|
|
|
bComment = bSemComment
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
2013-11-28 03:56:13 +00:00
|
|
|
if bComment != nil {
|
|
|
|
line = bytes.TrimLeft(line, string(bComment))
|
2016-01-23 06:53:52 +00:00
|
|
|
// Need append to a new line if multi-line comments.
|
|
|
|
if comment.Len() > 0 {
|
|
|
|
comment.WriteByte('\n')
|
|
|
|
}
|
2013-11-27 15:55:26 +00:00
|
|
|
comment.Write(line)
|
|
|
|
continue
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
2013-11-28 03:56:13 +00:00
|
|
|
|
2013-11-27 15:55:26 +00:00
|
|
|
if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
|
2014-07-12 14:12:06 +00:00
|
|
|
section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive
|
2013-11-27 15:55:26 +00:00
|
|
|
if comment.Len() > 0 {
|
|
|
|
cfg.sectionComment[section] = comment.String()
|
|
|
|
comment.Reset()
|
|
|
|
}
|
|
|
|
if _, ok := cfg.data[section]; !ok {
|
|
|
|
cfg.data[section] = make(map[string]string)
|
|
|
|
}
|
2014-07-12 14:12:06 +00:00
|
|
|
continue
|
|
|
|
}
|
2013-11-27 15:55:26 +00:00
|
|
|
|
2014-07-12 14:12:06 +00:00
|
|
|
if _, ok := cfg.data[section]; !ok {
|
|
|
|
cfg.data[section] = make(map[string]string)
|
|
|
|
}
|
|
|
|
keyValue := bytes.SplitN(line, bEqual, 2)
|
2014-10-24 11:03:27 +00:00
|
|
|
|
|
|
|
key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive
|
|
|
|
key = strings.ToLower(key)
|
|
|
|
|
|
|
|
// handle include "other.conf"
|
|
|
|
if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
includefiles := strings.Fields(key)
|
|
|
|
if includefiles[0] == "include" && len(includefiles) == 2 {
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
otherfile := strings.Trim(includefiles[1], "\"")
|
2016-10-14 08:52:03 +00:00
|
|
|
if !filepath.IsAbs(otherfile) {
|
2017-01-09 13:04:11 +00:00
|
|
|
otherfile = filepath.Join(dir, otherfile)
|
2014-10-24 11:03:27 +00:00
|
|
|
}
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
i, err := ini.parseFile(otherfile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
for sec, dt := range i.data {
|
|
|
|
if _, ok := cfg.data[sec]; !ok {
|
|
|
|
cfg.data[sec] = make(map[string]string)
|
|
|
|
}
|
|
|
|
for k, v := range dt {
|
|
|
|
cfg.data[sec][k] = v
|
|
|
|
}
|
|
|
|
}
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
for sec, comm := range i.sectionComment {
|
|
|
|
cfg.sectionComment[sec] = comm
|
|
|
|
}
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
for k, comm := range i.keyComment {
|
|
|
|
cfg.keyComment[k] = comm
|
|
|
|
}
|
2017-01-09 13:04:11 +00:00
|
|
|
|
2014-10-24 11:03:27 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(keyValue) != 2 {
|
|
|
|
return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val")
|
|
|
|
}
|
2014-07-12 14:12:06 +00:00
|
|
|
val := bytes.TrimSpace(keyValue[1])
|
|
|
|
if bytes.HasPrefix(val, bDQuote) {
|
|
|
|
val = bytes.Trim(val, `"`)
|
|
|
|
}
|
|
|
|
|
2016-03-29 13:47:33 +00:00
|
|
|
cfg.data[section][key] = ExpandValueEnv(string(val))
|
2014-07-12 14:12:06 +00:00
|
|
|
if comment.Len() > 0 {
|
|
|
|
cfg.keyComment[section+"."+key] = comment.String()
|
|
|
|
comment.Reset()
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
2015-09-10 06:53:19 +00:00
|
|
|
// ParseData parse ini the data
|
2017-01-11 10:55:53 +00:00
|
|
|
// When include other.conf,other.conf is either absolute directory
|
2017-04-19 11:50:11 +00:00
|
|
|
// or under beego in default temporary directory(/tmp/beego[-username]).
|
2015-09-10 06:53:19 +00:00
|
|
|
func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
|
2017-04-19 11:50:11 +00:00
|
|
|
dir := "beego"
|
|
|
|
currentUser, err := user.Current()
|
|
|
|
if err == nil {
|
|
|
|
dir = "beego-" + currentUser.Username
|
|
|
|
}
|
|
|
|
dir = filepath.Join(os.TempDir(), dir)
|
|
|
|
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-01-11 10:55:53 +00:00
|
|
|
|
|
|
|
return ini.parseData(dir, data)
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2015-09-10 06:53:19 +00:00
|
|
|
// IniConfigContainer A Config represents the ini configuration.
|
2013-12-24 13:57:33 +00:00
|
|
|
// When set and get value, support key as section:name type.
|
2013-08-21 16:07:33 +00:00
|
|
|
type IniConfigContainer struct {
|
2013-12-24 13:57:33 +00:00
|
|
|
data map[string]map[string]string // section=> key:val
|
|
|
|
sectionComment map[string]string // section : comment
|
2014-07-12 14:12:06 +00:00
|
|
|
keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment.
|
2013-08-21 16:07:33 +00:00
|
|
|
sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bool returns the boolean value for a given key.
|
|
|
|
func (c *IniConfigContainer) Bool(key string) (bool, error) {
|
Support Parse Bool with more diffrent values
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.
2016-01-23 03:02:40 +00:00
|
|
|
return ParseBool(c.getdata(key))
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultBool returns the boolean value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
|
2015-09-10 06:53:19 +00:00
|
|
|
v, err := c.Bool(key)
|
|
|
|
if err != nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:07:33 +00:00
|
|
|
// Int returns the integer value for a given key.
|
|
|
|
func (c *IniConfigContainer) Int(key string) (int, error) {
|
2014-08-25 12:14:14 +00:00
|
|
|
return strconv.Atoi(c.getdata(key))
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultInt returns the integer value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
|
2015-09-10 06:53:19 +00:00
|
|
|
v, err := c.Int(key)
|
|
|
|
if err != nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2013-12-24 13:57:33 +00:00
|
|
|
// Int64 returns the int64 value for a given key.
|
2013-08-21 16:07:33 +00:00
|
|
|
func (c *IniConfigContainer) Int64(key string) (int64, error) {
|
2014-08-25 12:14:14 +00:00
|
|
|
return strconv.ParseInt(c.getdata(key), 10, 64)
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultInt64 returns the int64 value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
|
2015-09-10 06:53:19 +00:00
|
|
|
v, err := c.Int64(key)
|
|
|
|
if err != nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:07:33 +00:00
|
|
|
// Float returns the float value for a given key.
|
|
|
|
func (c *IniConfigContainer) Float(key string) (float64, error) {
|
2014-08-25 12:14:14 +00:00
|
|
|
return strconv.ParseFloat(c.getdata(key), 64)
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultFloat returns the float64 value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
|
2015-09-10 06:53:19 +00:00
|
|
|
v, err := c.Float(key)
|
|
|
|
if err != nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:07:33 +00:00
|
|
|
// String returns the string value for a given key.
|
2014-08-25 13:31:53 +00:00
|
|
|
func (c *IniConfigContainer) String(key string) string {
|
2014-08-25 12:14:14 +00:00
|
|
|
return c.getdata(key)
|
2013-08-21 16:07:33 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultString returns the string value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultString(key string, defaultval string) string {
|
2015-09-10 06:53:19 +00:00
|
|
|
v := c.String(key)
|
|
|
|
if v == "" {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2014-01-15 09:19:03 +00:00
|
|
|
// Strings returns the []string value for a given key.
|
2016-03-03 12:03:23 +00:00
|
|
|
// Return nil if config value does not exist or is empty.
|
2014-01-15 09:19:03 +00:00
|
|
|
func (c *IniConfigContainer) Strings(key string) []string {
|
2016-03-02 14:44:20 +00:00
|
|
|
v := c.String(key)
|
|
|
|
if v == "" {
|
2016-03-03 12:03:23 +00:00
|
|
|
return nil
|
2016-03-02 14:44:20 +00:00
|
|
|
}
|
|
|
|
return strings.Split(v, ";")
|
2014-01-15 09:19:03 +00:00
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
// DefaultStrings returns the []string value for a given key.
|
|
|
|
// if err != nil return defaltval
|
|
|
|
func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
|
2015-09-10 06:53:19 +00:00
|
|
|
v := c.Strings(key)
|
2016-03-03 12:03:23 +00:00
|
|
|
if v == nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
return defaultval
|
|
|
|
}
|
2015-09-10 06:53:19 +00:00
|
|
|
return v
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2017-03-03 16:24:02 +00:00
|
|
|
return nil, errors.New("not exist section")
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2016-03-12 06:32:39 +00:00
|
|
|
// SaveConfigFile save the config into file.
|
|
|
|
//
|
|
|
|
// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation.
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
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()
|
|
|
|
|
2016-01-23 06:53:52 +00:00
|
|
|
// Get section or key comments. Fixed #1607
|
|
|
|
getCommentStr := func(section, key string) string {
|
|
|
|
comment, ok := "", false
|
|
|
|
if len(key) == 0 {
|
|
|
|
comment, ok = c.sectionComment[section]
|
|
|
|
} else {
|
|
|
|
comment, ok = c.keyComment[section+"."+key]
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
// Empty comment
|
|
|
|
if len(comment) == 0 || len(strings.TrimSpace(comment)) == 0 {
|
|
|
|
return string(bNumComment)
|
|
|
|
}
|
|
|
|
prefix := string(bNumComment)
|
|
|
|
// Add the line head character "#"
|
|
|
|
return prefix + strings.Replace(comment, lineBreak, lineBreak+prefix, -1)
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
buf := bytes.NewBuffer(nil)
|
2015-05-04 13:54:03 +00:00
|
|
|
// Save default section at first place
|
2015-09-10 06:53:19 +00:00
|
|
|
if dt, ok := c.data[defaultSection]; ok {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
for key, val := range dt {
|
|
|
|
if key != " " {
|
|
|
|
// Write key comments.
|
2016-01-23 06:53:52 +00:00
|
|
|
if v := getCommentStr(defaultSection, key); len(v) > 0 {
|
|
|
|
if _, err = buf.WriteString(v + lineBreak); err != nil {
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 13:54:03 +00:00
|
|
|
// Save named sections
|
|
|
|
for section, dt := range c.data {
|
2015-09-10 06:53:19 +00:00
|
|
|
if section != defaultSection {
|
2015-05-04 13:54:03 +00:00
|
|
|
// Write section comments.
|
2016-01-23 06:53:52 +00:00
|
|
|
if v := getCommentStr(section, ""); len(v) > 0 {
|
|
|
|
if _, err = buf.WriteString(v + lineBreak); err != nil {
|
2015-05-04 13:54:03 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2016-01-23 06:53:52 +00:00
|
|
|
if v := getCommentStr(section, key); len(v) > 0 {
|
|
|
|
if _, err = buf.WriteString(v + lineBreak); err != nil {
|
2015-05-04 13:54:03 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-17 17:24:45 +00:00
|
|
|
_, err = buf.WriteTo(f)
|
|
|
|
return err
|
config: add more method
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
2014-08-07 09:24:21 +00:00
|
|
|
}
|
|
|
|
|
2015-09-10 06:53:19 +00:00
|
|
|
// Set writes a new value for key.
|
2013-12-24 13:57:33 +00:00
|
|
|
// if write to one section, the key need be "section::key".
|
|
|
|
// if the section is not existed, it panics.
|
2013-08-21 16:07:33 +00:00
|
|
|
func (c *IniConfigContainer) Set(key, value string) error {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
2013-11-27 15:55:26 +00:00
|
|
|
if len(key) == 0 {
|
|
|
|
return errors.New("key is empty")
|
|
|
|
}
|
2013-11-29 02:17:35 +00:00
|
|
|
|
2014-07-12 14:12:06 +00:00
|
|
|
var (
|
|
|
|
section, k string
|
2017-04-10 03:30:23 +00:00
|
|
|
sectionKey = strings.Split(strings.ToLower(key), "::")
|
2014-07-12 14:12:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if len(sectionKey) >= 2 {
|
|
|
|
section = sectionKey[0]
|
|
|
|
k = sectionKey[1]
|
2013-11-27 15:55:26 +00:00
|
|
|
} else {
|
2015-09-10 06:53:19 +00:00
|
|
|
section = defaultSection
|
2014-07-12 14:12:06 +00:00
|
|
|
k = sectionKey[0]
|
2013-11-27 15:55:26 +00:00
|
|
|
}
|
2014-07-12 14:12:06 +00:00
|
|
|
|
2013-12-24 13:57:15 +00:00
|
|
|
if _, ok := c.data[section]; !ok {
|
|
|
|
c.data[section] = make(map[string]string)
|
|
|
|
}
|
2013-11-27 15:55:26 +00:00
|
|
|
c.data[section][k] = value
|
2013-08-21 16:07:33 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-12-24 13:57:33 +00:00
|
|
|
// DIY returns the raw value by a given key.
|
2013-08-21 16:07:33 +00:00
|
|
|
func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
|
2014-07-12 14:12:06 +00:00
|
|
|
if v, ok := c.data[strings.ToLower(key)]; ok {
|
2013-08-21 16:07:33 +00:00
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
return v, errors.New("key not find")
|
|
|
|
}
|
|
|
|
|
2013-12-24 13:57:33 +00:00
|
|
|
// section.key or key
|
2013-11-27 15:55:26 +00:00
|
|
|
func (c *IniConfigContainer) getdata(key string) string {
|
2014-08-25 13:31:53 +00:00
|
|
|
if len(key) == 0 {
|
2013-11-27 15:55:26 +00:00
|
|
|
return ""
|
|
|
|
}
|
2014-08-25 13:31:53 +00:00
|
|
|
c.RLock()
|
2014-08-25 12:14:14 +00:00
|
|
|
defer c.RUnlock()
|
2013-11-29 02:17:35 +00:00
|
|
|
|
2014-07-12 14:12:06 +00:00
|
|
|
var (
|
|
|
|
section, k string
|
2015-09-10 06:53:19 +00:00
|
|
|
sectionKey = strings.Split(strings.ToLower(key), "::")
|
2014-07-12 14:12:06 +00:00
|
|
|
)
|
|
|
|
if len(sectionKey) >= 2 {
|
|
|
|
section = sectionKey[0]
|
|
|
|
k = sectionKey[1]
|
2013-11-27 15:55:26 +00:00
|
|
|
} else {
|
2015-09-10 06:53:19 +00:00
|
|
|
section = defaultSection
|
2014-07-12 14:12:06 +00:00
|
|
|
k = sectionKey[0]
|
2013-11-27 15:55:26 +00:00
|
|
|
}
|
|
|
|
if v, ok := c.data[section]; ok {
|
2014-07-13 10:11:13 +00:00
|
|
|
if vv, ok := v[k]; ok {
|
2013-11-27 15:55:26 +00:00
|
|
|
return vv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2013-08-21 16:07:33 +00:00
|
|
|
func init() {
|
|
|
|
Register("ini", &IniConfig{})
|
|
|
|
}
|