summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/pelletier
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pelletier')
-rw-r--r--vendor/github.com/pelletier/go-toml/.gitignore1
-rw-r--r--vendor/github.com/pelletier/go-toml/.travis.yml5
-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/doc_test.go9
-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.go107
-rw-r--r--vendor/github.com/pelletier/go-toml/keysparsing_test.go16
-rw-r--r--vendor/github.com/pelletier/go-toml/marshal.go230
-rw-r--r--vendor/github.com/pelletier/go-toml/marshal_test.go134
-rw-r--r--vendor/github.com/pelletier/go-toml/parser.go6
-rw-r--r--vendor/github.com/pelletier/go-toml/parser_test.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/query/doc.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/toml.go26
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_create.go6
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_write.go43
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_write_test.go16
18 files changed, 562 insertions, 107 deletions
diff --git a/vendor/github.com/pelletier/go-toml/.gitignore b/vendor/github.com/pelletier/go-toml/.gitignore
index f1b619018..99e38bbc5 100644
--- a/vendor/github.com/pelletier/go-toml/.gitignore
+++ b/vendor/github.com/pelletier/go-toml/.gitignore
@@ -1 +1,2 @@
test_program/test_program_bin
+fuzz/
diff --git a/vendor/github.com/pelletier/go-toml/.travis.yml b/vendor/github.com/pelletier/go-toml/.travis.yml
index 496691166..6e644fdfd 100644
--- a/vendor/github.com/pelletier/go-toml/.travis.yml
+++ b/vendor/github.com/pelletier/go-toml/.travis.yml
@@ -1,9 +1,8 @@
sudo: false
language: go
go:
- - 1.7.6
- - 1.8.3
- - 1.9
+ - 1.8.4
+ - 1.9.1
- tip
matrix:
allow_failures:
diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md
index 2681690d5..0d357acf3 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 3c89619e8..d5fd98c02 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/doc_test.go b/vendor/github.com/pelletier/go-toml/doc_test.go
index a48c04b01..3b8171b22 100644
--- a/vendor/github.com/pelletier/go-toml/doc_test.go
+++ b/vendor/github.com/pelletier/go-toml/doc_test.go
@@ -61,19 +61,24 @@ func ExampleMarshal() {
type Postgres struct {
User string `toml:"user"`
Password string `toml:"password"`
+ Database string `toml:"db" commented:"true" comment:"not used anymore"`
}
type Config struct {
- Postgres Postgres `toml:"postgres"`
+ Postgres Postgres `toml:"postgres" comment:"Postgres configuration"`
}
- config := Config{Postgres{User: "pelletier", Password: "mypassword"}}
+ config := Config{Postgres{User: "pelletier", Password: "mypassword", Database: "old_database"}}
b, err := toml.Marshal(config)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
// Output:
+ // # Postgres configuration
// [postgres]
+ //
+ // # not used anymore
+ // # db = "old_database"
// password = "mypassword"
// user = "pelletier"
}
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 000000000..14570c8d3
--- /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 000000000..3204b4c44
--- /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 d62ca5fd1..9707c6884 100644
--- a/vendor/github.com/pelletier/go-toml/keysparsing.go
+++ b/vendor/github.com/pelletier/go-toml/keysparsing.go
@@ -6,15 +6,37 @@ import (
"bytes"
"errors"
"fmt"
+ "strconv"
"unicode"
)
+var escapeSequenceMap = map[rune]rune{
+ 'b': '\b',
+ 't': '\t',
+ 'n': '\n',
+ 'f': '\f',
+ 'r': '\r',
+ '"': '"',
+ '\\': '\\',
+}
+
+type parseKeyState int
+
+const (
+ BARE parseKeyState = iota
+ BASIC
+ LITERAL
+ ESC
+ UNICODE_4
+ UNICODE_8
+)
+
func parseKey(key string) ([]string, error) {
groups := []string{}
var buffer bytes.Buffer
- inQuotes := false
+ var hex bytes.Buffer
+ state := BARE
wasInQuotes := false
- escapeNext := false
ignoreSpace := true
expectDot := false
@@ -25,25 +47,67 @@ func parseKey(key string) ([]string, error) {
}
ignoreSpace = false
}
- if escapeNext {
- buffer.WriteRune(char)
- escapeNext = false
+
+ if state == ESC {
+ if char == 'u' {
+ state = UNICODE_4
+ hex.Reset()
+ } else if char == 'U' {
+ state = UNICODE_8
+ hex.Reset()
+ } else if newChar, ok := escapeSequenceMap[char]; ok {
+ buffer.WriteRune(newChar)
+ state = BASIC
+ } else {
+ return nil, fmt.Errorf(`invalid escape sequence \%c`, char)
+ }
+ continue
+ }
+
+ if state == UNICODE_4 || state == UNICODE_8 {
+ if isHexDigit(char) {
+ hex.WriteRune(char)
+ }
+ if (state == UNICODE_4 && hex.Len() == 4) || (state == UNICODE_8 && hex.Len() == 8) {
+ if value, err := strconv.ParseInt(hex.String(), 16, 32); err == nil {
+ buffer.WriteRune(rune(value))
+ } else {
+ return nil, err
+ }
+ state = BASIC
+ }
continue
}
+
switch char {
case '\\':
- escapeNext = true
- continue
+ if state == BASIC {
+ state = ESC
+ } else if state == LITERAL {
+ buffer.WriteRune(char)
+ }
+ case '\'':
+ if state == BARE {
+ state = LITERAL
+ } else if state == LITERAL {
+ groups = append(groups, buffer.String())
+ buffer.Reset()
+ wasInQuotes = true
+ state = BARE
+ }
+ expectDot = false
case '"':
- if inQuotes {
+ if state == BARE {
+ state = BASIC
+ } else if state == BASIC {
groups = append(groups, buffer.String())
buffer.Reset()
+ state = BARE
wasInQuotes = true
}
- inQuotes = !inQuotes
expectDot = false
case '.':
- if inQuotes {
+ if state != BARE {
buffer.WriteRune(char)
} else {
if !wasInQuotes {
@@ -58,28 +122,31 @@ func parseKey(key string) ([]string, error) {
wasInQuotes = false
}
case ' ':
- if inQuotes {
+ if state == BASIC {
buffer.WriteRune(char)
} else {
expectDot = true
}
default:
- if !inQuotes && !isValidBareChar(char) {
- return nil, fmt.Errorf("invalid bare character: %c", char)
- }
- if !inQuotes && expectDot {
- return nil, errors.New("what?")
+ if state == BARE {
+ if !isValidBareChar(char) {
+ return nil, fmt.Errorf("invalid bare character: %c", char)
+ } else if expectDot {
+ return nil, errors.New("what?")
+ }
}
buffer.WriteRune(char)
expectDot = false
}
}
- if inQuotes {
- return nil, errors.New("mismatched quotes")
- }
- if escapeNext {
+
+ // state must be BARE at the end
+ if state == ESC {
return nil, errors.New("unfinished escape sequence")
+ } else if state != BARE {
+ return nil, errors.New("mismatched quotes")
}
+
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing_test.go b/vendor/github.com/pelletier/go-toml/keysparsing_test.go
index 1a9ecccaa..7aa4cd64a 100644
--- a/vendor/github.com/pelletier/go-toml/keysparsing_test.go
+++ b/vendor/github.com/pelletier/go-toml/keysparsing_test.go
@@ -22,7 +22,10 @@ func testResult(t *testing.T, key string, expected []string) {
}
func testError(t *testing.T, key string, expectedError string) {
- _, err := parseKey(key)
+ res, err := parseKey(key)
+ if err == nil {
+ t.Fatalf("Expected error, but succesfully parsed key %s", res)
+ }
if fmt.Sprintf("%s", err) != expectedError {
t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
}
@@ -47,6 +50,17 @@ func TestBaseKeyPound(t *testing.T) {
func TestQuotedKeys(t *testing.T) {
testResult(t, `hello."foo".bar`, []string{"hello", "foo", "bar"})
testResult(t, `"hello!"`, []string{"hello!"})
+ testResult(t, `"hello\tworld"`, []string{"hello\tworld"})
+ testResult(t, `"\U0001F914"`, []string{"\U0001F914"})
+ testResult(t, `"\u2764"`, []string{"\u2764"})
+
+ testResult(t, `hello.'foo'.bar`, []string{"hello", "foo", "bar"})
+ testResult(t, `'hello!'`, []string{"hello!"})
+ testResult(t, `'hello\tworld'`, []string{`hello\tworld`})
+
+ testError(t, `"\w"`, `invalid escape sequence \w`)
+ testError(t, `"\`, `unfinished escape sequence`)
+ testError(t, `"\t`, `mismatched quotes`)
}
func TestEmptyKey(t *testing.T) {
diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go
index 1a3176f97..1bbdfa1d8 100644
--- a/vendor/github.com/pelletier/go-toml/marshal.go
+++ b/vendor/github.com/pelletier/go-toml/marshal.go
@@ -4,17 +4,29 @@ import (
"bytes"
"errors"
"fmt"
+ "io"
"reflect"
+ "strconv"
"strings"
"time"
)
type tomlOpts struct {
name string
+ comment string
+ commented bool
include bool
omitempty bool
}
+type encOpts struct {
+ quoteMapKeys bool
+}
+
+var encOptsDefaults = encOpts{
+ quoteMapKeys: false,
+}
+
var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
@@ -94,8 +106,15 @@ encoder, except that there is no concept of a Marshaler interface or MarshalTOML
function for sub-structs, and currently only definite types can be marshaled
(i.e. no `interface{}`).
+The following struct annotations are supported:
+
+ toml:"Field" Overrides the field's name to output.
+ omitempty When set, empty values and groups are not emitted.
+ comment:"comment" Emits a # comment on the same line. This supports new lines.
+ 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:
@@ -115,6 +134,47 @@ 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
+}
+
+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")
@@ -123,7 +183,7 @@ 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
}
@@ -132,9 +192,9 @@ func Marshal(v interface{}) ([]byte, error) {
}
// 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() {
@@ -143,31 +203,39 @@ 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, val)
+ tval.Set(opts.name, opts.comment, opts.commented, 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(), val)
+ if e.quoteMapKeys {
+ keyStr, err := tomlValueStringRepresentation(key.String())
+ if err != nil {
+ return nil, err
+ }
+ tval.SetPath([]string{keyStr}, "", false, val)
+ } else {
+ tval.Set(key.String(), "", false, 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
}
@@ -177,10 +245,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
}
@@ -190,19 +258,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:
@@ -227,17 +295,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
@@ -246,6 +313,10 @@ func (t *Tree) Unmarshal(v interface{}) error {
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
// `interface{}`).
//
+// The following struct annotations are supported:
+//
+// toml:"Field" Overrides the field's name to map to.
+//
// See Marshal() documentation for types mapping table.
func Unmarshal(data []byte, v interface{}) error {
t, err := LoadReader(bytes.NewReader(data))
@@ -255,10 +326,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() {
@@ -276,7 +389,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))
}
@@ -288,8 +401,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))
}
@@ -300,10 +414,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
}
@@ -313,10 +427,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
}
@@ -326,17 +440,30 @@ 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))
+ } else {
+ 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))
+ } else {
+ 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{}))
+ } else {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
+ }
default:
switch mtype.Kind() {
case reflect.Bool:
@@ -430,13 +557,13 @@ func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error)
}
return reflect.ValueOf(val), 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
}
@@ -448,7 +575,12 @@ func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error)
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",")
- result := tomlOpts{vf.Name, true, false}
+ var comment string
+ if c := vf.Tag.Get("comment"); c != "" {
+ comment = c
+ }
+ commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
+ result := tomlOpts{name: vf.Name, comment: comment, commented: commented, 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/marshal_test.go b/vendor/github.com/pelletier/go-toml/marshal_test.go
index dbfc7c1d1..e7d1d6e4d 100644
--- a/vendor/github.com/pelletier/go-toml/marshal_test.go
+++ b/vendor/github.com/pelletier/go-toml/marshal_test.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -508,6 +509,14 @@ func TestPointerUnmarshal(t *testing.T) {
}
}
+func TestUnmarshalTypeMismatch(t *testing.T) {
+ result := pointerMarshalTestStruct{}
+ err := Unmarshal([]byte("List = 123"), &result)
+ if !strings.HasPrefix(err.Error(), "(1, 1): Can't convert 123(int64) to []string(slice)") {
+ t.Errorf("Type mismatch must be reported: got %v", err.Error())
+ }
+}
+
type nestedMarshalTestStruct struct {
String [][]string
//Struct [][]basicMarshalTestSubStruct
@@ -598,3 +607,128 @@ func TestNestedCustomMarshaler(t *testing.T) {
t.Errorf("Bad nested custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
+
+var commentTestToml = []byte(`
+# it's a comment on type
+[postgres]
+ # isCommented = "dvalue"
+ noComment = "cvalue"
+
+ # A comment on AttrB with a
+ # break line
+ password = "bvalue"
+
+ # A comment on AttrA
+ user = "avalue"
+
+ [[postgres.My]]
+
+ # a comment on my on typeC
+ My = "Foo"
+
+ [[postgres.My]]
+
+ # a comment on my on typeC
+ My = "Baar"
+`)
+
+func TestMarshalComment(t *testing.T) {
+ type TypeC struct {
+ My string `comment:"a comment on my on typeC"`
+ }
+ type TypeB struct {
+ AttrA string `toml:"user" comment:"A comment on AttrA"`
+ AttrB string `toml:"password" comment:"A comment on AttrB with a\n break line"`
+ AttrC string `toml:"noComment"`
+ AttrD string `toml:"isCommented" commented:"true"`
+ My []TypeC
+ }
+ type TypeA struct {
+ TypeB TypeB `toml:"postgres" comment:"it's a comment on type"`
+ }
+
+ ta := []TypeC{{My: "Foo"}, {My: "Baar"}}
+ config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", AttrD: "dvalue", My: ta}}
+ result, err := Marshal(config)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := commentTestToml
+ if !bytes.Equal(result, expected) {
+ t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
+ }
+}
+
+type mapsTestStruct struct {
+ Simple map[string]string
+ Paths map[string]string
+ Other map[string]float64
+ X struct {
+ Y struct {
+ Z map[string]bool
+ }
+ }
+}
+
+var mapsTestData = mapsTestStruct{
+ Simple: map[string]string{
+ "one plus one": "two",
+ "next": "three",
+ },
+ Paths: map[string]string{
+ "/this/is/a/path": "/this/is/also/a/path",
+ "/heloo.txt": "/tmp/lololo.txt",
+ },
+ Other: map[string]float64{
+ "testing": 3.9999,
+ },
+ X: struct{ Y struct{ Z map[string]bool } }{
+ Y: struct{ Z map[string]bool }{
+ Z: map[string]bool{
+ "is.Nested": true,
+ },
+ },
+ },
+}
+var mapsTestToml = []byte(`
+[Other]
+ "testing" = 3.9999
+
+[Paths]
+ "/heloo.txt" = "/tmp/lololo.txt"
+ "/this/is/a/path" = "/this/is/also/a/path"
+
+[Simple]
+ "next" = "three"
+ "one plus one" = "two"
+
+[X]
+
+ [X.Y]
+
+ [X.Y.Z]
+ "is.Nested" = true
+`)
+
+func TestEncodeQuotedMapKeys(t *testing.T) {
+ var buf bytes.Buffer
+ if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil {
+ t.Fatal(err)
+ }
+ result := buf.Bytes()
+ expected := mapsTestToml
+ if !bytes.Equal(result, expected) {
+ t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
+ }
+}
+func TestDecodeQuotedMapKeys(t *testing.T) {
+ result := mapsTestStruct{}
+ err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result)
+ expected := mapsTestData
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(result, expected) {
+ t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result)
+ }
+}
diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go
index 8ee49cb56..d492a1e6f 100644
--- a/vendor/github.com/pelletier/go-toml/parser.go
+++ b/vendor/github.com/pelletier/go-toml/parser.go
@@ -110,7 +110,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
newTree := newTree()
newTree.position = startToken.Position
array = append(array, newTree)
- p.tree.SetPath(p.currentTable, array)
+ p.tree.SetPath(p.currentTable, "", false, array)
// remove all keys that were children of this table array
prefix := key.val + "."
@@ -205,7 +205,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
case *Tree, []*Tree:
toInsert = value
default:
- toInsert = &tomlValue{value, key.Position}
+ toInsert = &tomlValue{value: value, position: key.Position}
}
targetNode.values[keyVal] = toInsert
return p.parseStart
@@ -299,7 +299,7 @@ Loop:
key := p.getToken()
p.assume(tokenEqual)
value := p.parseRvalue()
- tree.Set(key.val, value)
+ tree.Set(key.val, "", false, value)
case tokenComma:
if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma")
diff --git a/vendor/github.com/pelletier/go-toml/parser_test.go b/vendor/github.com/pelletier/go-toml/parser_test.go
index 508cb65f0..029bc52c3 100644
--- a/vendor/github.com/pelletier/go-toml/parser_test.go
+++ b/vendor/github.com/pelletier/go-toml/parser_test.go
@@ -46,7 +46,7 @@ func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{})
func TestCreateSubTree(t *testing.T) {
tree := newTree()
tree.createSubTree([]string{"a", "b", "c"}, Position{})
- tree.Set("a.b.c", 42)
+ tree.Set("a.b.c", "", false, 42)
if tree.Get("a.b.c") != 42 {
t.Fail()
}
diff --git a/vendor/github.com/pelletier/go-toml/query/doc.go b/vendor/github.com/pelletier/go-toml/query/doc.go
index f999fc965..ed63c1109 100644
--- a/vendor/github.com/pelletier/go-toml/query/doc.go
+++ b/vendor/github.com/pelletier/go-toml/query/doc.go
@@ -139,7 +139,7 @@
// Compiled Queries
//
// Queries may be executed directly on a Tree object, or compiled ahead
-// of time and executed discretely. The former is more convienent, but has the
+// of time and executed discretely. The former is more convenient, but has the
// penalty of having to recompile the query expression each time.
//
// // basic query
diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go
index 64f19ed30..c3e324374 100644
--- a/vendor/github.com/pelletier/go-toml/toml.go
+++ b/vendor/github.com/pelletier/go-toml/toml.go
@@ -11,14 +11,18 @@ import (
)
type tomlValue struct {
- value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
- position Position
+ value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
+ comment string
+ commented bool
+ position Position
}
// Tree is the result of the parsing of a TOML file.
type Tree struct {
- values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
- position Position
+ values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
+ comment string
+ commented bool
+ position Position
}
func newTree() *Tree {
@@ -177,14 +181,14 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
// 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, value interface{}) {
- t.SetPath(strings.Split(key, "."), value)
+func (t *Tree) Set(key string, comment string, commented bool, value interface{}) {
+ t.SetPath(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, value interface{}) {
+func (t *Tree) SetPath(keys []string, comment string, commented bool, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
@@ -209,13 +213,17 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
switch value.(type) {
case *Tree:
+ tt := value.(*Tree)
+ tt.comment = comment
toInsert = value
case []*Tree:
toInsert = value
case *tomlValue:
- toInsert = value
+ tt := value.(*tomlValue)
+ tt.comment = comment
+ toInsert = tt
default:
- toInsert = &tomlValue{value: value}
+ toInsert = &tomlValue{value: value, comment: comment, commented: commented}
}
subtree.values[keys[len(keys)-1]] = toInsert
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go
index 19d1c0dc6..79610e9b3 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_create.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_create.go
@@ -104,7 +104,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
}
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
}
- return &tomlValue{arrayValue.Interface(), Position{}}, nil
+ return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
}
func toTree(object interface{}) (interface{}, error) {
@@ -127,7 +127,7 @@ func toTree(object interface{}) (interface{}, error) {
}
values[key.String()] = newValue
}
- return &Tree{values, Position{}}, nil
+ return &Tree{values: values, position: Position{}}, nil
}
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
@@ -138,5 +138,5 @@ func toTree(object interface{}) (interface{}, error) {
if err != nil {
return nil, err
}
- return &tomlValue{simpleValue, Position{}}, nil
+ return &tomlValue{value: simpleValue, position: Position{}}, nil
}
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go
index ca763ed58..449f35a44 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_write.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go
@@ -118,7 +118,24 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, err
}
- writtenBytesCount, err := writeStrings(w, indent, k, " = ", repr, "\n")
+ if v.comment != "" {
+ comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
+ start := "# "
+ if strings.HasPrefix(comment, "#") {
+ start = ""
+ }
+ writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
+ bytesCount += int64(writtenBytesCountComment)
+ if errc != nil {
+ return bytesCount, errc
+ }
+ }
+
+ var commented string
+ if v.commented {
+ commented = "# "
+ }
+ writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
@@ -132,11 +149,31 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
+ var commented string
+ if t.commented {
+ commented = "# "
+ }
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *Tree:
- writtenBytesCount, err := writeStrings(w, "\n", indent, "[", combinedKey, "]\n")
+ tv, ok := t.values[k].(*Tree)
+ if !ok {
+ return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
+ }
+ if tv.comment != "" {
+ comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
+ start := "# "
+ if strings.HasPrefix(comment, "#") {
+ start = ""
+ }
+ writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
+ bytesCount += int64(writtenBytesCountComment)
+ if errc != nil {
+ return bytesCount, errc
+ }
+ }
+ writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
@@ -147,7 +184,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
}
case []*Tree:
for _, subTree := range node {
- writtenBytesCount, err := writeStrings(w, "\n", indent, "[[", combinedKey, "]]\n")
+ writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
index c2a1ce3b7..5ea59bc1a 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
@@ -30,7 +30,7 @@ func (f *failingWriter) Write(p []byte) (n int, err error) {
f.buffer.Write(p[:toWrite])
f.written = f.failAt
- return toWrite, fmt.Errorf("failingWriter failed after writting %d bytes", f.written)
+ return toWrite, fmt.Errorf("failingWriter failed after writing %d bytes", f.written)
}
func assertErrorString(t *testing.T, expected string, err error) {
@@ -161,13 +161,13 @@ func TestTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
}
func TestTreeWriteToInvalidTreeTomlValue(t *testing.T) {
- tree := Tree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}}
+ tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
- tree := Tree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}}
+ tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
@@ -176,7 +176,7 @@ func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
toml, _ := Load(`a = 2`)
writer := failingWriter{failAt: 0, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 0 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 0 bytes", err)
}
func TestTreeWriteToFailingWriterInTable(t *testing.T) {
@@ -185,11 +185,11 @@ func TestTreeWriteToFailingWriterInTable(t *testing.T) {
a = 2`)
writer := failingWriter{failAt: 2, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
writer = failingWriter{failAt: 13, written: 0}
_, err = toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 13 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 13 bytes", err)
}
func TestTreeWriteToFailingWriterInArray(t *testing.T) {
@@ -198,11 +198,11 @@ func TestTreeWriteToFailingWriterInArray(t *testing.T) {
a = 2`)
writer := failingWriter{failAt: 2, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
writer = failingWriter{failAt: 15, written: 0}
_, err = toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 15 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 15 bytes", err)
}
func TestTreeWriteToMapExampleFile(t *testing.T) {