Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 728039f679 | |||
| 1d8903f1d0 | |||
| 65b27e6823 | |||
| 6ea91ef590 | |||
| 51edd0ca49 | |||
| d95bfe020e |
@@ -88,6 +88,33 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
curl https://codecov.io/bash > codecov.sh
|
curl https://codecov.io/bash > codecov.sh
|
||||||
bash codecov.sh -v
|
bash codecov.sh -v
|
||||||
|
docker:
|
||||||
|
docker:
|
||||||
|
- image: "circleci/golang:1.12"
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- setup_remote_docker:
|
||||||
|
docker_layer_caching: true
|
||||||
|
- run: docker build -t pelletier/go-toml:$CIRCLE_SHA1 .
|
||||||
|
- run:
|
||||||
|
name: "Publish docker image"
|
||||||
|
command: |
|
||||||
|
if [ "${CIRCLE_PR_REPONAME}" == "" ]; then
|
||||||
|
IMAGE_NAME="pelletier/go-toml"
|
||||||
|
IMAGE_SHA_TAG="${IMAGE_NAME}:$CIRCLE_SHA1"
|
||||||
|
if [ "${CIRCLE_BRANCH}" = "master" ]; then
|
||||||
|
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
|
docker tag ${IMAGE_SHA_TAG} ${IMAGE_NAME}:latest
|
||||||
|
docker push ${IMAGE_NAME}:latest
|
||||||
|
fi
|
||||||
|
if [ "${CIRCLE_TAG}" != "" ]; then
|
||||||
|
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
|
docker tag ${IMAGE_SHA_TAG} ${IMAGE_NAME}:${CIRCLE_TAG}
|
||||||
|
docker push ${IMAGE_NAME}:${CIRCLE_TAG}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "not pushing docker image for forked repo"
|
||||||
|
fi
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2.1
|
version: 2.1
|
||||||
@@ -138,3 +165,6 @@ workflows:
|
|||||||
requires:
|
requires:
|
||||||
- go1_11
|
- go1_11
|
||||||
- go1_12
|
- go1_12
|
||||||
|
- docker:
|
||||||
|
requires:
|
||||||
|
- codecov
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
cmd/tomll/tomll
|
||||||
|
cmd/tomljson/tomljson
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
test_program/test_program_bin
|
test_program/test_program_bin
|
||||||
fuzz/
|
fuzz/
|
||||||
|
cmd/tomll/tomll
|
||||||
|
cmd/tomljson/tomljson
|
||||||
|
cmd/tomltestgen/tomltestgen
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
FROM golang:1.12-alpine3.9 as builder
|
||||||
|
WORKDIR /go/src/github.com/pelletier/go-toml
|
||||||
|
COPY . .
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
ENV GOOS=linux
|
||||||
|
RUN go install ./...
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=builder /go/bin/tomll /usr/bin/tomll
|
||||||
|
COPY --from=builder /go/bin/tomljson /usr/bin/tomljson
|
||||||
@@ -101,6 +101,23 @@ Go-toml provides two handy command line tools:
|
|||||||
tomljson --help
|
tomljson --help
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Docker image
|
||||||
|
|
||||||
|
Those tools are also availble as a Docker image from
|
||||||
|
[dockerhub](https://hub.docker.com/r/pelletier/go-toml). For example, to
|
||||||
|
use `tomljson`:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -v $PWD:/workdir pelletier/go-toml tomljson /workdir/example.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Only master (`latest`) and tagged versions are published to dockerhub. You
|
||||||
|
can build your own image as usual:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t go-toml .
|
||||||
|
```
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
Feel free to report bugs and patches using GitHub's pull requests system on
|
Feel free to report bugs and patches using GitHub's pull requests system on
|
||||||
|
|||||||
+5
-4
@@ -16,13 +16,14 @@ func Example_tree() {
|
|||||||
fmt.Println("Error ", err.Error())
|
fmt.Println("Error ", err.Error())
|
||||||
} else {
|
} else {
|
||||||
// retrieve data directly
|
// retrieve data directly
|
||||||
user := config.Get("postgres.user").(string)
|
directUser := config.Get("postgres.user").(string)
|
||||||
password := config.Get("postgres.password").(string)
|
directPassword := config.Get("postgres.password").(string)
|
||||||
|
fmt.Println("User is", directUser, " and password is", directPassword)
|
||||||
|
|
||||||
// or using an intermediate object
|
// or using an intermediate object
|
||||||
configTree := config.Get("postgres").(*toml.Tree)
|
configTree := config.Get("postgres").(*toml.Tree)
|
||||||
user = configTree.Get("user").(string)
|
user := configTree.Get("user").(string)
|
||||||
password = configTree.Get("password").(string)
|
password := configTree.Get("password").(string)
|
||||||
fmt.Println("User is", user, " and password is", password)
|
fmt.Println("User is", user, " and password is", password)
|
||||||
|
|
||||||
// show where elements are in the file
|
// show where elements are in the file
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ func testResult(t *testing.T, key string, expected []string) {
|
|||||||
func testError(t *testing.T, key string, expectedError string) {
|
func testError(t *testing.T, key string, expectedError string) {
|
||||||
res, err := parseKey(key)
|
res, err := parseKey(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error, but succesfully parsed key %s", res)
|
t.Fatalf("Expected error, but successfully parsed key %s", res)
|
||||||
}
|
}
|
||||||
if fmt.Sprintf("%s", err) != expectedError {
|
if fmt.Sprintf("%s", err) != expectedError {
|
||||||
t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
|
t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
|
||||||
|
|||||||
+35
-7
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -329,7 +330,26 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
for _, key := range mval.MapKeys() {
|
keys := mval.MapKeys()
|
||||||
|
if e.order == OrderPreserve && len(keys) > 0 {
|
||||||
|
// Sorting []reflect.Value is not straight forward.
|
||||||
|
//
|
||||||
|
// OrderPreserve will support deterministic results when string is used
|
||||||
|
// as the key to maps.
|
||||||
|
typ := keys[0].Type()
|
||||||
|
kind := keys[0].Kind()
|
||||||
|
if kind == reflect.String {
|
||||||
|
ikeys := make([]string, len(keys))
|
||||||
|
for i := range keys {
|
||||||
|
ikeys[i] = keys[i].Interface().(string)
|
||||||
|
}
|
||||||
|
sort.Strings(ikeys)
|
||||||
|
for i := range ikeys {
|
||||||
|
keys[i] = reflect.ValueOf(ikeys[i]).Convert(typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
mvalf := mval.MapIndex(key)
|
mvalf := mval.MapIndex(key)
|
||||||
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -494,11 +514,19 @@ func (d *Decoder) SetTagName(v string) *Decoder {
|
|||||||
|
|
||||||
func (d *Decoder) unmarshal(v interface{}) error {
|
func (d *Decoder) unmarshal(v interface{}) error {
|
||||||
mtype := reflect.TypeOf(v)
|
mtype := reflect.TypeOf(v)
|
||||||
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
|
if mtype.Kind() != reflect.Ptr {
|
||||||
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
|
return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
|
||||||
}
|
}
|
||||||
|
|
||||||
sval, err := d.valueFromTree(mtype.Elem(), d.tval)
|
elem := mtype.Elem()
|
||||||
|
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Struct, reflect.Map:
|
||||||
|
default:
|
||||||
|
return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
|
||||||
|
}
|
||||||
|
|
||||||
|
sval, err := d.valueFromTree(elem, d.tval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -546,8 +574,8 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
|
|||||||
|
|
||||||
if !found && opts.defaultValue != "" {
|
if !found && opts.defaultValue != "" {
|
||||||
mvalf := mval.Field(i)
|
mvalf := mval.Field(i)
|
||||||
var val interface{} = nil
|
var val interface{}
|
||||||
var err error = nil
|
var err error
|
||||||
switch mvalf.Kind() {
|
switch mvalf.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
val, err = strconv.ParseBool(opts.defaultValue)
|
val, err = strconv.ParseBool(opts.defaultValue)
|
||||||
@@ -587,7 +615,7 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return mval, formatError(err, tval.GetPosition(key))
|
return mval, formatError(err, tval.GetPosition(key))
|
||||||
}
|
}
|
||||||
mval.SetMapIndex(reflect.ValueOf(key), mvalf)
|
mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mval, nil
|
return mval, nil
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
title = "TOML Marshal Testing"
|
||||||
|
|
||||||
|
[basic_map]
|
||||||
|
one = "one"
|
||||||
|
two = "two"
|
||||||
|
|
||||||
|
[long_map]
|
||||||
|
a7 = "1"
|
||||||
|
b3 = "2"
|
||||||
|
c8 = "3"
|
||||||
|
d4 = "4"
|
||||||
|
e6 = "5"
|
||||||
|
f5 = "6"
|
||||||
|
g10 = "7"
|
||||||
|
h1 = "8"
|
||||||
|
i2 = "9"
|
||||||
|
j9 = "10"
|
||||||
+110
-5
@@ -126,6 +126,12 @@ type testDoc struct {
|
|||||||
Unexported2 int `toml:"-"`
|
Unexported2 int `toml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testMapDoc struct {
|
||||||
|
Title string `toml:"title"`
|
||||||
|
BasicMap map[string]string `toml:"basic_map"`
|
||||||
|
LongMap map[string]string `toml:"long_map"`
|
||||||
|
}
|
||||||
|
|
||||||
type testDocBasics struct {
|
type testDocBasics struct {
|
||||||
Uint uint `toml:"uint"`
|
Uint uint `toml:"uint"`
|
||||||
Bool bool `toml:"bool"`
|
Bool bool `toml:"bool"`
|
||||||
@@ -200,6 +206,26 @@ var docData = testDoc{
|
|||||||
SubDocPtrs: []*testSubDoc{&subdoc},
|
SubDocPtrs: []*testSubDoc{&subdoc},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mapTestDoc = testMapDoc{
|
||||||
|
Title: "TOML Marshal Testing",
|
||||||
|
BasicMap: map[string]string{
|
||||||
|
"one": "one",
|
||||||
|
"two": "two",
|
||||||
|
},
|
||||||
|
LongMap: map[string]string{
|
||||||
|
"h1": "8",
|
||||||
|
"i2": "9",
|
||||||
|
"b3": "2",
|
||||||
|
"d4": "4",
|
||||||
|
"f5": "6",
|
||||||
|
"e6": "5",
|
||||||
|
"a7": "1",
|
||||||
|
"c8": "3",
|
||||||
|
"j9": "10",
|
||||||
|
"g10": "7",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func TestDocMarshal(t *testing.T) {
|
func TestDocMarshal(t *testing.T) {
|
||||||
result, err := Marshal(docData)
|
result, err := Marshal(docData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -223,6 +249,29 @@ func TestDocMarshalOrdered(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDocMarshalMaps(t *testing.T) {
|
||||||
|
result, err := Marshal(mapTestDoc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expected, _ := ioutil.ReadFile("marshal_OrderPreserve_Map_test.toml")
|
||||||
|
if !bytes.Equal(result, expected) {
|
||||||
|
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDocMarshalOrderedMaps(t *testing.T) {
|
||||||
|
var result bytes.Buffer
|
||||||
|
err := NewEncoder(&result).Order(OrderPreserve).Encode(mapTestDoc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expected, _ := ioutil.ReadFile("marshal_OrderPreserve_Map_test.toml")
|
||||||
|
if !bytes.Equal(result.Bytes(), expected) {
|
||||||
|
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDocMarshalPointer(t *testing.T) {
|
func TestDocMarshalPointer(t *testing.T) {
|
||||||
result, err := Marshal(&docData)
|
result, err := Marshal(&docData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1054,12 +1103,68 @@ func TestUnmarshalCustomTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalMap(t *testing.T) {
|
func TestUnmarshalMap(t *testing.T) {
|
||||||
m := make(map[string]int)
|
testToml := []byte(`
|
||||||
m["a"] = 1
|
a = 1
|
||||||
|
b = 2
|
||||||
|
c = 3
|
||||||
|
`)
|
||||||
|
var result map[string]int
|
||||||
|
err := Unmarshal(testToml, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Received unexpected error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err := Unmarshal(basicTestToml, m)
|
expected := map[string]int{
|
||||||
if err.Error() != "Only a pointer to struct can be unmarshaled from TOML" {
|
"a": 1,
|
||||||
t.Fail()
|
"b": 2,
|
||||||
|
"c": 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalMapWithTypedKey(t *testing.T) {
|
||||||
|
testToml := []byte(`
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
c = 3
|
||||||
|
`)
|
||||||
|
|
||||||
|
type letter string
|
||||||
|
var result map[letter]int
|
||||||
|
err := Unmarshal(testToml, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Received unexpected error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[letter]int{
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
"c": 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalNonPointer(t *testing.T) {
|
||||||
|
a := 1
|
||||||
|
err := Unmarshal([]byte{}, a)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("unmarshal should err when given a non pointer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalInvalidPointerKind(t *testing.T) {
|
||||||
|
a := 1
|
||||||
|
err := Unmarshal([]byte{}, &a)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("unmarshal should err when given an invalid pointer type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ func (t *Tree) Delete(key string) error {
|
|||||||
return t.DeletePath(keys)
|
return t.DeletePath(keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes a key from the tree.
|
// DeletePath removes a key from the tree.
|
||||||
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
||||||
func (t *Tree) DeletePath(keys []string) error {
|
func (t *Tree) DeletePath(keys []string) error {
|
||||||
keyLen := len(keys)
|
keyLen := len(keys)
|
||||||
|
|||||||
+1
-1
@@ -259,7 +259,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord marshalOrder) (int64, error) {
|
func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord marshalOrder) (int64, error) {
|
||||||
orderedVals := make([]sortNode, 0)
|
var orderedVals []sortNode
|
||||||
|
|
||||||
switch ord {
|
switch ord {
|
||||||
case OrderPreserve:
|
case OrderPreserve:
|
||||||
|
|||||||
Reference in New Issue
Block a user