diff --git a/vendor/gopkg.in/ini.v1/.travis.yml b/vendor/gopkg.in/ini.v1/.travis.yml index c8ea49c..08682ef 100644 --- a/vendor/gopkg.in/ini.v1/.travis.yml +++ b/vendor/gopkg.in/ini.v1/.travis.yml @@ -7,7 +7,9 @@ go: - 1.9.x - 1.10.x - 1.11.x + - 1.12.x +install: skip script: - go get golang.org/x/tools/cmd/cover - go get github.com/smartystreets/goconvey diff --git a/vendor/gopkg.in/ini.v1/README.md b/vendor/gopkg.in/ini.v1/README.md index ae4dfc3..44e1fcd 100644 --- a/vendor/gopkg.in/ini.v1/README.md +++ b/vendor/gopkg.in/ini.v1/README.md @@ -22,18 +22,10 @@ Package ini provides INI file read and write functionality in Go. The minimum requirement of Go is **1.6**. -To use a tagged revision: - ```sh $ go get gopkg.in/ini.v1 ``` -To use with latest changes: - -```sh -$ go get github.com/go-ini/ini -``` - Please add `-u` flag to update in the future. ## Getting Help diff --git a/vendor/gopkg.in/ini.v1/data_source.go b/vendor/gopkg.in/ini.v1/data_source.go new file mode 100644 index 0000000..dc0277e --- /dev/null +++ b/vendor/gopkg.in/ini.v1/data_source.go @@ -0,0 +1,74 @@ +// Copyright 2019 Unknwon +// +// 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 ini + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" +) + +var ( + _ dataSource = (*sourceFile)(nil) + _ dataSource = (*sourceData)(nil) + _ dataSource = (*sourceReadCloser)(nil) +) + +// dataSource is an interface that returns object which can be read and closed. +type dataSource interface { + ReadCloser() (io.ReadCloser, error) +} + +// sourceFile represents an object that contains content on the local file system. +type sourceFile struct { + name string +} + +func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { + return os.Open(s.name) +} + +// sourceData represents an object that contains content in memory. +type sourceData struct { + data []byte +} + +func (s *sourceData) ReadCloser() (io.ReadCloser, error) { + return ioutil.NopCloser(bytes.NewReader(s.data)), nil +} + +// sourceReadCloser represents an input stream with Close method. +type sourceReadCloser struct { + reader io.ReadCloser +} + +func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { + return s.reader, nil +} + +func parseDataSource(source interface{}) (dataSource, error) { + switch s := source.(type) { + case string: + return sourceFile{s}, nil + case []byte: + return &sourceData{s}, nil + case io.ReadCloser: + return &sourceReadCloser{s}, nil + default: + return nil, fmt.Errorf("error parsing data source: unknown type %q", s) + } +} diff --git a/vendor/gopkg.in/ini.v1/deprecated.go b/vendor/gopkg.in/ini.v1/deprecated.go new file mode 100644 index 0000000..e8bda06 --- /dev/null +++ b/vendor/gopkg.in/ini.v1/deprecated.go @@ -0,0 +1,25 @@ +// Copyright 2019 Unknwon +// +// 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 ini + +const ( + // Deprecated: Use "DefaultSection" instead. + DEFAULT_SECTION = DefaultSection +) + +var ( + // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. + AllCapsUnderscore = SnackCase +) diff --git a/vendor/gopkg.in/ini.v1/error.go b/vendor/gopkg.in/ini.v1/error.go index 80afe74..d88347c 100644 --- a/vendor/gopkg.in/ini.v1/error.go +++ b/vendor/gopkg.in/ini.v1/error.go @@ -18,10 +18,12 @@ import ( "fmt" ) +// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one. type ErrDelimiterNotFound struct { Line string } +// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound. func IsErrDelimiterNotFound(err error) bool { _, ok := err.(ErrDelimiterNotFound) return ok diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go index 0ed0eaf..017b77c 100644 --- a/vendor/gopkg.in/ini.v1/file.go +++ b/vendor/gopkg.in/ini.v1/file.go @@ -68,7 +68,7 @@ func Empty() *File { func (f *File) NewSection(name string) (*Section, error) { if len(name) == 0 { return nil, errors.New("error creating new section: empty section name") - } else if f.options.Insensitive && name != DEFAULT_SECTION { + } else if f.options.Insensitive && name != DefaultSection { name = strings.ToLower(name) } @@ -111,7 +111,7 @@ func (f *File) NewSections(names ...string) (err error) { // GetSection returns section by given name. func (f *File) GetSection(name string) (*Section, error) { if len(name) == 0 { - name = DEFAULT_SECTION + name = DefaultSection } if f.options.Insensitive { name = strings.ToLower(name) @@ -141,7 +141,7 @@ func (f *File) Section(name string) *Section { return sec } -// Section returns list of Section. +// Sections returns a list of Section stored in the current instance. func (f *File) Sections() []*Section { if f.BlockMode { f.lock.RLock() @@ -175,7 +175,7 @@ func (f *File) DeleteSection(name string) { } if len(name) == 0 { - name = DEFAULT_SECTION + name = DefaultSection } for i, s := range f.sectionList { @@ -302,11 +302,11 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { } alignSpaces := bytes.Repeat([]byte(" "), alignLength) - KEY_LIST: + KeyList: for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { - if len(indent) > 0 && sname != DEFAULT_SECTION { + if len(indent) > 0 && sname != DefaultSection { buf.WriteString(indent) } @@ -325,7 +325,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { } } - if len(indent) > 0 && sname != DEFAULT_SECTION { + if len(indent) > 0 && sname != DefaultSection { buf.WriteString(indent) } @@ -347,7 +347,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { if kname != sec.keyList[len(sec.keyList)-1] { buf.WriteString(LineBreak) } - continue KEY_LIST + continue KeyList } // Write out alignment spaces before "=" sign diff --git a/vendor/gopkg.in/ini.v1/helper.go b/vendor/gopkg.in/ini.v1/helper.go new file mode 100644 index 0000000..f9d80a6 --- /dev/null +++ b/vendor/gopkg.in/ini.v1/helper.go @@ -0,0 +1,24 @@ +// Copyright 2019 Unknwon +// +// 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 ini + +func inSlice(str string, s []string) bool { + for _, v := range s { + if str == v { + return true + } + } + return false +} diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index f827a1e..9de6171 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -18,55 +18,47 @@ package ini import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" "regexp" "runtime" ) const ( - // Name for default section. You can use this constant or the string literal. + // DefaultSection is the name of default section. You can use this constant or the string literal. // In most of cases, an empty string is all you need to access the section. - DEFAULT_SECTION = "DEFAULT" + DefaultSection = "DEFAULT" // Maximum allowed depth when recursively substituing variable names. - _DEPTH_VALUES = 99 - _VERSION = "1.42.0" + depthValues = 99 + version = "1.48.0" ) // Version returns current package version literal. func Version() string { - return _VERSION + return version } var ( - // Delimiter to determine or compose a new line. - // This variable will be changed to "\r\n" automatically on Windows - // at package init time. + // LineBreak is the delimiter to determine or compose a new line. + // This variable will be changed to "\r\n" automatically on Windows at package init time. LineBreak = "\n" - // Place custom spaces when PrettyFormat and PrettyEqual are both disabled - DefaultFormatLeft = "" - DefaultFormatRight = "" - // Variable regexp pattern: %(variable)s - varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) + varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) - // Indicate whether to align "=" sign with spaces to produce pretty output - // or reduce all possible spaces for compact format. - PrettyFormat = true - - // Place spaces around "=" sign even when PrettyFormat is false - PrettyEqual = false - - // Explicitly write DEFAULT section header + // DefaultHeader explicitly writes default section header. DefaultHeader = false - // Indicate whether to put a line between sections + // PrettySection indicates whether to put a line between sections. PrettySection = true + // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output + // or reduce all possible spaces for compact format. + PrettyFormat = true + // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. + PrettyEqual = false + // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. + DefaultFormatLeft = "" + // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. + DefaultFormatRight = "" ) func init() { @@ -75,60 +67,7 @@ func init() { } } -func inSlice(str string, s []string) bool { - for _, v := range s { - if str == v { - return true - } - } - return false -} - -// dataSource is an interface that returns object which can be read and closed. -type dataSource interface { - ReadCloser() (io.ReadCloser, error) -} - -// sourceFile represents an object that contains content on the local file system. -type sourceFile struct { - name string -} - -func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { - return os.Open(s.name) -} - -// sourceData represents an object that contains content in memory. -type sourceData struct { - data []byte -} - -func (s *sourceData) ReadCloser() (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(s.data)), nil -} - -// sourceReadCloser represents an input stream with Close method. -type sourceReadCloser struct { - reader io.ReadCloser -} - -func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { - return s.reader, nil -} - -func parseDataSource(source interface{}) (dataSource, error) { - switch s := source.(type) { - case string: - return sourceFile{s}, nil - case []byte: - return &sourceData{s}, nil - case io.ReadCloser: - return &sourceReadCloser{s}, nil - default: - return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s) - } -} - +// LoadOptions contains all customized options used for load data source(s). type LoadOptions struct { // Loose indicates whether the parser should ignore nonexistent files or return error. Loose bool @@ -174,6 +113,7 @@ type LoadOptions struct { PreserveSurroundedQuote bool } +// LoadSources allows caller to apply customized options for loading from data source(s). func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { sources := make([]dataSource, len(others)+1) sources[0], err = parseDataSource(source) diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go index 0fee0dc..62f9146 100644 --- a/vendor/gopkg.in/ini.v1/key.go +++ b/vendor/gopkg.in/ini.v1/key.go @@ -54,6 +54,16 @@ func (k *Key) addShadow(val string) error { return errors.New("cannot add shadow to auto-increment or boolean key") } + // Deduplicate shadows based on their values. + if k.value == val { + return nil + } + for i := range k.shadows { + if k.shadows[i].value == val { + return nil + } + } + shadow := newKey(k.s, k.name, val) shadow.isShadow = true k.shadows = append(k.shadows, shadow) @@ -77,6 +87,7 @@ func (k *Key) addNestedValue(val string) error { return nil } +// AddNestedValue adds a nested value to the key. func (k *Key) AddNestedValue(val string) error { if !k.s.f.options.AllowNestedValues { return errors.New("nested value is not allowed") @@ -126,7 +137,7 @@ func (k *Key) transformValue(val string) string { if !strings.Contains(val, "%") { return val } - for i := 0; i < _DEPTH_VALUES; i++ { + for i := 0; i < depthValues; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { break @@ -186,8 +197,8 @@ func (k *Key) Float64() (float64, error) { // Int returns int type value. func (k *Key) Int() (int, error) { - v, err := strconv.ParseInt(k.String(), 0, 64) - return int(v), err + v, err := strconv.ParseInt(k.String(), 0, 64) + return int(v), err } // Int64 returns int64 type value. @@ -491,7 +502,7 @@ func (k *Key) Strings(delim string) []string { buf.WriteRune(runes[idx]) } } - idx += 1 + idx++ if idx == len(runes) { break } @@ -553,6 +564,12 @@ func (k *Key) Uint64s(delim string) []uint64 { return vals } +// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Bools(delim string) []bool { + vals, _ := k.parseBools(k.Strings(delim), true, false) + return vals +} + // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { @@ -601,6 +618,13 @@ func (k *Key) ValidUint64s(delim string) []uint64 { return vals } +// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned +// integer, then it will not be included to result list. +func (k *Key) ValidBools(delim string) []bool { + vals, _ := k.parseBools(k.Strings(delim), false, false) + return vals +} + // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) @@ -637,6 +661,11 @@ func (k *Key) StrictUint64s(delim string) ([]uint64, error) { return k.parseUint64s(k.Strings(delim), false, true) } +// StrictBools returns list of bool divided by given delimiter or error on first invalid input. +func (k *Key) StrictBools(delim string) ([]bool, error) { + return k.parseBools(k.Strings(delim), false, true) +} + // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { @@ -649,6 +678,21 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } +// parseBools transforms strings to bools. +func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { + vals := make([]bool, 0, len(strs)) + for _, str := range strs { + val, err := parseBool(str) + if err != nil && returnOnInvalid { + return nil, err + } + if err == nil || addInvalid { + vals = append(vals, val) + } + } + return vals, nil +} + // parseFloat64s transforms strings to float64s. func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) @@ -669,7 +713,7 @@ func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, vals := make([]int, 0, len(strs)) for _, str := range strs { valInt64, err := strconv.ParseInt(str, 0, 64) - val := int(valInt64) + val := int(valInt64) if err != nil && returnOnInvalid { return nil, err } diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index f20073d..7c22a25 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -27,25 +27,29 @@ import ( var pythonMultiline = regexp.MustCompile("^(\\s+)([^\n]+)") -type tokenType int - -const ( - _TOKEN_INVALID tokenType = iota - _TOKEN_COMMENT - _TOKEN_SECTION - _TOKEN_KEY -) +type parserOptions struct { + IgnoreContinuation bool + IgnoreInlineComment bool + AllowPythonMultilineValues bool + SpaceBeforeInlineComment bool + UnescapeValueDoubleQuotes bool + UnescapeValueCommentSymbols bool + PreserveSurroundedQuote bool +} type parser struct { buf *bufio.Reader + options parserOptions + isEOF bool count int comment *bytes.Buffer } -func newParser(r io.Reader) *parser { +func newParser(r io.Reader, opts parserOptions) *parser { return &parser{ buf: bufio.NewReader(r), + options: opts, count: 1, comment: &bytes.Buffer{}, } @@ -196,12 +200,13 @@ func hasSurroundedQuote(in string, quote byte) bool { strings.IndexByte(in[1:], quote) == len(in)-2 } -func (p *parser) readValue(in []byte, - parserBufferSize int, - ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols, allowPythonMultilines, spaceBeforeInlineComment, preserveSurroundedQuote bool) (string, error) { +func (p *parser) readValue(in []byte, bufferSize int) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { + if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { + return p.readPythonMultilines(line, bufferSize) + } return "", nil } @@ -210,7 +215,7 @@ func (p *parser) readValue(in []byte, valQuote = `"""` } else if line[0] == '`' { valQuote = "`" - } else if unescapeValueDoubleQuotes && line[0] == '"' { + } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' { valQuote = `"` } @@ -222,7 +227,7 @@ func (p *parser) readValue(in []byte, return p.readMultilines(line, line[startIdx:], valQuote) } - if unescapeValueDoubleQuotes && valQuote == `"` { + if p.options.UnescapeValueDoubleQuotes && valQuote == `"` { return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil } return line[startIdx : pos+startIdx], nil @@ -234,14 +239,14 @@ func (p *parser) readValue(in []byte, trimmedLastChar := line[len(line)-1] // Check continuation lines when desired - if !ignoreContinuation && trimmedLastChar == '\\' { + if !p.options.IgnoreContinuation && trimmedLastChar == '\\' { return p.readContinuationLines(line[:len(line)-1]) } // Check if ignore inline comment - if !ignoreInlineComment { + if !p.options.IgnoreInlineComment { var i int - if spaceBeforeInlineComment { + if p.options.SpaceBeforeInlineComment { i = strings.Index(line, " #") if i == -1 { i = strings.Index(line, " ;") @@ -260,65 +265,75 @@ func (p *parser) readValue(in []byte, // Trim single and double quotes if (hasSurroundedQuote(line, '\'') || - hasSurroundedQuote(line, '"')) && !preserveSurroundedQuote { + hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { line = line[1 : len(line)-1] - } else if len(valQuote) == 0 && unescapeValueCommentSymbols { + } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { if strings.Contains(line, `\;`) { line = strings.Replace(line, `\;`, ";", -1) } if strings.Contains(line, `\#`) { line = strings.Replace(line, `\#`, "#", -1) } - } else if allowPythonMultilines && lastChar == '\n' { - parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize) - peekBuffer := bytes.NewBuffer(parserBufferPeekResult) - - val := line - - for { - peekData, peekErr := peekBuffer.ReadBytes('\n') - if peekErr != nil { - if peekErr == io.EOF { - return val, nil - } - return "", peekErr - } - - peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) - if len(peekMatches) != 3 { - return val, nil - } - - // NOTE: Return if not a python-ini multi-line value. - currentIdentSize := len(peekMatches[1]) - if currentIdentSize <= 0 { - return val, nil - } - - // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. - _, err := p.readUntil('\n') - if err != nil { - return "", err - } - - val += fmt.Sprintf("\n%s", peekMatches[2]) - } + } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { + return p.readPythonMultilines(line, bufferSize) } return line, nil } +func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { + parserBufferPeekResult, _ := p.buf.Peek(bufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { + return line, nil + } + return "", peekErr + } + + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + if len(peekMatches) != 3 { + return line, nil + } + + // NOTE: Return if not a python-ini multi-line value. + currentIdentSize := len(peekMatches[1]) + if currentIdentSize <= 0 { + return line, nil + } + + // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.readUntil('\n') + if err != nil { + return "", err + } + + line += fmt.Sprintf("\n%s", peekMatches[2]) + } +} + // parse parses data through an io.Reader. func (f *File) parse(reader io.Reader) (err error) { - p := newParser(reader) + p := newParser(reader, parserOptions{ + IgnoreContinuation: f.options.IgnoreContinuation, + IgnoreInlineComment: f.options.IgnoreInlineComment, + AllowPythonMultilineValues: f.options.AllowPythonMultilineValues, + SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment, + UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes, + UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols, + PreserveSurroundedQuote: f.options.PreserveSurroundedQuote, + }) if err = p.BOM(); err != nil { return fmt.Errorf("BOM: %v", err) } // Ignore error because default section name is never empty string. - name := DEFAULT_SECTION + name := DefaultSection if f.options.Insensitive { - name = strings.ToLower(DEFAULT_SECTION) + name = strings.ToLower(DefaultSection) } section, _ := f.NewSection(name) @@ -426,15 +441,7 @@ func (f *File) parse(reader io.Reader) (err error) { if IsErrDelimiterNotFound(err) { switch { case f.options.AllowBooleanKeys: - kname, err := p.readValue(line, - parserBufferSize, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols, - f.options.AllowPythonMultilineValues, - f.options.SpaceBeforeInlineComment, - f.options.PreserveSurroundedQuote) + kname, err := p.readValue(line, parserBufferSize) if err != nil { return err } @@ -461,15 +468,7 @@ func (f *File) parse(reader io.Reader) (err error) { p.count++ } - value, err := p.readValue(line[offset:], - parserBufferSize, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols, - f.options.AllowPythonMultilineValues, - f.options.SpaceBeforeInlineComment, - f.options.PreserveSurroundedQuote) + value, err := p.readValue(line[offset:], parserBufferSize) if err != nil { return err } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index bc32c62..0bd3e13 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -106,7 +106,6 @@ func (s *Section) NewBooleanKey(name string) (*Key, error) { // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { - // FIXME: change to section level lock? if s.f.BlockMode { s.f.lock.RLock() } @@ -129,9 +128,8 @@ func (s *Section) GetKey(name string) (*Key, error) { continue } return sec.GetKey(name) - } else { - break } + break } return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) } @@ -144,8 +142,7 @@ func (s *Section) HasKey(name string) bool { return key != nil } -// Haskey is a backwards-compatible name for HasKey. -// TODO: delete me in v2 +// Deprecated: Use "HasKey" instead. func (s *Section) Haskey(name string) bool { return s.HasKey(name) } diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go index a9dfed0..2764534 100644 --- a/vendor/gopkg.in/ini.v1/struct.go +++ b/vendor/gopkg.in/ini.v1/struct.go @@ -29,8 +29,8 @@ type NameMapper func(string) string // Built-in name getters. var ( - // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. - AllCapsUnderscore NameMapper = func(raw string) string { + // SnackCase converts to format SNACK_CASE. + SnackCase NameMapper = func(raw string) string { newstr := make([]rune, 0, len(raw)) for i, chr := range raw { if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { @@ -50,7 +50,7 @@ var ( if i > 0 { newstr = append(newstr, '_') } - chr -= ('A' - 'a') + chr -= 'A' - 'a' } newstr = append(newstr, chr) } @@ -108,6 +108,8 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh vals, err = key.parseUint64s(strs, true, false) case reflect.Float64: vals, err = key.parseFloat64s(strs, true, false) + case reflect.Bool: + vals, err = key.parseBools(strs, true, false) case reflectTime: vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) default: @@ -132,6 +134,8 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) case reflect.Float64: slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) + case reflect.Bool: + slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) case reflectTime: slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) } @@ -149,7 +153,7 @@ func wrapStrictError(err error, isStrict bool) error { // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, -// because we want to use default value that is already assigned to strcut. +// because we want to use default value that is already assigned to struct. func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { switch t.Kind() { case reflect.String: @@ -205,6 +209,17 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: return setSliceWithProperType(key, field, delim, allowShadow, isStrict) + case reflect.Ptr: + switch t.Elem().Kind() { + case reflect.Bool: + boolVal, err := key.Bool() + if err != nil { + return wrapStrictError(err, isStrict) + } + field.Set(reflect.ValueOf(&boolVal)) + default: + return fmt.Errorf("unsupported type '%s'", t) + } default: return fmt.Errorf("unsupported type '%s'", t) } @@ -244,14 +259,21 @@ func (s *Section) mapTo(val reflect.Value, isStrict bool) error { continue } - isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous isStruct := tpField.Type.Kind() == reflect.Struct + isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct + isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous if isAnonymous { field.Set(reflect.New(tpField.Type.Elem())) } - if isAnonymous || isStruct { + if isAnonymous || isStruct || isStructPtr { if sec, err := s.f.GetSection(fieldName); err == nil { + // Only set the field to non-nil struct value if we have + // a section for it. Otherwise, we end up with a non-nil + // struct ptr even though there is no data. + if isStructPtr && field.IsNil() { + field.Set(reflect.New(tpField.Type.Elem())) + } if err = sec.mapTo(field, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } @@ -283,7 +305,7 @@ func (s *Section) MapTo(v interface{}) error { return s.mapTo(val, false) } -// MapTo maps section to given struct in strict mode, +// StrictMapTo maps section to given struct in strict mode, // which returns all possible error including value parsing error. func (s *Section) StrictMapTo(v interface{}) error { typ := reflect.TypeOf(v) @@ -303,13 +325,13 @@ func (f *File) MapTo(v interface{}) error { return f.Section("").MapTo(v) } -// MapTo maps file to given struct in strict mode, +// StrictMapTo maps file to given struct in strict mode, // which returns all possible error including value parsing error. func (f *File) StrictMapTo(v interface{}) error { return f.Section("").StrictMapTo(v) } -// MapTo maps data sources to given struct with name mapper. +// MapToWithMapper maps data sources to given struct with name mapper. func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) if err != nil { @@ -342,14 +364,45 @@ func StrictMapTo(v, source interface{}, others ...interface{}) error { } // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. -func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { +func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { slice := field.Slice(0, field.Len()) if field.Len() == 0 { return nil } + sliceOf := field.Type().Elem().Kind() + + if allowShadow { + var keyWithShadows *Key + for i := 0; i < field.Len(); i++ { + var val string + switch sliceOf { + case reflect.String: + val = slice.Index(i).String() + case reflect.Int, reflect.Int64: + val = fmt.Sprint(slice.Index(i).Int()) + case reflect.Uint, reflect.Uint64: + val = fmt.Sprint(slice.Index(i).Uint()) + case reflect.Float64: + val = fmt.Sprint(slice.Index(i).Float()) + case reflect.Bool: + val = fmt.Sprint(slice.Index(i).Bool()) + case reflectTime: + val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) + default: + return fmt.Errorf("unsupported type '[]%s'", sliceOf) + } + + if i == 0 { + keyWithShadows = newKey(key.s, key.name, val) + } else { + keyWithShadows.AddShadow(val) + } + } + key = keyWithShadows + return nil + } var buf bytes.Buffer - sliceOf := field.Type().Elem().Kind() for i := 0; i < field.Len(); i++ { switch sliceOf { case reflect.String: @@ -360,6 +413,8 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) err buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) case reflect.Float64: buf.WriteString(fmt.Sprint(slice.Index(i).Float())) + case reflect.Bool: + buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) case reflectTime: buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) default: @@ -367,12 +422,12 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) err } buf.WriteString(delim) } - key.SetValue(buf.String()[:buf.Len()-1]) + key.SetValue(buf.String()[:buf.Len()-len(delim)]) return nil } // reflectWithProperType does the opposite thing as setWithProperType. -func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { +func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { switch t.Kind() { case reflect.String: key.SetValue(field.String()) @@ -387,7 +442,11 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim case reflectTime: key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) case reflect.Slice: - return reflectSliceWithProperType(key, field, delim) + return reflectSliceWithProperType(key, field, delim, allowShadow) + case reflect.Ptr: + if !field.IsNil() { + return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow) + } default: return fmt.Errorf("unsupported type '%s'", t) } @@ -432,12 +491,12 @@ func (s *Section) reflectFrom(val reflect.Value) error { continue } - opts := strings.SplitN(tag, ",", 2) - if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { + rawName, omitEmpty, allowShadow := parseTagOptions(tag) + if omitEmpty && isEmptyValue(field) { continue } - fieldName := s.parseFieldName(tpField.Name, opts[0]) + fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } @@ -473,7 +532,7 @@ func (s *Section) reflectFrom(val reflect.Value) error { key.Comment = tpField.Tag.Get("comment") } - if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { + if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim")), allowShadow); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } @@ -500,7 +559,7 @@ func (f *File) ReflectFrom(v interface{}) error { return f.Section("").ReflectFrom(v) } -// ReflectFrom reflects data sources from given struct with name mapper. +// ReflectFromWithMapper reflects data sources from given struct with name mapper. func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { cfg.NameMapper = mapper return cfg.ReflectFrom(v) diff --git a/vendor/modules.txt b/vendor/modules.txt index 512ce69..879230e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,2 +1,2 @@ -# gopkg.in/ini.v1 v1.42.0 +# gopkg.in/ini.v1 v1.48.0 gopkg.in/ini.v1