aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/pelletier
diff options
context:
space:
mode:
authorNiall Sheridan <nsheridan@gmail.com>2018-06-20 22:39:07 +0100
committerNiall Sheridan <nsheridan@gmail.com>2018-06-20 22:39:07 +0100
commitde6d2c524430287c699aaa898c1325da6afea539 (patch)
treef78eb841208d667668a7bc92a9290d693cc7103b /vendor/github.com/pelletier
parenteb99016e1629e690e55633de6fc63a14c53e7ea2 (diff)
Update dependencies
Diffstat (limited to 'vendor/github.com/pelletier')
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/README.md62
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/buffruneio.go117
-rw-r--r--vendor/github.com/pelletier/go-toml/README.md18
-rw-r--r--vendor/github.com/pelletier/go-toml/doc.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/fuzz.go31
-rwxr-xr-xvendor/github.com/pelletier/go-toml/fuzz.sh15
-rw-r--r--vendor/github.com/pelletier/go-toml/keysparsing.go15
-rw-r--r--vendor/github.com/pelletier/go-toml/lexer.go101
-rw-r--r--vendor/github.com/pelletier/go-toml/marshal.go365
-rw-r--r--vendor/github.com/pelletier/go-toml/parser.go79
-rwxr-xr-xvendor/github.com/pelletier/go-toml/test.sh4
-rw-r--r--vendor/github.com/pelletier/go-toml/token.go4
-rw-r--r--vendor/github.com/pelletier/go-toml/toml.go85
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_write.go87
14 files changed, 617 insertions, 368 deletions
diff --git a/vendor/github.com/pelletier/go-buffruneio/README.md b/vendor/github.com/pelletier/go-buffruneio/README.md
deleted file mode 100644
index ff608b3..0000000
--- a/vendor/github.com/pelletier/go-buffruneio/README.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# buffruneio
-
-[![Tests Status](https://travis-ci.org/pelletier/go-buffruneio.svg?branch=master)](https://travis-ci.org/pelletier/go-buffruneio)
-[![GoDoc](https://godoc.org/github.com/pelletier/go-buffruneio?status.svg)](https://godoc.org/github.com/pelletier/go-buffruneio)
-
-Buffruneio is a wrapper around bufio to provide buffered runes access with
-unlimited unreads.
-
-```go
-import "github.com/pelletier/go-buffruneio"
-```
-
-## Examples
-
-```go
-import (
- "fmt"
- "github.com/pelletier/go-buffruneio"
- "strings"
-)
-
-reader := buffruneio.NewReader(strings.NewReader("abcd"))
-fmt.Println(reader.ReadRune()) // 'a'
-fmt.Println(reader.ReadRune()) // 'b'
-fmt.Println(reader.ReadRune()) // 'c'
-reader.UnreadRune()
-reader.UnreadRune()
-fmt.Println(reader.ReadRune()) // 'b'
-fmt.Println(reader.ReadRune()) // 'c'
-```
-
-## Documentation
-
-The documentation and additional examples are available at
-[godoc.org](http://godoc.org/github.com/pelletier/go-buffruneio).
-
-## Contribute
-
-Feel free to report bugs and patches using GitHub's pull requests system on
-[pelletier/go-toml](https://github.com/pelletier/go-buffruneio). Any feedback is
-much appreciated!
-
-## LICENSE
-
-Copyright (c) 2016 Thomas Pelletier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go
deleted file mode 100644
index 4e6d6ea..0000000
--- a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads.
-package buffruneio
-
-import (
- "bufio"
- "container/list"
- "errors"
- "io"
-)
-
-// Rune to indicate end of file.
-const (
- EOF = -(iota + 1)
-)
-
-// ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer.
-var ErrNoRuneToUnread = errors.New("no rune to unwind")
-
-// Reader implements runes buffering for an io.Reader object.
-type Reader struct {
- buffer *list.List
- current *list.Element
- input *bufio.Reader
-}
-
-// NewReader returns a new Reader.
-func NewReader(rd io.Reader) *Reader {
- return &Reader{
- buffer: list.New(),
- input: bufio.NewReader(rd),
- }
-}
-
-type runeWithSize struct {
- r rune
- size int
-}
-
-func (rd *Reader) feedBuffer() error {
- r, size, err := rd.input.ReadRune()
-
- if err != nil {
- if err != io.EOF {
- return err
- }
- r = EOF
- }
-
- newRuneWithSize := runeWithSize{r, size}
-
- rd.buffer.PushBack(newRuneWithSize)
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- }
- return nil
-}
-
-// ReadRune reads the next rune from buffer, or from the underlying reader if needed.
-func (rd *Reader) ReadRune() (rune, int, error) {
- if rd.current == rd.buffer.Back() || rd.current == nil {
- err := rd.feedBuffer()
- if err != nil {
- return EOF, 0, err
- }
- }
-
- runeWithSize := rd.current.Value.(runeWithSize)
- rd.current = rd.current.Next()
- return runeWithSize.r, runeWithSize.size, nil
-}
-
-// UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
-func (rd *Reader) UnreadRune() error {
- if rd.current == rd.buffer.Front() {
- return ErrNoRuneToUnread
- }
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- } else {
- rd.current = rd.current.Prev()
- }
- return nil
-}
-
-// Forget removes runes stored before the current stream position index.
-func (rd *Reader) Forget() {
- if rd.current == nil {
- rd.current = rd.buffer.Back()
- }
- for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
- }
-}
-
-// PeekRune returns at most the next n runes, reading from the uderlying source if
-// needed. Does not move the current index. It includes EOF if reached.
-func (rd *Reader) PeekRunes(n int) []rune {
- res := make([]rune, 0, n)
- cursor := rd.current
- for i := 0; i < n; i++ {
- if cursor == nil {
- err := rd.feedBuffer()
- if err != nil {
- return res
- }
- cursor = rd.buffer.Back()
- }
- if cursor != nil {
- r := cursor.Value.(runeWithSize).r
- res = append(res, r)
- if r == EOF {
- return res
- }
- cursor = cursor.Next()
- }
- }
- return res
-}
diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md
index 2681690..0d357ac 100644
--- a/vendor/github.com/pelletier/go-toml/README.md
+++ b/vendor/github.com/pelletier/go-toml/README.md
@@ -57,9 +57,9 @@ type Config struct {
}
doc := []byte(`
-[postgres]
-user = "pelletier"
-password = "mypassword"`)
+[Postgres]
+User = "pelletier"
+Password = "mypassword"`)
config := Config{}
toml.Unmarshal(doc, &config)
@@ -114,6 +114,18 @@ You have to make sure two kind of tests run:
You can run both of them using `./test.sh`.
+### Fuzzing
+
+The script `./fuzz.sh` is available to
+run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml.
+
+## Versioning
+
+Go-toml follows [Semantic Versioning](http://semver.org/). The supported version
+of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
+this document. The last two major versions of Go are supported
+(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
+
## License
The MIT License (MIT). Read [LICENSE](LICENSE).
diff --git a/vendor/github.com/pelletier/go-toml/doc.go b/vendor/github.com/pelletier/go-toml/doc.go
index 3c89619..d5fd98c 100644
--- a/vendor/github.com/pelletier/go-toml/doc.go
+++ b/vendor/github.com/pelletier/go-toml/doc.go
@@ -17,7 +17,7 @@
// JSONPath-like queries
//
// The package github.com/pelletier/go-toml/query implements a system
-// similar to JSONPath to quickly retrive elements of a TOML document using a
+// similar to JSONPath to quickly retrieve elements of a TOML document using a
// single expression. See the package documentation for more information.
//
package toml
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.go b/vendor/github.com/pelletier/go-toml/fuzz.go
new file mode 100644
index 0000000..14570c8
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/fuzz.go
@@ -0,0 +1,31 @@
+// +build gofuzz
+
+package toml
+
+func Fuzz(data []byte) int {
+ tree, err := LoadBytes(data)
+ if err != nil {
+ if tree != nil {
+ panic("tree must be nil if there is an error")
+ }
+ return 0
+ }
+
+ str, err := tree.ToTomlString()
+ if err != nil {
+ if str != "" {
+ panic(`str must be "" if there is an error`)
+ }
+ panic(err)
+ }
+
+ tree, err = Load(str)
+ if err != nil {
+ if tree != nil {
+ panic("tree must be nil if there is an error")
+ }
+ return 0
+ }
+
+ return 1
+}
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.sh b/vendor/github.com/pelletier/go-toml/fuzz.sh
new file mode 100755
index 0000000..3204b4c
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/fuzz.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+set -eu
+
+go get github.com/dvyukov/go-fuzz/go-fuzz
+go get github.com/dvyukov/go-fuzz/go-fuzz-build
+
+if [ ! -e toml-fuzz.zip ]; then
+ go-fuzz-build github.com/pelletier/go-toml
+fi
+
+rm -fr fuzz
+mkdir -p fuzz/corpus
+cp *.toml fuzz/corpus
+
+go-fuzz -bin=toml-fuzz.zip -workdir=fuzz
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go
index d62ca5f..284db64 100644
--- a/vendor/github.com/pelletier/go-toml/keysparsing.go
+++ b/vendor/github.com/pelletier/go-toml/keysparsing.go
@@ -9,12 +9,14 @@ import (
"unicode"
)
+// Convert the bare key group string to an array.
+// The input supports double quotation to allow "." inside the key name,
+// but escape sequences are not supported. Lexers must unescape them beforehand.
func parseKey(key string) ([]string, error) {
groups := []string{}
var buffer bytes.Buffer
inQuotes := false
wasInQuotes := false
- escapeNext := false
ignoreSpace := true
expectDot := false
@@ -25,15 +27,7 @@ func parseKey(key string) ([]string, error) {
}
ignoreSpace = false
}
- if escapeNext {
- buffer.WriteRune(char)
- escapeNext = false
- continue
- }
switch char {
- case '\\':
- escapeNext = true
- continue
case '"':
if inQuotes {
groups = append(groups, buffer.String())
@@ -77,9 +71,6 @@ func parseKey(key string) ([]string, error) {
if inQuotes {
return nil, errors.New("mismatched quotes")
}
- if escapeNext {
- return nil, errors.New("unfinished escape sequence")
- }
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go
index 1b6647d..d11de42 100644
--- a/vendor/github.com/pelletier/go-toml/lexer.go
+++ b/vendor/github.com/pelletier/go-toml/lexer.go
@@ -204,6 +204,14 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
return l.lexFalse
}
+ if l.follow("inf") {
+ return l.lexInf
+ }
+
+ if l.follow("nan") {
+ return l.lexNan
+ }
+
if isSpace(next) {
l.skip()
continue
@@ -265,6 +273,18 @@ func (l *tomlLexer) lexFalse() tomlLexStateFn {
return l.lexRvalue
}
+func (l *tomlLexer) lexInf() tomlLexStateFn {
+ l.fastForward(3)
+ l.emit(tokenInf)
+ return l.lexRvalue
+}
+
+func (l *tomlLexer) lexNan() tomlLexStateFn {
+ l.fastForward(3)
+ l.emit(tokenNan)
+ return l.lexRvalue
+}
+
func (l *tomlLexer) lexEqual() tomlLexStateFn {
l.next()
l.emit(tokenEqual)
@@ -277,6 +297,8 @@ func (l *tomlLexer) lexComma() tomlLexStateFn {
return l.lexRvalue
}
+// Parse the key and emits its value without escape sequences.
+// bare keys, basic string keys and literal string keys are supported.
func (l *tomlLexer) lexKey() tomlLexStateFn {
growingString := ""
@@ -287,7 +309,16 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
if err != nil {
return l.errorf(err.Error())
}
- growingString += `"` + str + `"`
+ growingString += str
+ l.next()
+ continue
+ } else if r == '\'' {
+ l.next()
+ str, err := l.lexLiteralStringAsString(`'`, false)
+ if err != nil {
+ return l.errorf(err.Error())
+ }
+ growingString += str
l.next()
continue
} else if r == '\n' {
@@ -527,6 +558,7 @@ func (l *tomlLexer) lexTableKey() tomlLexStateFn {
return l.lexInsideTableKey
}
+// Parse the key till "]]", but only bare keys are supported
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() {
switch r {
@@ -550,6 +582,7 @@ func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
return l.errorf("unclosed table array key")
}
+// Parse the key till "]" but only bare keys are supported
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() {
switch r {
@@ -575,11 +608,77 @@ func (l *tomlLexer) lexRightBracket() tomlLexStateFn {
return l.lexRvalue
}
+type validRuneFn func(r rune) bool
+
+func isValidHexRune(r rune) bool {
+ return r >= 'a' && r <= 'f' ||
+ r >= 'A' && r <= 'F' ||
+ r >= '0' && r <= '9' ||
+ r == '_'
+}
+
+func isValidOctalRune(r rune) bool {
+ return r >= '0' && r <= '7' || r == '_'
+}
+
+func isValidBinaryRune(r rune) bool {
+ return r == '0' || r == '1' || r == '_'
+}
+
func (l *tomlLexer) lexNumber() tomlLexStateFn {
r := l.peek()
+
+ if r == '0' {
+ follow := l.peekString(2)
+ if len(follow) == 2 {
+ var isValidRune validRuneFn
+ switch follow[1] {
+ case 'x':
+ isValidRune = isValidHexRune
+ case 'o':
+ isValidRune = isValidOctalRune
+ case 'b':
+ isValidRune = isValidBinaryRune
+ default:
+ if follow[1] >= 'a' && follow[1] <= 'z' || follow[1] >= 'A' && follow[1] <= 'Z' {
+ return l.errorf("unknown number base: %s. possible options are x (hex) o (octal) b (binary)", string(follow[1]))
+ }
+ }
+
+ if isValidRune != nil {
+ l.next()
+ l.next()
+ digitSeen := false
+ for {
+ next := l.peek()
+ if !isValidRune(next) {
+ break
+ }
+ digitSeen = true
+ l.next()
+ }
+
+ if !digitSeen {
+ return l.errorf("number needs at least one digit")
+ }
+
+ l.emit(tokenInteger)
+
+ return l.lexRvalue
+ }
+ }
+ }
+
if r == '+' || r == '-' {
l.next()
+ if l.follow("inf") {
+ return l.lexInf
+ }
+ if l.follow("nan") {
+ return l.lexNan
+ }
}
+
pointSeen := false
expSeen := false
digitSeen := false
diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go
index ce3bd8d..671da55 100644
--- a/vendor/github.com/pelletier/go-toml/marshal.go
+++ b/vendor/github.com/pelletier/go-toml/marshal.go
@@ -4,20 +4,33 @@ import (
"bytes"
"errors"
"fmt"
+ "io"
"reflect"
"strconv"
"strings"
"time"
)
+const tagKeyMultiline = "multiline"
+
type tomlOpts struct {
name string
comment string
commented bool
+ multiline bool
include bool
omitempty bool
}
+type encOpts struct {
+ quoteMapKeys bool
+ arraysOneElementPerLine bool
+}
+
+var encOptsDefaults = encOpts{
+ quoteMapKeys: false,
+}
+
var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
@@ -105,7 +118,7 @@ The following struct annotations are supported:
commented:"true" Emits the value as commented.
Note that pointers are automatically assigned the "omitempty" option, as TOML
-explicity does not handle null values (saying instead the label should be
+explicitly does not handle null values (saying instead the label should be
dropped).
Tree structural types and corresponding marshal types:
@@ -125,6 +138,66 @@ Tree primitive types and corresponding marshal types:
time.Time time.Time{}, pointers to same
*/
func Marshal(v interface{}) ([]byte, error) {
+ return NewEncoder(nil).marshal(v)
+}
+
+// Encoder writes TOML values to an output stream.
+type Encoder struct {
+ w io.Writer
+ encOpts
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: w,
+ encOpts: encOptsDefaults,
+ }
+}
+
+// Encode writes the TOML encoding of v to the stream.
+//
+// See the documentation for Marshal for details.
+func (e *Encoder) Encode(v interface{}) error {
+ b, err := e.marshal(v)
+ if err != nil {
+ return err
+ }
+ if _, err := e.w.Write(b); err != nil {
+ return err
+ }
+ return nil
+}
+
+// QuoteMapKeys sets up the encoder to encode
+// maps with string type keys with quoted TOML keys.
+//
+// This relieves the character limitations on map keys.
+func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
+ e.quoteMapKeys = v
+ return e
+}
+
+// ArraysWithOneElementPerLine sets up the encoder to encode arrays
+// with more than one element on multiple lines instead of one.
+//
+// For example:
+//
+// A = [1,2,3]
+//
+// Becomes
+//
+// A = [
+// 1,
+// 2,
+// 3,
+// ]
+func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder {
+ e.arraysOneElementPerLine = v
+ return e
+}
+
+func (e *Encoder) marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
@@ -133,18 +206,21 @@ func Marshal(v interface{}) ([]byte, error) {
if isCustomMarshaler(mtype) {
return callCustomMarshaler(sval)
}
- t, err := valueToTree(mtype, sval)
+ t, err := e.valueToTree(mtype, sval)
if err != nil {
return []byte{}, err
}
- s, err := t.ToTomlString()
- return []byte(s), err
+
+ var buf bytes.Buffer
+ _, err = t.writeTo(&buf, "", "", 0, e.arraysOneElementPerLine)
+
+ return buf.Bytes(), err
}
// Convert given marshal struct or map value to toml tree
-func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
+func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if mtype.Kind() == reflect.Ptr {
- return valueToTree(mtype.Elem(), mval.Elem())
+ return e.valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTree()
switch mtype.Kind() {
@@ -153,31 +229,44 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef)
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
- val, err := valueToToml(mtypef.Type, mvalf)
+ val, err := e.valueToToml(mtypef.Type, mvalf)
if err != nil {
return nil, err
}
- tval.Set(opts.name, opts.comment, opts.commented, val)
+
+ tval.SetWithOptions(opts.name, SetOptions{
+ Comment: opts.comment,
+ Commented: opts.commented,
+ Multiline: opts.multiline,
+ }, val)
}
}
case reflect.Map:
for _, key := range mval.MapKeys() {
mvalf := mval.MapIndex(key)
- val, err := valueToToml(mtype.Elem(), mvalf)
+ val, err := e.valueToToml(mtype.Elem(), mvalf)
if err != nil {
return nil, err
}
- tval.Set(key.String(), "", false, val)
+ if e.quoteMapKeys {
+ keyStr, err := tomlValueStringRepresentation(key.String(), "", e.arraysOneElementPerLine)
+ if err != nil {
+ return nil, err
+ }
+ tval.SetPath([]string{keyStr}, val)
+ } else {
+ tval.Set(key.String(), val)
+ }
}
}
return tval, nil
}
// Convert given marshal slice to slice of Toml trees
-func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
+func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
tval := make([]*Tree, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
- val, err := valueToTree(mtype.Elem(), mval.Index(i))
+ val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
@@ -187,10 +276,10 @@ func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
}
// Convert given marshal slice to slice of toml values
-func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
+func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
tval := make([]interface{}, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
- val, err := valueToToml(mtype.Elem(), mval.Index(i))
+ val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
@@ -200,19 +289,19 @@ func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, err
}
// Convert given marshal value to toml value
-func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
+func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
if mtype.Kind() == reflect.Ptr {
- return valueToToml(mtype.Elem(), mval.Elem())
+ return e.valueToToml(mtype.Elem(), mval.Elem())
}
switch {
case isCustomMarshaler(mtype):
return callCustomMarshaler(mval)
case isTree(mtype):
- return valueToTree(mtype, mval)
+ return e.valueToTree(mtype, mval)
case isTreeSlice(mtype):
- return valueToTreeSlice(mtype, mval)
+ return e.valueToTreeSlice(mtype, mval)
case isOtherSlice(mtype):
- return valueToOtherSlice(mtype, mval)
+ return e.valueToOtherSlice(mtype, mval)
default:
switch mtype.Kind() {
case reflect.Bool:
@@ -237,17 +326,16 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
// sub-structs, and only definite types can be unmarshaled.
func (t *Tree) Unmarshal(v interface{}) error {
- mtype := reflect.TypeOf(v)
- if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
- return errors.New("Only a pointer to struct can be unmarshaled from TOML")
- }
+ d := Decoder{tval: t}
+ return d.unmarshal(v)
+}
- sval, err := valueFromTree(mtype.Elem(), t)
- if err != nil {
- return err
- }
- reflect.ValueOf(v).Elem().Set(sval)
- return nil
+// Marshal returns the TOML encoding of Tree.
+// See Marshal() documentation for types mapping table.
+func (t *Tree) Marshal() ([]byte, error) {
+ var buf bytes.Buffer
+ err := NewEncoder(&buf).Encode(t)
+ return buf.Bytes(), err
}
// Unmarshal parses the TOML-encoded data and stores the result in the value
@@ -269,10 +357,52 @@ func Unmarshal(data []byte, v interface{}) error {
return t.Unmarshal(v)
}
+// Decoder reads and decodes TOML values from an input stream.
+type Decoder struct {
+ r io.Reader
+ tval *Tree
+ encOpts
+}
+
+// NewDecoder returns a new decoder that reads from r.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{
+ r: r,
+ encOpts: encOptsDefaults,
+ }
+}
+
+// Decode reads a TOML-encoded value from it's input
+// and unmarshals it in the value pointed at by v.
+//
+// See the documentation for Marshal for details.
+func (d *Decoder) Decode(v interface{}) error {
+ var err error
+ d.tval, err = LoadReader(d.r)
+ if err != nil {
+ return err
+ }
+ return d.unmarshal(v)
+}
+
+func (d *Decoder) unmarshal(v interface{}) error {
+ mtype := reflect.TypeOf(v)
+ if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
+ return errors.New("Only a pointer to struct can be unmarshaled from TOML")
+ }
+
+ sval, err := d.valueFromTree(mtype.Elem(), d.tval)
+ if err != nil {
+ return err
+ }
+ reflect.ValueOf(v).Elem().Set(sval)
+ return nil
+}
+
// Convert toml tree to marshal struct or map, using marshal type
-func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
+func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
- return unwrapPointer(mtype, tval)
+ return d.unwrapPointer(mtype, tval)
}
var mval reflect.Value
switch mtype.Kind() {
@@ -290,7 +420,7 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
continue
}
val := tval.Get(key)
- mvalf, err := valueFromToml(mtypef.Type, val)
+ mvalf, err := d.valueFromToml(mtypef.Type, val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
@@ -302,8 +432,9 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
case reflect.Map:
mval = reflect.MakeMap(mtype)
for _, key := range tval.Keys() {
- val := tval.Get(key)
- mvalf, err := valueFromToml(mtype.Elem(), val)
+ // TODO: path splits key
+ val := tval.GetPath([]string{key})
+ mvalf, err := d.valueFromToml(mtype.Elem(), val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
@@ -314,10 +445,10 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
}
// Convert toml value to marshal struct/map slice, using marshal type
-func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
+func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
- val, err := valueFromTree(mtype.Elem(), tval[i])
+ val, err := d.valueFromTree(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
@@ -327,10 +458,10 @@ func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error)
}
// Convert toml value to marshal primitive slice, using marshal type
-func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
+func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
- val, err := valueFromToml(mtype.Elem(), tval[i])
+ val, err := d.valueFromToml(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
@@ -340,117 +471,86 @@ func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value,
}
// Convert toml value to marshal value, using marshal type
-func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
+func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
- return unwrapPointer(mtype, tval)
+ return d.unwrapPointer(mtype, tval)
}
- switch {
- case isTree(mtype):
- return valueFromTree(mtype, tval.(*Tree))
- case isTreeSlice(mtype):
- return valueFromTreeSlice(mtype, tval.([]*Tree))
- case isOtherSlice(mtype):
- return valueFromOtherSlice(mtype, tval.([]interface{}))
+
+ switch tval.(type) {
+ case *Tree:
+ if isTree(mtype) {
+ return d.valueFromTree(mtype, tval.(*Tree))
+ }
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
+ case []*Tree:
+ if isTreeSlice(mtype) {
+ return d.valueFromTreeSlice(mtype, tval.([]*Tree))
+ }
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
+ case []interface{}:
+ if isOtherSlice(mtype) {
+ return d.valueFromOtherSlice(mtype, tval.([]interface{}))
+ }
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
default:
switch mtype.Kind() {
- case reflect.Bool:
- val, ok := tval.(bool)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
- }
- return reflect.ValueOf(val), nil
- case reflect.Int:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
- }
- return reflect.ValueOf(int(val)), nil
- case reflect.Int8:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
- }
- return reflect.ValueOf(int8(val)), nil
- case reflect.Int16:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
- }
- return reflect.ValueOf(int16(val)), nil
- case reflect.Int32:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
+ case reflect.Bool, reflect.Struct:
+ val := reflect.ValueOf(tval)
+ // if this passes for when mtype is reflect.Struct, tval is a time.Time
+ if !val.Type().ConvertibleTo(mtype) {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(int32(val)), nil
- case reflect.Int64:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
- }
- return reflect.ValueOf(val), nil
- case reflect.Uint:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
- }
- return reflect.ValueOf(uint(val)), nil
- case reflect.Uint8:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
+
+ return val.Convert(mtype), nil
+ case reflect.String:
+ val := reflect.ValueOf(tval)
+ // stupidly, int64 is convertible to string. So special case this.
+ if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(uint8(val)), nil
- case reflect.Uint16:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
+
+ return val.Convert(mtype), nil
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val := reflect.ValueOf(tval)
+ if !val.Type().ConvertibleTo(mtype) {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(uint16(val)), nil
- case reflect.Uint32:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
+ if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Int()) {
+ return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(uint32(val)), nil
- case reflect.Uint64:
- val, ok := tval.(int64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
+
+ return val.Convert(mtype), nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ val := reflect.ValueOf(tval)
+ if !val.Type().ConvertibleTo(mtype) {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(uint64(val)), nil
- case reflect.Float32:
- val, ok := tval.(float64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
+ if val.Int() < 0 {
+ return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(float32(val)), nil
- case reflect.Float64:
- val, ok := tval.(float64)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
+ if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Int())) {
+ return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(val), nil
- case reflect.String:
- val, ok := tval.(string)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
+
+ return val.Convert(mtype), nil
+ case reflect.Float32, reflect.Float64:
+ val := reflect.ValueOf(tval)
+ if !val.Type().ConvertibleTo(mtype) {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(val), nil
- case reflect.Struct:
- val, ok := tval.(time.Time)
- if !ok {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
+ if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Float()) {
+ return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
- return reflect.ValueOf(val), nil
+
+ return val.Convert(mtype), nil
default:
- return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind())
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
}
}
}
-func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
- val, err := valueFromToml(mtype.Elem(), tval)
+func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
+ val, err := d.valueFromToml(mtype.Elem(), tval)
if err != nil {
return reflect.ValueOf(nil), err
}
@@ -467,7 +567,8 @@ func tomlOptions(vf reflect.StructField) tomlOpts {
comment = c
}
commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
- result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
+ multiline, _ := strconv.ParseBool(vf.Tag.Get(tagKeyMultiline))
+ result := tomlOpts{name: vf.Name, comment: comment, commented: commented, multiline: multiline, include: true, omitempty: false}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false
diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go
index d492a1e..2d27599 100644
--- a/vendor/github.com/pelletier/go-toml/parser.go
+++ b/vendor/github.com/pelletier/go-toml/parser.go
@@ -5,6 +5,7 @@ package toml
import (
"errors"
"fmt"
+ "math"
"reflect"
"regexp"
"strconv"
@@ -110,7 +111,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
newTree := newTree()
newTree.position = startToken.Position
array = append(array, newTree)
- p.tree.SetPath(p.currentTable, "", false, array)
+ p.tree.SetPath(p.currentTable, array)
// remove all keys that were children of this table array
prefix := key.val + "."
@@ -185,10 +186,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
}
// assign value to the found table
- keyVals, err := parseKey(key.val)
- if err != nil {
- p.raiseError(key, "%s", err)
- }
+ keyVals := []string{key.val}
if len(keyVals) != 1 {
p.raiseError(key, "Invalid key")
}
@@ -212,13 +210,25 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
}
var numberUnderscoreInvalidRegexp *regexp.Regexp
+var hexNumberUnderscoreInvalidRegexp *regexp.Regexp
-func cleanupNumberToken(value string) (string, error) {
+func numberContainsInvalidUnderscore(value string) error {
if numberUnderscoreInvalidRegexp.MatchString(value) {
- return "", errors.New("invalid use of _ in number")
+ return errors.New("invalid use of _ in number")
+ }
+ return nil
+}
+
+func hexNumberContainsInvalidUnderscore(value string) error {
+ if hexNumberUnderscoreInvalidRegexp.MatchString(value) {
+ return errors.New("invalid use of _ in hex number")
}
+ return nil
+}
+
+func cleanupNumberToken(value string) string {
cleanedVal := strings.Replace(value, "_", "", -1)
- return cleanedVal, nil
+ return cleanedVal
}
func (p *tomlParser) parseRvalue() interface{} {
@@ -234,21 +244,57 @@ func (p *tomlParser) parseRvalue() interface{} {
return true
case tokenFalse:
return false
+ case tokenInf:
+ if tok.val[0] == '-' {
+ return math.Inf(-1)
+ }
+ return math.Inf(1)
+ case tokenNan:
+ return math.NaN()
case tokenInteger:
- cleanedVal, err := cleanupNumberToken(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
+ cleanedVal := cleanupNumberToken(tok.val)
+ var err error
+ var val int64
+ if len(cleanedVal) >= 3 && cleanedVal[0] == '0' {
+ switch cleanedVal[1] {
+ case 'x':
+ err = hexNumberContainsInvalidUnderscore(tok.val)
+ if err != nil {
+ p.raiseError(tok, "%s", err)
+ }
+ val, err = strconv.ParseInt(cleanedVal[2:], 16, 64)
+ case 'o':
+ err = numberContainsInvalidUnderscore(tok.val)
+ if err != nil {
+ p.raiseError(tok, "%s", err)
+ }
+ val, err = strconv.ParseInt(cleanedVal[2:], 8, 64)
+ case 'b':
+ err = numberContainsInvalidUnderscore(tok.val)
+ if err != nil {
+ p.raiseError(tok, "%s", err)
+ }
+ val, err = strconv.ParseInt(cleanedVal[2:], 2, 64)
+ default:
+ panic("invalid base") // the lexer should catch this first
+ }
+ } else {
+ err = numberContainsInvalidUnderscore(tok.val)
+ if err != nil {
+ p.raiseError(tok, "%s", err)
+ }
+ val, err = strconv.ParseInt(cleanedVal, 10, 64)
}
- val, err := strconv.ParseInt(cleanedVal, 10, 64)
if err != nil {
p.raiseError(tok, "%s", err)
}
return val
case tokenFloat:
- cleanedVal, err := cleanupNumberToken(tok.val)
+ err := numberContainsInvalidUnderscore(tok.val)
if err != nil {
p.raiseError(tok, "%s", err)
}
+ cleanedVal := cleanupNumberToken(tok.val)
val, err := strconv.ParseFloat(cleanedVal, 64)
if err != nil {
p.raiseError(tok, "%s", err)
@@ -299,7 +345,7 @@ Loop:
key := p.getToken()
p.assume(tokenEqual)
value := p.parseRvalue()
- tree.Set(key.val, "", false, value)
+ tree.Set(key.val, value)
case tokenComma:
if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma")
@@ -309,7 +355,7 @@ Loop:
}
p.getToken()
default:
- p.raiseError(follow, "unexpected token type in inline table: %s", follow.typ.String())
+ p.raiseError(follow, "unexpected token type in inline table: %s", follow.String())
}
previous = follow
}
@@ -379,5 +425,6 @@ func parseToml(flow []token) *Tree {
}
func init() {
- numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`)
+ numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d])|_$|^_`)
+ hexNumberUnderscoreInvalidRegexp = regexp.MustCompile(`(^0x_)|([^\da-f]_|_[^\da-f])|_$|^_`)
}
diff --git a/vendor/github.com/pelletier/go-toml/test.sh b/vendor/github.com/pelletier/go-toml/test.sh
index 91a8896..ba6adf3 100755
--- a/vendor/github.com/pelletier/go-toml/test.sh
+++ b/vendor/github.com/pelletier/go-toml/test.sh
@@ -1,6 +1,7 @@
#!/bin/bash
# fail out of the script if anything here fails
set -e
+set -o pipefail
# set the path to the present working directory
export GOPATH=`pwd`
@@ -22,9 +23,6 @@ function git_clone() {
# Remove potential previous runs
rm -rf src test_program_bin toml-test
-# Run go vet
-go vet ./...
-
go get github.com/pelletier/go-buffruneio
go get github.com/davecgh/go-spew/spew
go get gopkg.in/yaml.v2
diff --git a/vendor/github.com/pelletier/go-toml/token.go b/vendor/github.com/pelletier/go-toml/token.go
index 5581fe0..1a90813 100644
--- a/vendor/github.com/pelletier/go-toml/token.go
+++ b/vendor/github.com/pelletier/go-toml/token.go
@@ -23,6 +23,8 @@ const (
tokenTrue
tokenFalse
tokenFloat
+ tokenInf
+ tokenNan
tokenEqual
tokenLeftBracket
tokenRightBracket
@@ -55,6 +57,8 @@ var tokenTypeNames = []string{
"True",
"False",
"Float",
+ "Inf",
+ "NaN",
"=",
"[",
"]",
diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go
index c3e3243..98c185a 100644
--- a/vendor/github.com/pelletier/go-toml/toml.go
+++ b/vendor/github.com/pelletier/go-toml/toml.go
@@ -14,6 +14,7 @@ type tomlValue struct {
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
comment string
commented bool
+ multiline bool
position Position
}
@@ -71,18 +72,15 @@ func (t *Tree) Keys() []string {
}
// Get the value at key in the Tree.
-// Key is a dot-separated path (e.g. a.b.c).
+// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
+// If you need to retrieve non-bare keys, use GetPath.
// Returns nil if the path does not exist in the tree.
// If keys is of length zero, the current tree is returned.
func (t *Tree) Get(key string) interface{} {
if key == "" {
return t
}
- comps, err := parseKey(key)
- if err != nil {
- return nil
- }
- return t.GetPath(comps)
+ return t.GetPath(strings.Split(key, "."))
}
// GetPath returns the element in the tree indicated by 'keys'.
@@ -178,17 +176,86 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
return val
}
+// SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
+// The default values within the struct are valid default options.
+type SetOptions struct {
+ Comment string
+ Commented bool
+ Multiline bool
+}
+
+// SetWithOptions is the same as Set, but allows you to provide formatting
+// instructions to the key, that will be used by Marshal().
+func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
+ t.SetPathWithOptions(strings.Split(key, "."), opts, value)
+}
+
+// SetPathWithOptions is the same as SetPath, but allows you to provide
+// formatting instructions to the key, that will be reused by Marshal().
+func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
+ subtree := t
+ for _, intermediateKey := range keys[:len(keys)-1] {
+ nextTree, exists := subtree.values[intermediateKey]
+ if !exists {
+ nextTree = newTree()
+ subtree.values[intermediateKey] = nextTree // add new element here
+ }
+ switch node := nextTree.(type) {
+ case *Tree:
+ subtree = node
+ case []*Tree:
+ // go to most recent element
+ if len(node) == 0 {
+ // create element if it does not exist
+ subtree.values[intermediateKey] = append(node, newTree())
+ }
+ subtree = node[len(node)-1]
+ }
+ }
+
+ var toInsert interface{}
+
+ switch value.(type) {
+ case *Tree:
+ tt := value.(*Tree)
+ tt.comment = opts.Comment
+ toInsert = value
+ case []*Tree:
+ toInsert = value
+ case *tomlValue:
+ tt := value.(*tomlValue)
+ tt.comment = opts.Comment
+ toInsert = tt
+ default:
+ toInsert = &tomlValue{value: value, comment: opts.Comment, commented: opts.Commented, multiline: opts.Multiline}
+ }
+
+ subtree.values[keys[len(keys)-1]] = toInsert
+}
+
// Set an element in the tree.
// Key is a dot-separated path (e.g. a.b.c).
// Creates all necessary intermediate trees, if needed.
-func (t *Tree) Set(key string, comment string, commented bool, value interface{}) {
- t.SetPath(strings.Split(key, "."), comment, commented, value)
+func (t *Tree) Set(key string, value interface{}) {
+ t.SetWithComment(key, "", false, value)
+}
+
+// SetWithComment is the same as Set, but allows you to provide comment
+// information to the key, that will be reused by Marshal().
+func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
+ t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
}
// SetPath sets an element in the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}).
// Creates all necessary intermediate trees, if needed.
-func (t *Tree) SetPath(keys []string, comment string, commented bool, value interface{}) {
+func (t *Tree) SetPath(keys []string, value interface{}) {
+ t.SetPathWithComment(keys, "", false, value)
+}
+
+// SetPathWithComment is the same as SetPath, but allows you to provide comment
+// information to the key, that will be reused by Marshal().
+func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go
index 449f35a..e4049e2 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_write.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go
@@ -12,7 +12,41 @@ import (
"time"
)
-// encodes a string to a TOML-compliant string value
+// Encodes a string to a TOML-compliant multi-line string value
+// This function is a clone of the existing encodeTomlString function, except that whitespace characters
+// are preserved. Quotation marks and backslashes are also not escaped.
+func encodeMultilineTomlString(value string) string {
+ var b bytes.Buffer
+
+ for _, rr := range value {
+ switch rr {
+ case '\b':
+ b.WriteString(`\b`)
+ case '\t':
+ b.WriteString("\t")
+ case '\n':
+ b.WriteString("\n")
+ case '\f':
+ b.WriteString(`\f`)
+ case '\r':
+ b.WriteString("\r")
+ case '"':
+ b.WriteString(`"`)
+ case '\\':
+ b.WriteString(`\`)
+ default:
+ intRr := uint16(rr)
+ if intRr < 0x001F {
+ b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
+ } else {
+ b.WriteRune(rr)
+ }
+ }
+ }
+ return b.String()
+}
+
+// Encodes a string to a TOML-compliant string value
func encodeTomlString(value string) string {
var b bytes.Buffer
@@ -44,7 +78,16 @@ func encodeTomlString(value string) string {
return b.String()
}
-func tomlValueStringRepresentation(v interface{}) (string, error) {
+func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) {
+ // this interface check is added to dereference the change made in the writeTo function.
+ // That change was made to allow this function to see formatting options.
+ tv, ok := v.(*tomlValue)
+ if ok {
+ v = tv.value
+ } else {
+ tv = &tomlValue{}
+ }
+
switch value := v.(type) {
case uint64:
return strconv.FormatUint(value, 10), nil
@@ -54,14 +97,17 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
// Ensure a round float does contain a decimal point. Otherwise feeding
// the output back to the parser would convert to an integer.
if math.Trunc(value) == value {
- return strconv.FormatFloat(value, 'f', 1, 32), nil
+ return strings.ToLower(strconv.FormatFloat(value, 'f', 1, 32)), nil
}
- return strconv.FormatFloat(value, 'f', -1, 32), nil
+ return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil
case string:
+ if tv.multiline {
+ return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil
+ }
return "\"" + encodeTomlString(value) + "\"", nil
case []byte:
b, _ := v.([]byte)
- return tomlValueStringRepresentation(string(b))
+ return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine)
case bool:
if value {
return "true", nil
@@ -76,21 +122,38 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Slice {
- values := []string{}
+ var values []string
for i := 0; i < rv.Len(); i++ {
item := rv.Index(i).Interface()
- itemRepr, err := tomlValueStringRepresentation(item)
+ itemRepr, err := tomlValueStringRepresentation(item, indent, arraysOneElementPerLine)
if err != nil {
return "", err
}
values = append(values, itemRepr)
}
+ if arraysOneElementPerLine && len(values) > 1 {
+ stringBuffer := bytes.Buffer{}
+ valueIndent := indent + ` ` // TODO: move that to a shared encoder state
+
+ stringBuffer.WriteString("[\n")
+
+ for _, value := range values {
+ stringBuffer.WriteString(valueIndent)
+ stringBuffer.WriteString(value)
+ stringBuffer.WriteString(`,`)
+ stringBuffer.WriteString("\n")
+ }
+
+ stringBuffer.WriteString(indent + "]")
+
+ return stringBuffer.String(), nil
+ }
return "[" + strings.Join(values, ",") + "]", nil
}
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
}
-func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) {
+func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
simpleValuesKeys := make([]string, 0)
complexValuesKeys := make([]string, 0)
@@ -113,7 +176,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
- repr, err := tomlValueStringRepresentation(v.value)
+ repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
@@ -178,7 +241,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
if err != nil {
return bytesCount, err
}
- bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount)
+ bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
@@ -190,7 +253,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, err
}
- bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount)
+ bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
@@ -216,7 +279,7 @@ func writeStrings(w io.Writer, s ...string) (int, error) {
// WriteTo encode the Tree as Toml and writes it to the writer w.
// Returns the number of bytes written in case of success, or an error if anything happened.
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
- return t.writeTo(w, "", "", 0)
+ return t.writeTo(w, "", "", 0, false)
}
// ToTomlString generates a human-readable representation of the current tree.