From 30802e07b2d84fbc213b490d3402707dffe60096 Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Mon, 10 Apr 2017 21:18:42 +0100 Subject: update dependencies --- vendor/github.com/pelletier/go-toml/lexer.go | 8 +- vendor/github.com/pelletier/go-toml/marshal.go | 479 +++++++++++++++++++++ .../github.com/pelletier/go-toml/marshal_test.toml | 38 ++ vendor/github.com/pelletier/go-toml/test.sh | 7 +- vendor/github.com/pelletier/go-toml/token.go | 3 +- vendor/github.com/pelletier/go-toml/toml.go | 12 +- .../pelletier/go-toml/tomltree_conversions.go | 227 ---------- .../pelletier/go-toml/tomltree_create.go | 135 ++++++ .../github.com/pelletier/go-toml/tomltree_write.go | 217 ++++++++++ 9 files changed, 887 insertions(+), 239 deletions(-) create mode 100644 vendor/github.com/pelletier/go-toml/marshal.go create mode 100644 vendor/github.com/pelletier/go-toml/marshal_test.toml delete mode 100644 vendor/github.com/pelletier/go-toml/tomltree_conversions.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_create.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_write.go (limited to 'vendor/github.com/pelletier/go-toml') diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go index 4ba134c..104f3b1 100644 --- a/vendor/github.com/pelletier/go-toml/lexer.go +++ b/vendor/github.com/pelletier/go-toml/lexer.go @@ -36,7 +36,7 @@ type tomlLexer struct { // Basic read operations on input func (l *tomlLexer) read() rune { - r, err := l.input.ReadRune() + r, _, err := l.input.ReadRune() if err != nil { panic(err) } @@ -89,7 +89,7 @@ func (l *tomlLexer) emit(t tokenType) { } func (l *tomlLexer) peek() rune { - r, err := l.input.ReadRune() + r, _, err := l.input.ReadRune() if err != nil { panic(err) } @@ -99,7 +99,7 @@ func (l *tomlLexer) peek() rune { func (l *tomlLexer) follow(next string) bool { for _, expectedRune := range next { - r, err := l.input.ReadRune() + r, _, err := l.input.ReadRune() defer l.input.UnreadRune() if err != nil { panic(err) @@ -219,7 +219,7 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn { break } - possibleDate := string(l.input.Peek(35)) + possibleDate := string(l.input.PeekRunes(35)) dateMatch := dateRegexp.FindString(possibleDate) if dateMatch != "" { l.fastForward(len(dateMatch)) diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go new file mode 100644 index 0000000..a1d7010 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/marshal.go @@ -0,0 +1,479 @@ +package toml + +import ( + "errors" + "fmt" + "reflect" + "strings" + "time" +) + +/* +TomlTree structural types and corresponding marshal types +------------------------------------------------------------------------------- +*TomlTree (*)struct, (*)map[string]interface{} +[]*TomlTree (*)[](*)struct, (*)[](*)map[string]interface{} +[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{}) +interface{} (*)primitive + +TomlTree primitive types and corresponding marshal types +----------------------------------------------------------- +uint64 uint, uint8-uint64, pointers to same +int64 int, int8-uint64, pointers to same +float64 float32, float64, pointers to same +string string, pointers to same +bool bool, pointers to same +time.Time time.Time{}, pointers to same +*/ + +type tomlOpts struct { + name string + include bool + omitempty bool +} + +var timeType = reflect.TypeOf(time.Time{}) +var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() + +// Check if the given marshall type maps to a TomlTree primitive +func isPrimitive(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Ptr: + return isPrimitive(mtype.Elem()) + case reflect.Bool: + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Struct: + return mtype == timeType || isCustomMarshaler(mtype) + default: + return false + } +} + +// Check if the given marshall type maps to a TomlTree slice +func isTreeSlice(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Slice: + return !isOtherSlice(mtype) + default: + return false + } +} + +// Check if the given marshall type maps to a non-TomlTree slice +func isOtherSlice(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Ptr: + return isOtherSlice(mtype.Elem()) + case reflect.Slice: + return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem()) + default: + return false + } +} + +// Check if the given marshall type maps to a TomlTree +func isTree(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Map: + return true + case reflect.Struct: + return !isPrimitive(mtype) + default: + return false + } +} + +func isCustomMarshaler(mtype reflect.Type) bool { + return mtype.Implements(marshalerType) +} + +func callCustomMarshaler(mval reflect.Value) ([]byte, error) { + return mval.Interface().(Marshaler).MarshalTOML() +} + +// Marshaler is the interface implemented by types that +// can marshal themselves into valid TOML. +type Marshaler interface { + MarshalTOML() ([]byte, error) +} + +/* +Marshal returns the TOML encoding of v. Behavior is similar to the Go json +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{}`). + +Note that pointers are automatically assigned the "omitempty" option, as TOML +explicity does not handle null values (saying instead the label should be +dropped). +*/ +func 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") + } + sval := reflect.ValueOf(v) + if isCustomMarshaler(mtype) { + return callCustomMarshaler(sval) + } + t, err := valueToTree(mtype, sval) + if err != nil { + return []byte{}, err + } + s, err := t.ToTomlString() + return []byte(s), err +} + +// Convert given marshal struct or map value to toml tree +func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) { + if mtype.Kind() == reflect.Ptr { + return valueToTree(mtype.Elem(), mval.Elem()) + } + tval := newTomlTree() + switch mtype.Kind() { + case reflect.Struct: + for i := 0; i < mtype.NumField(); i++ { + mtypef, mvalf := mtype.Field(i), mval.Field(i) + opts := tomlOptions(mtypef) + if opts.include && (!opts.omitempty || !isZero(mvalf)) { + val, err := valueToToml(mtypef.Type, mvalf) + if err != nil { + return nil, err + } + tval.Set(opts.name, val) + } + } + case reflect.Map: + for _, key := range mval.MapKeys() { + mvalf := mval.MapIndex(key) + val, err := valueToToml(mtype.Elem(), mvalf) + if err != nil { + return nil, err + } + 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) ([]*TomlTree, error) { + tval := make([]*TomlTree, mval.Len(), mval.Len()) + for i := 0; i < mval.Len(); i++ { + val, err := valueToTree(mtype.Elem(), mval.Index(i)) + if err != nil { + return nil, err + } + tval[i] = val + } + return tval, nil +} + +// Convert given marshal slice to slice of toml values +func 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)) + if err != nil { + return nil, err + } + tval[i] = val + } + return tval, nil +} + +// Convert given marshal value to toml value +func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { + if mtype.Kind() == reflect.Ptr { + return valueToToml(mtype.Elem(), mval.Elem()) + } + switch { + case isCustomMarshaler(mtype): + return callCustomMarshaler(mval) + case isTree(mtype): + return valueToTree(mtype, mval) + case isTreeSlice(mtype): + return valueToTreeSlice(mtype, mval) + case isOtherSlice(mtype): + return valueToOtherSlice(mtype, mval) + default: + switch mtype.Kind() { + case reflect.Bool: + return mval.Bool(), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return mval.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return mval.Uint(), nil + case reflect.Float32, reflect.Float64: + return mval.Float(), nil + case reflect.String: + return mval.String(), nil + case reflect.Struct: + return mval.Interface().(time.Time), nil + default: + return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) + } + } +} + +/* +Unmarshal parses the TOML-encoded data and stores the result in the value +pointed to by v. Behavior is similar to the Go json encoder, except that there +is no concept of an Unmarshaler interface or UnmarshalTOML function for +sub-structs, and currently only definite types can be unmarshaled to (i.e. no +`interface{}`). +*/ +func Unmarshal(data []byte, 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") + } + + t, err := Load(string(data)) + if err != nil { + return err + } + + sval, err := valueFromTree(mtype.Elem(), t) + 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 *TomlTree) (reflect.Value, error) { + if mtype.Kind() == reflect.Ptr { + return unwrapPointer(mtype, tval) + } + var mval reflect.Value + switch mtype.Kind() { + case reflect.Struct: + mval = reflect.New(mtype).Elem() + for i := 0; i < mtype.NumField(); i++ { + mtypef := mtype.Field(i) + opts := tomlOptions(mtypef) + if opts.include { + key := opts.name + exists := tval.Has(key) + if exists { + val := tval.Get(key) + mvalf, err := valueFromToml(mtypef.Type, val) + if err != nil { + return mval, formatError(err, tval.GetPosition(key)) + } + mval.Field(i).Set(mvalf) + } + } + } + case reflect.Map: + mval = reflect.MakeMap(mtype) + for _, key := range tval.Keys() { + val := tval.Get(key) + mvalf, err := valueFromToml(mtype.Elem(), val) + if err != nil { + return mval, formatError(err, tval.GetPosition(key)) + } + mval.SetMapIndex(reflect.ValueOf(key), mvalf) + } + } + return mval, nil +} + +// Convert toml value to marshal struct/map slice, using marshal type +func valueFromTreeSlice(mtype reflect.Type, tval []*TomlTree) (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]) + if err != nil { + return mval, err + } + mval.Index(i).Set(val) + } + return mval, nil +} + +// Convert toml value to marshal primitive slice, using marshal type +func 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]) + if err != nil { + return mval, err + } + mval.Index(i).Set(val) + } + return mval, nil +} + +// Convert toml value to marshal value, using marshal type +func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) { + if mtype.Kind() == reflect.Ptr { + return unwrapPointer(mtype, tval) + } + switch { + case isTree(mtype): + return valueFromTree(mtype, tval.(*TomlTree)) + case isTreeSlice(mtype): + return valueFromTreeSlice(mtype, tval.([]*TomlTree)) + case isOtherSlice(mtype): + return valueFromOtherSlice(mtype, tval.([]interface{})) + 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) + } + 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 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 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) + } + 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 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) + } + 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) + } + 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 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) + } + return reflect.ValueOf(val), nil + default: + return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind()) + } + } +} + +func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) { + val, err := valueFromToml(mtype.Elem(), tval) + if err != nil { + return reflect.ValueOf(nil), err + } + mval := reflect.New(mtype.Elem()) + mval.Elem().Set(val) + return mval, nil +} + +func tomlOptions(vf reflect.StructField) tomlOpts { + tag := vf.Tag.Get("toml") + parse := strings.Split(tag, ",") + result := tomlOpts{vf.Name, true, false} + if parse[0] != "" { + if parse[0] == "-" && len(parse) == 1 { + result.include = false + } else { + result.name = strings.Trim(parse[0], " ") + } + } + if vf.PkgPath != "" { + result.include = false + } + if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" { + result.omitempty = true + } + if vf.Type.Kind() == reflect.Ptr { + result.omitempty = true + } + return result +} + +func isZero(val reflect.Value) bool { + switch val.Type().Kind() { + case reflect.Map: + fallthrough + case reflect.Array: + fallthrough + case reflect.Slice: + return val.Len() == 0 + default: + return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) + } +} + +func formatError(err error, pos Position) error { + if err.Error()[0] == '(' { // Error already contains position information + return err + } + return fmt.Errorf("%s: %s", pos, err) +} diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.toml b/vendor/github.com/pelletier/go-toml/marshal_test.toml new file mode 100644 index 0000000..1c5f98e --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/marshal_test.toml @@ -0,0 +1,38 @@ +title = "TOML Marshal Testing" + +[basic] + bool = true + date = 1979-05-27T07:32:00Z + float = 123.4 + int = 5000 + string = "Bite me" + uint = 5001 + +[basic_lists] + bools = [true,false,true] + dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] + floats = [12.3,45.6,78.9] + ints = [8001,8001,8002] + strings = ["One","Two","Three"] + uints = [5002,5003] + +[basic_map] + one = "one" + two = "two" + +[subdoc] + + [subdoc.first] + name = "First" + + [subdoc.second] + name = "Second" + +[[subdoclist]] + name = "List.First" + +[[subdoclist]] + name = "List.Second" + +[[subdocptrs]] + name = "Second" diff --git a/vendor/github.com/pelletier/go-toml/test.sh b/vendor/github.com/pelletier/go-toml/test.sh index 15ac1e1..436d2fb 100755 --- a/vendor/github.com/pelletier/go-toml/test.sh +++ b/vendor/github.com/pelletier/go-toml/test.sh @@ -19,6 +19,9 @@ function git_clone() { popd } +# Run go vet +go vet ./... + go get github.com/pelletier/go-buffruneio go get github.com/davecgh/go-spew/spew @@ -38,8 +41,8 @@ cp -R cmd/* src/github.com/pelletier/go-toml/cmd go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go # Run basic unit tests -go test github.com/pelletier/go-toml \ - github.com/pelletier/go-toml/cmd/tomljson +go test github.com/pelletier/go-toml -v -covermode=count -coverprofile=coverage.out +go test github.com/pelletier/go-toml/cmd/tomljson # run the entire BurntSushi test suite if [[ $# -eq 0 ]] ; then diff --git a/vendor/github.com/pelletier/go-toml/token.go b/vendor/github.com/pelletier/go-toml/token.go index e598cf9..5581fe0 100644 --- a/vendor/github.com/pelletier/go-toml/token.go +++ b/vendor/github.com/pelletier/go-toml/token.go @@ -135,5 +135,6 @@ func isDigit(r rune) bool { func isHexDigit(r rune) bool { return isDigit(r) || - r == 'A' || r == 'B' || r == 'C' || r == 'D' || r == 'E' || r == 'F' + (r >= 'a' && r <= 'f') || + (r >= 'A' && r <= 'F') } diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go index ad23fe8..1ba56a1 100644 --- a/vendor/github.com/pelletier/go-toml/toml.go +++ b/vendor/github.com/pelletier/go-toml/toml.go @@ -10,13 +10,13 @@ import ( ) type tomlValue struct { - value interface{} + value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list position Position } // TomlTree is the result of the parsing of a TOML file. type TomlTree struct { - values map[string]interface{} + values map[string]interface{} // string -> *tomlValue, *TomlTree, []*TomlTree position Position } @@ -28,10 +28,12 @@ func newTomlTree() *TomlTree { } // TreeFromMap initializes a new TomlTree object using the given map. -func TreeFromMap(m map[string]interface{}) *TomlTree { - return &TomlTree{ - values: m, +func TreeFromMap(m map[string]interface{}) (*TomlTree, error) { + result, err := toTree(m) + if err != nil { + return nil, err } + return result.(*TomlTree), nil } // Has returns a boolean indicating if the given key exists. diff --git a/vendor/github.com/pelletier/go-toml/tomltree_conversions.go b/vendor/github.com/pelletier/go-toml/tomltree_conversions.go deleted file mode 100644 index fc8f22b..0000000 --- a/vendor/github.com/pelletier/go-toml/tomltree_conversions.go +++ /dev/null @@ -1,227 +0,0 @@ -package toml - -// Tools to convert a TomlTree to different representations - -import ( - "fmt" - "strconv" - "strings" - "time" -) - -// encodes a string to a TOML-compliant string value -func encodeTomlString(value string) string { - result := "" - for _, rr := range value { - intRr := uint16(rr) - switch rr { - case '\b': - result += "\\b" - case '\t': - result += "\\t" - case '\n': - result += "\\n" - case '\f': - result += "\\f" - case '\r': - result += "\\r" - case '"': - result += "\\\"" - case '\\': - result += "\\\\" - default: - if intRr < 0x001F { - result += fmt.Sprintf("\\u%0.4X", intRr) - } else { - result += string(rr) - } - } - } - return result -} - -// Value print support function for ToString() -// Outputs the TOML compliant string representation of a value -func toTomlValue(item interface{}, indent int) string { - tab := strings.Repeat(" ", indent) - switch value := item.(type) { - case int: - return tab + strconv.FormatInt(int64(value), 10) - case int8: - return tab + strconv.FormatInt(int64(value), 10) - case int16: - return tab + strconv.FormatInt(int64(value), 10) - case int32: - return tab + strconv.FormatInt(int64(value), 10) - case int64: - return tab + strconv.FormatInt(value, 10) - case uint: - return tab + strconv.FormatUint(uint64(value), 10) - case uint8: - return tab + strconv.FormatUint(uint64(value), 10) - case uint16: - return tab + strconv.FormatUint(uint64(value), 10) - case uint32: - return tab + strconv.FormatUint(uint64(value), 10) - case uint64: - return tab + strconv.FormatUint(value, 10) - case float32: - return tab + strconv.FormatFloat(float64(value), 'f', -1, 32) - case float64: - return tab + strconv.FormatFloat(value, 'f', -1, 64) - case string: - return tab + "\"" + encodeTomlString(value) + "\"" - case bool: - if value { - return "true" - } - return "false" - case time.Time: - return tab + value.Format(time.RFC3339) - case []interface{}: - values := []string{} - for _, item := range value { - values = append(values, toTomlValue(item, 0)) - } - return "[" + strings.Join(values, ",") + "]" - case nil: - return "" - default: - panic(fmt.Errorf("unsupported value type %T: %v", value, value)) - } -} - -// Recursive support function for ToString() -// Outputs a tree, using the provided keyspace to prefix table names -func (t *TomlTree) toToml(indent, keyspace string) string { - resultChunks := []string{} - for k, v := range t.values { - // figure out the keyspace - combinedKey := k - if keyspace != "" { - combinedKey = keyspace + "." + combinedKey - } - resultChunk := "" - // output based on type - switch node := v.(type) { - case []*TomlTree: - for _, item := range node { - if len(item.Keys()) > 0 { - resultChunk += fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey) - } - resultChunk += item.toToml(indent+" ", combinedKey) - } - resultChunks = append(resultChunks, resultChunk) - case *TomlTree: - if len(node.Keys()) > 0 { - resultChunk += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) - } - resultChunk += node.toToml(indent+" ", combinedKey) - resultChunks = append(resultChunks, resultChunk) - case map[string]interface{}: - sub := TreeFromMap(node) - - if len(sub.Keys()) > 0 { - resultChunk += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) - } - resultChunk += sub.toToml(indent+" ", combinedKey) - resultChunks = append(resultChunks, resultChunk) - case map[string]string: - sub := TreeFromMap(convertMapStringString(node)) - - if len(sub.Keys()) > 0 { - resultChunk += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) - } - resultChunk += sub.toToml(indent+" ", combinedKey) - resultChunks = append(resultChunks, resultChunk) - case map[interface{}]interface{}: - sub := TreeFromMap(convertMapInterfaceInterface(node)) - - if len(sub.Keys()) > 0 { - resultChunk += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) - } - resultChunk += sub.toToml(indent+" ", combinedKey) - resultChunks = append(resultChunks, resultChunk) - case *tomlValue: - resultChunk = fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(node.value, 0)) - resultChunks = append([]string{resultChunk}, resultChunks...) - default: - resultChunk = fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(v, 0)) - resultChunks = append([]string{resultChunk}, resultChunks...) - } - - } - return strings.Join(resultChunks, "") -} - -// Same as ToToml(), but does not panic and returns an error -func (t *TomlTree) toTomlSafe(indent, keyspace string) (result string, err error) { - defer func() { - if r := recover(); r != nil { - result = "" - switch x := r.(type) { - case error: - err = x - default: - err = fmt.Errorf("unknown panic: %s", r) - } - } - }() - result = t.toToml(indent, keyspace) - return -} - -func convertMapStringString(in map[string]string) map[string]interface{} { - result := make(map[string]interface{}, len(in)) - for k, v := range in { - result[k] = v - } - return result -} - -func convertMapInterfaceInterface(in map[interface{}]interface{}) map[string]interface{} { - result := make(map[string]interface{}, len(in)) - for k, v := range in { - result[k.(string)] = v - } - return result -} - -// ToString generates a human-readable representation of the current tree. -// Output spans multiple lines, and is suitable for ingest by a TOML parser. -// If the conversion cannot be performed, ToString returns a non-nil error. -func (t *TomlTree) ToString() (string, error) { - return t.toTomlSafe("", "") -} - -// String generates a human-readable representation of the current tree. -// Alias of ToString. -func (t *TomlTree) String() string { - result, _ := t.ToString() - return result -} - -// ToMap recursively generates a representation of the current tree using map[string]interface{}. -func (t *TomlTree) ToMap() map[string]interface{} { - result := map[string]interface{}{} - - for k, v := range t.values { - switch node := v.(type) { - case []*TomlTree: - var array []interface{} - for _, item := range node { - array = append(array, item.ToMap()) - } - result[k] = array - case *TomlTree: - result[k] = node.ToMap() - case map[string]interface{}: - sub := TreeFromMap(node) - result[k] = sub.ToMap() - case *tomlValue: - result[k] = node.value - } - } - - return result -} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go new file mode 100644 index 0000000..c6054f3 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_create.go @@ -0,0 +1,135 @@ +package toml + +import ( + "fmt" + "reflect" + "time" +) + +// supported values: +// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32 + +var kindToTypeMapping = map[reflect.Kind]reflect.Type{ + reflect.Bool: reflect.TypeOf(true), + reflect.String: reflect.TypeOf(""), + reflect.Float32: reflect.TypeOf(float64(1)), + reflect.Float64: reflect.TypeOf(float64(1)), + reflect.Int: reflect.TypeOf(int64(1)), + reflect.Int8: reflect.TypeOf(int64(1)), + reflect.Int16: reflect.TypeOf(int64(1)), + reflect.Int32: reflect.TypeOf(int64(1)), + reflect.Int64: reflect.TypeOf(int64(1)), + reflect.Uint: reflect.TypeOf(uint64(1)), + reflect.Uint8: reflect.TypeOf(uint64(1)), + reflect.Uint16: reflect.TypeOf(uint64(1)), + reflect.Uint32: reflect.TypeOf(uint64(1)), + reflect.Uint64: reflect.TypeOf(uint64(1)), +} + +func simpleValueCoercion(object interface{}) (interface{}, error) { + switch original := object.(type) { + case string, bool, int64, uint64, float64, time.Time: + return original, nil + case int: + return int64(original), nil + case int8: + return int64(original), nil + case int16: + return int64(original), nil + case int32: + return int64(original), nil + case uint: + return uint64(original), nil + case uint8: + return uint64(original), nil + case uint16: + return uint64(original), nil + case uint32: + return uint64(original), nil + case float32: + return float64(original), nil + case fmt.Stringer: + return original.String(), nil + default: + return nil, fmt.Errorf("cannot convert type %T to TomlTree", object) + } +} + +func sliceToTree(object interface{}) (interface{}, error) { + // arrays are a bit tricky, since they can represent either a + // collection of simple values, which is represented by one + // *tomlValue, or an array of tables, which is represented by an + // array of *TomlTree. + + // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice + value := reflect.ValueOf(object) + insideType := value.Type().Elem() + length := value.Len() + if length > 0 { + insideType = reflect.ValueOf(value.Index(0).Interface()).Type() + } + if insideType.Kind() == reflect.Map { + // this is considered as an array of tables + tablesArray := make([]*TomlTree, 0, length) + for i := 0; i < length; i++ { + table := value.Index(i) + tree, err := toTree(table.Interface()) + if err != nil { + return nil, err + } + tablesArray = append(tablesArray, tree.(*TomlTree)) + } + return tablesArray, nil + } + + sliceType := kindToTypeMapping[insideType.Kind()] + if sliceType == nil { + sliceType = insideType + } + + arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length) + + for i := 0; i < length; i++ { + val := value.Index(i).Interface() + simpleValue, err := simpleValueCoercion(val) + if err != nil { + return nil, err + } + arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue)) + } + return &tomlValue{arrayValue.Interface(), Position{}}, nil +} + +func toTree(object interface{}) (interface{}, error) { + value := reflect.ValueOf(object) + + if value.Kind() == reflect.Map { + values := map[string]interface{}{} + keys := value.MapKeys() + for _, key := range keys { + if key.Kind() != reflect.String { + if _, ok := key.Interface().(string); !ok { + return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind()) + } + } + + v := value.MapIndex(key) + newValue, err := toTree(v.Interface()) + if err != nil { + return nil, err + } + values[key.String()] = newValue + } + return &TomlTree{values, Position{}}, nil + } + + if value.Kind() == reflect.Array || value.Kind() == reflect.Slice { + return sliceToTree(object) + } + + simpleValue, err := simpleValueCoercion(object) + if err != nil { + return nil, err + } + return &tomlValue{simpleValue, Position{}}, nil +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go new file mode 100644 index 0000000..6a7fa17 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go @@ -0,0 +1,217 @@ +package toml + +import ( + "bytes" + "fmt" + "io" + "sort" + "strconv" + "strings" + "time" + "reflect" +) + +// encodes a string to a TOML-compliant string value +func encodeTomlString(value string) string { + result := "" + for _, rr := range value { + switch rr { + case '\b': + result += "\\b" + case '\t': + result += "\\t" + case '\n': + result += "\\n" + case '\f': + result += "\\f" + case '\r': + result += "\\r" + case '"': + result += "\\\"" + case '\\': + result += "\\\\" + default: + intRr := uint16(rr) + if intRr < 0x001F { + result += fmt.Sprintf("\\u%0.4X", intRr) + } else { + result += string(rr) + } + } + } + return result +} + +func tomlValueStringRepresentation(v interface{}) (string, error) { + switch value := v.(type) { + case uint64: + return strconv.FormatUint(value, 10), nil + case int64: + return strconv.FormatInt(value, 10), nil + case float64: + return strconv.FormatFloat(value, 'f', -1, 32), nil + case string: + return "\"" + encodeTomlString(value) + "\"", nil + case []byte: + b, _ := v.([]byte) + return tomlValueStringRepresentation(string(b)) + case bool: + if value { + return "true", nil + } + return "false", nil + case time.Time: + return value.Format(time.RFC3339), nil + case nil: + return "", nil + } + + rv := reflect.ValueOf(v) + + if rv.Kind() == reflect.Slice { + values := []string{} + for i := 0; i < rv.Len(); i++ { + item := rv.Index(i).Interface() + itemRepr, err := tomlValueStringRepresentation(item) + if err != nil { + return "", err + } + values = append(values, itemRepr) + } + return "[" + strings.Join(values, ",") + "]", nil + } + return "", fmt.Errorf("unsupported value type %T: %v", v, v) +} + +func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) { + simpleValuesKeys := make([]string, 0) + complexValuesKeys := make([]string, 0) + + for k := range t.values { + v := t.values[k] + switch v.(type) { + case *TomlTree, []*TomlTree: + complexValuesKeys = append(complexValuesKeys, k) + default: + simpleValuesKeys = append(simpleValuesKeys, k) + } + } + + sort.Strings(simpleValuesKeys) + sort.Strings(complexValuesKeys) + + for _, k := range simpleValuesKeys { + v, ok := t.values[k].(*tomlValue) + if !ok { + return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) + } + + repr, err := tomlValueStringRepresentation(v.value) + if err != nil { + return bytesCount, err + } + + kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr) + writtenBytesCount, err := w.Write([]byte(kvRepr)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + } + + for _, k := range complexValuesKeys { + v := t.values[k] + + combinedKey := k + if keyspace != "" { + combinedKey = keyspace + "." + combinedKey + } + + switch node := v.(type) { + // node has to be of those two types given how keys are sorted above + case *TomlTree: + tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) + writtenBytesCount, err := w.Write([]byte(tableName)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount) + if err != nil { + return bytesCount, err + } + case []*TomlTree: + for _, subTree := range node { + if len(subTree.values) > 0 { + tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey) + writtenBytesCount, err := w.Write([]byte(tableArrayName)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + + bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount) + if err != nil { + return bytesCount, err + } + } + } + } + } + + return bytesCount, nil +} + +// WriteTo encode the TomlTree 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 *TomlTree) WriteTo(w io.Writer) (int64, error) { + return t.writeTo(w, "", "", 0) +} + +// ToTomlString generates a human-readable representation of the current tree. +// Output spans multiple lines, and is suitable for ingest by a TOML parser. +// If the conversion cannot be performed, ToString returns a non-nil error. +func (t *TomlTree) ToTomlString() (string, error) { + var buf bytes.Buffer + _, err := t.WriteTo(&buf) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// String generates a human-readable representation of the current tree. +// Alias of ToString. Present to implement the fmt.Stringer interface. +func (t *TomlTree) String() string { + result, _ := t.ToTomlString() + return result +} + +// ToMap recursively generates a representation of the tree using Go built-in structures. +// The following types are used: +// * uint64 +// * int64 +// * bool +// * string +// * time.Time +// * map[string]interface{} (where interface{} is any of this list) +// * []interface{} (where interface{} is any of this list) +func (t *TomlTree) ToMap() map[string]interface{} { + result := map[string]interface{}{} + + for k, v := range t.values { + switch node := v.(type) { + case []*TomlTree: + var array []interface{} + for _, item := range node { + array = append(array, item.ToMap()) + } + result[k] = array + case *TomlTree: + result[k] = node.ToMap() + case *tomlValue: + result[k] = node.value + } + } + return result +} -- cgit v1.2.3