summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/ini.v1
diff options
context:
space:
mode:
authorTamal Saha <tamal@appscode.com>2019-08-23 09:40:30 -0700
committertechknowlogick <techknowlogick@gitea.io>2019-08-23 12:40:29 -0400
commit171b3598778a1ecd0a921c71ed6755bfef68f7f0 (patch)
tree02857629ef9e8e26ee0ee559153f803f77b588b7 /vendor/gopkg.in/ini.v1
parentca6fb004ac50fc924861112403895d637c6a2d1d (diff)
downloadgitea-171b3598778a1ecd0a921c71ed6755bfef68f7f0.tar.gz
gitea-171b3598778a1ecd0a921c71ed6755bfef68f7f0.zip
Use gitea forked macaron (#7933)
Signed-off-by: Tamal Saha <tamal@appscode.com>
Diffstat (limited to 'vendor/gopkg.in/ini.v1')
-rw-r--r--vendor/gopkg.in/ini.v1/.travis.yml2
-rw-r--r--vendor/gopkg.in/ini.v1/README.md20
-rw-r--r--vendor/gopkg.in/ini.v1/error.go2
-rw-r--r--vendor/gopkg.in/ini.v1/file.go12
-rw-r--r--vendor/gopkg.in/ini.v1/ini.go32
-rw-r--r--vendor/gopkg.in/ini.v1/key.go11
-rw-r--r--vendor/gopkg.in/ini.v1/parser.go135
-rw-r--r--vendor/gopkg.in/ini.v1/section.go7
-rw-r--r--vendor/gopkg.in/ini.v1/struct.go83
9 files changed, 184 insertions, 120 deletions
diff --git a/vendor/gopkg.in/ini.v1/.travis.yml b/vendor/gopkg.in/ini.v1/.travis.yml
index c8ea49ccc6..08682ef840 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 ae4dfc3a5a..036c56d63b 100644
--- a/vendor/gopkg.in/ini.v1/README.md
+++ b/vendor/gopkg.in/ini.v1/README.md
@@ -22,19 +22,27 @@ 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:
+Please add `-u` flag to update in the future.
+
+## Go Modules
+
+For historical reason, people use two different import paths for this package: `github.com/go-ini/ini` and `gopkg.in/ini.v1`. If you get error similar to the following one:
-```sh
-$ go get github.com/go-ini/ini
+```
+go: finding github.com/go-ini/ini v0.0.0-00010101000000-000000000000
+go: github.com/go-ini/ini@v0.0.0-00010101000000-000000000000: unknown revision 000000000000
+go: error loading module requirements
```
-Please add `-u` flag to update in the future.
+It is because one of your dependencies is using deprecated import path `github.com/go-ini/ini`, you can make a quick fix by adding the following line to your `go.mod` file (`v.1.44.0` was the latest version tagged on `master` branch):
+
+```
+replace github.com/go-ini/ini => gopkg.in/ini.v1 v1.44.0
+```
## Getting Help
diff --git a/vendor/gopkg.in/ini.v1/error.go b/vendor/gopkg.in/ini.v1/error.go
index 80afe74315..d88347c54b 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 0ed0eafd02..b38aadd1f8 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 {
@@ -306,7 +306,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
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)
}
diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go
index f827a1ef99..36c072cdf3 100644
--- a/vendor/gopkg.in/ini.v1/ini.go
+++ b/vendor/gopkg.in/ini.v1/ini.go
@@ -28,44 +28,46 @@ import (
)
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"
+ // Deprecated: Use "DefaultSection" instead.
+ DEFAULT_SECTION = DefaultSection
// Maximum allowed depth when recursively substituing variable names.
- _DEPTH_VALUES = 99
- _VERSION = "1.42.0"
+ depthValues = 99
+ version = "1.46.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 = ""
+ // 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 = ""
// Variable regexp pattern: %(variable)s
varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`)
- // Indicate whether to align "=" sign with spaces to produce pretty output
+ // PrettyFormat indicates 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 places 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
)
@@ -129,6 +131,7 @@ func parseDataSource(source interface{}) (dataSource, error) {
}
}
+// 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 +177,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 0fee0dc7e4..38860ff4bd 100644
--- a/vendor/gopkg.in/ini.v1/key.go
+++ b/vendor/gopkg.in/ini.v1/key.go
@@ -77,6 +77,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 +127,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 +187,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 +492,7 @@ func (k *Key) Strings(delim string) []string {
buf.WriteRune(runes[idx])
}
}
- idx += 1
+ idx++
if idx == len(runes) {
break
}
@@ -669,7 +670,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 f20073d1b4..7c22a25c1a 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)
+ } else if p.options.AllowPythonMultilineValues && lastChar == '\n' {
+ return p.readPythonMultilines(line, bufferSize)
+ }
- val := line
+ return line, nil
+}
- for {
- peekData, peekErr := peekBuffer.ReadBytes('\n')
- if peekErr != nil {
- if peekErr == io.EOF {
- return val, nil
- }
- return "", peekErr
- }
+func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) {
+ parserBufferPeekResult, _ := p.buf.Peek(bufferSize)
+ peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
- peekMatches := pythonMultiline.FindStringSubmatch(string(peekData))
- if len(peekMatches) != 3 {
- return val, nil
+ for {
+ peekData, peekErr := peekBuffer.ReadBytes('\n')
+ if peekErr != nil {
+ if peekErr == io.EOF {
+ return line, nil
}
+ return "", peekErr
+ }
- // NOTE: Return if not a python-ini multi-line value.
- currentIdentSize := len(peekMatches[1])
- if currentIdentSize <= 0 {
- return val, nil
- }
+ peekMatches := pythonMultiline.FindStringSubmatch(string(peekData))
+ if len(peekMatches) != 3 {
+ 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
- }
+ // NOTE: Return if not a python-ini multi-line value.
+ currentIdentSize := len(peekMatches[1])
+ if currentIdentSize <= 0 {
+ return line, nil
+ }
- val += fmt.Sprintf("\n%s", peekMatches[2])
+ // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer.
+ _, err := p.readUntil('\n')
+ if err != nil {
+ return "", err
}
- }
- return line, nil
+ 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 bc32c620d6..0bd3e13015 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 a9dfed078a..c713f8296c 100644
--- a/vendor/gopkg.in/ini.v1/struct.go
+++ b/vendor/gopkg.in/ini.v1/struct.go
@@ -149,7 +149,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 +205,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 +255,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 +301,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 +321,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 +360,43 @@ 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 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:
@@ -367,12 +414,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 +434,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 +483,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 +524,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 +551,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)