Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 728039f679 | |||
| 1d8903f1d0 | |||
| 65b27e6823 | |||
| 6ea91ef590 | |||
| 51edd0ca49 | |||
| d95bfe020e |
@@ -88,6 +88,33 @@ jobs:
|
||||
command: |
|
||||
curl https://codecov.io/bash > codecov.sh
|
||||
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:
|
||||
version: 2.1
|
||||
@@ -138,3 +165,6 @@ workflows:
|
||||
requires:
|
||||
- go1_11
|
||||
- go1_12
|
||||
- docker:
|
||||
requires:
|
||||
- codecov
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
cmd/tomll/tomll
|
||||
cmd/tomljson/tomljson
|
||||
@@ -1,2 +1,5 @@
|
||||
test_program/test_program_bin
|
||||
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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
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())
|
||||
} else {
|
||||
// retrieve data directly
|
||||
user := config.Get("postgres.user").(string)
|
||||
password := config.Get("postgres.password").(string)
|
||||
directUser := config.Get("postgres.user").(string)
|
||||
directPassword := config.Get("postgres.password").(string)
|
||||
fmt.Println("User is", directUser, " and password is", directPassword)
|
||||
|
||||
// or using an intermediate object
|
||||
configTree := config.Get("postgres").(*toml.Tree)
|
||||
user = configTree.Get("user").(string)
|
||||
password = configTree.Get("password").(string)
|
||||
user := configTree.Get("user").(string)
|
||||
password := configTree.Get("password").(string)
|
||||
fmt.Println("User is", user, " and password is", password)
|
||||
|
||||
// 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) {
|
||||
res, err := parseKey(key)
|
||||
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 {
|
||||
t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
|
||||
|
||||
+35
-7
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -329,7 +330,26 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
||||
}
|
||||
}
|
||||
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)
|
||||
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
||||
if err != nil {
|
||||
@@ -494,11 +514,19 @@ func (d *Decoder) SetTagName(v string) *Decoder {
|
||||
|
||||
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")
|
||||
if mtype.Kind() != reflect.Ptr {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@@ -546,8 +574,8 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
|
||||
|
||||
if !found && opts.defaultValue != "" {
|
||||
mvalf := mval.Field(i)
|
||||
var val interface{} = nil
|
||||
var err error = nil
|
||||
var val interface{}
|
||||
var err error
|
||||
switch mvalf.Kind() {
|
||||
case reflect.Bool:
|
||||
val, err = strconv.ParseBool(opts.defaultValue)
|
||||
@@ -587,7 +615,7 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
@@ -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:"-"`
|
||||
}
|
||||
|
||||
type testMapDoc struct {
|
||||
Title string `toml:"title"`
|
||||
BasicMap map[string]string `toml:"basic_map"`
|
||||
LongMap map[string]string `toml:"long_map"`
|
||||
}
|
||||
|
||||
type testDocBasics struct {
|
||||
Uint uint `toml:"uint"`
|
||||
Bool bool `toml:"bool"`
|
||||
@@ -200,6 +206,26 @@ var docData = testDoc{
|
||||
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) {
|
||||
result, err := Marshal(docData)
|
||||
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) {
|
||||
result, err := Marshal(&docData)
|
||||
if err != nil {
|
||||
@@ -1054,12 +1103,68 @@ func TestUnmarshalCustomTag(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshalMap(t *testing.T) {
|
||||
m := make(map[string]int)
|
||||
m["a"] = 1
|
||||
testToml := []byte(`
|
||||
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)
|
||||
if err.Error() != "Only a pointer to struct can be unmarshaled from TOML" {
|
||||
t.Fail()
|
||||
expected := map[string]int{
|
||||
"a": 1,
|
||||
"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)
|
||||
}
|
||||
|
||||
// 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"}).
|
||||
func (t *Tree) DeletePath(keys []string) error {
|
||||
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) {
|
||||
orderedVals := make([]sortNode, 0)
|
||||
var orderedVals []sortNode
|
||||
|
||||
switch ord {
|
||||
case OrderPreserve:
|
||||
|
||||
Reference in New Issue
Block a user