Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e8d2a6aad | |||
| 3f7178ffd6 | |||
| 9fd5922321 | |||
| 610cf85ed6 | |||
| 99f8a2a010 | |||
| 556d384d4c | |||
| eb7280e4a7 | |||
| 7ee1118b4b | |||
| a12e102214 | |||
| ad60b7e437 | |||
| 3503483c73 | |||
| d2d17bccec | |||
| 76a94674c9 | |||
| 80f8b7660b | |||
| 6f6ca41621 | |||
| c4efb7477c |
@@ -0,0 +1,29 @@
|
|||||||
|
export CGO_ENABLED=0
|
||||||
|
go := go
|
||||||
|
go.goos ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f1)
|
||||||
|
go.goarch ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f2)
|
||||||
|
|
||||||
|
out.tools := tomll tomljson jsontoml
|
||||||
|
out.dist := $(out.tools:=_$(go.goos)_$(go.goarch).tar.xz)
|
||||||
|
sources := $(wildcard **/*.go)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
tools: $(out.tools)
|
||||||
|
|
||||||
|
$(out.tools): $(sources)
|
||||||
|
GOOS=$(go.goos) GOARCH=$(go.goarch) $(go) build ./cmd/$@
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
dist: $(out.dist)
|
||||||
|
|
||||||
|
$(out.dist):%_$(go.goos)_$(go.goarch).tar.xz: %
|
||||||
|
if [ "$(go.goos)" = "windows" ]; then \
|
||||||
|
tar -cJf $@ $^.exe; \
|
||||||
|
else \
|
||||||
|
tar -cJf $@ $^; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
clean:
|
||||||
|
rm -rf $(out.tools) $(out.dist)
|
||||||
+86
-23
@@ -13,9 +13,9 @@ stages:
|
|||||||
vmImage: ubuntu-latest
|
vmImage: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go 1.13"
|
displayName: "Install Go 1.14"
|
||||||
inputs:
|
inputs:
|
||||||
version: "1.13"
|
version: "1.14"
|
||||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
@@ -36,9 +36,9 @@ stages:
|
|||||||
vmImage: ubuntu-latest
|
vmImage: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go 1.13"
|
displayName: "Install Go 1.14"
|
||||||
inputs:
|
inputs:
|
||||||
version: "1.13"
|
version: "1.14"
|
||||||
- task: Go@0
|
- task: Go@0
|
||||||
displayName: "go fmt ./..."
|
displayName: "go fmt ./..."
|
||||||
inputs:
|
inputs:
|
||||||
@@ -51,9 +51,9 @@ stages:
|
|||||||
vmImage: ubuntu-latest
|
vmImage: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go 1.13"
|
displayName: "Install Go 1.14"
|
||||||
inputs:
|
inputs:
|
||||||
version: "1.13"
|
version: "1.14"
|
||||||
- task: Go@0
|
- task: Go@0
|
||||||
displayName: "Generate coverage"
|
displayName: "Generate coverage"
|
||||||
inputs:
|
inputs:
|
||||||
@@ -62,16 +62,18 @@ stages:
|
|||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
targetType: 'inline'
|
targetType: 'inline'
|
||||||
script: 'bash <(curl -s https://codecov.io/bash) -t $(CODECOV_TOKEN)'
|
script: 'bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}'
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: $(CODECOV_TOKEN)
|
||||||
- job: benchmark
|
- job: benchmark
|
||||||
displayName: "benchmark"
|
displayName: "benchmark"
|
||||||
pool:
|
pool:
|
||||||
vmImage: ubuntu-latest
|
vmImage: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go 1.13"
|
displayName: "Install Go 1.14"
|
||||||
inputs:
|
inputs:
|
||||||
version: "1.13"
|
version: "1.14"
|
||||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
@@ -84,9 +86,9 @@ stages:
|
|||||||
vmImage: ubuntu-latest
|
vmImage: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go 1.13"
|
displayName: "Install Go 1.14"
|
||||||
inputs:
|
inputs:
|
||||||
version: "1.13"
|
version: "1.14"
|
||||||
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
@@ -100,24 +102,24 @@ stages:
|
|||||||
displayName: "unit tests"
|
displayName: "unit tests"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
linux 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'ubuntu-latest'
|
||||||
|
mac 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'macOS-latest'
|
||||||
|
windows 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'windows-latest'
|
||||||
linux 1.13:
|
linux 1.13:
|
||||||
goVersion: '1.13'
|
goVersion: '1.13'
|
||||||
imageName: 'ubuntu-latest'
|
imageName: 'ubuntu-latest'
|
||||||
mac 1.13:
|
mac 1.13:
|
||||||
goVersion: '1.13'
|
goVersion: '1.13'
|
||||||
imageName: 'macos-10.13'
|
imageName: 'macOS-latest'
|
||||||
windows 1.13:
|
windows 1.13:
|
||||||
goVersion: '1.13'
|
goVersion: '1.13'
|
||||||
imageName: 'vs2017-win2016'
|
imageName: 'windows-latest'
|
||||||
linux 1.12:
|
|
||||||
goVersion: '1.12'
|
|
||||||
imageName: 'ubuntu-latest'
|
|
||||||
mac 1.12:
|
|
||||||
goVersion: '1.12'
|
|
||||||
imageName: 'macos-10.13'
|
|
||||||
windows 1.12:
|
|
||||||
goVersion: '1.12'
|
|
||||||
imageName: 'vs2017-win2016'
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
steps:
|
steps:
|
||||||
@@ -130,6 +132,67 @@ stages:
|
|||||||
inputs:
|
inputs:
|
||||||
command: 'test'
|
command: 'test'
|
||||||
arguments: './...'
|
arguments: './...'
|
||||||
|
- stage: build_binaries
|
||||||
|
displayName: "Build binaries"
|
||||||
|
dependsOn: run_checks
|
||||||
|
jobs:
|
||||||
|
- job: build_binary
|
||||||
|
displayName: "Build binary"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
linux_amd64:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
darwin_amd64:
|
||||||
|
GOOS: darwin
|
||||||
|
GOARCH: amd64
|
||||||
|
windows_amd64:
|
||||||
|
GOOS: windows
|
||||||
|
GOARCH: amd64
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go"
|
||||||
|
inputs:
|
||||||
|
version: 1.14
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
targetType: inline
|
||||||
|
script: "make dist"
|
||||||
|
env:
|
||||||
|
go.goos: $(GOOS)
|
||||||
|
go.goarch: $(GOARCH)
|
||||||
|
- task: CopyFiles@2
|
||||||
|
inputs:
|
||||||
|
sourceFolder: '$(Build.SourcesDirectory)'
|
||||||
|
contents: '*.tar.xz'
|
||||||
|
TargetFolder: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
inputs:
|
||||||
|
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
artifactName: binaries
|
||||||
|
- stage: build_binaries_manifest
|
||||||
|
displayName: "Build binaries manifest"
|
||||||
|
dependsOn: build_binaries
|
||||||
|
jobs:
|
||||||
|
- job: build_manifest
|
||||||
|
displayName: "Build binaries manifest"
|
||||||
|
steps:
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
inputs:
|
||||||
|
buildType: 'current'
|
||||||
|
downloadType: 'single'
|
||||||
|
artifactName: 'binaries'
|
||||||
|
downloadPath: '$(Build.SourcesDirectory)'
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
targetType: inline
|
||||||
|
script: "cd binaries && sha256sum --binary *.tar.xz | tee $(Build.ArtifactStagingDirectory)/sha256sums.txt"
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
inputs:
|
||||||
|
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
artifactName: manifest
|
||||||
|
|
||||||
- stage: build_docker_image
|
- stage: build_docker_image
|
||||||
displayName: "Build Docker image"
|
displayName: "Build Docker image"
|
||||||
@@ -164,4 +227,4 @@ stages:
|
|||||||
command: 'buildAndPush'
|
command: 'buildAndPush'
|
||||||
Dockerfile: 'Dockerfile'
|
Dockerfile: 'Dockerfile'
|
||||||
buildContext: '.'
|
buildContext: '.'
|
||||||
tags: 'latest'
|
tags: 'latest'
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,3 +9,9 @@ gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
|||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
|
|||||||
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(tokenRightCurlyBrace)
|
l.emit(tokenRightCurlyBrace)
|
||||||
return l.lexVoid
|
return l.lexRvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
||||||
|
|||||||
+95
-37
@@ -302,7 +302,7 @@ func (e *Encoder) marshal(v interface{}) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
_, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order)
|
_, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order, false)
|
||||||
|
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
@@ -320,20 +320,25 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
|||||||
tval := e.nextTree()
|
tval := e.nextTree()
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
for i := 0; i < mtype.NumField(); i++ {
|
switch mval.Interface().(type) {
|
||||||
mtypef, mvalf := mtype.Field(i), mval.Field(i)
|
case Tree:
|
||||||
opts := tomlOptions(mtypef, e.annotation)
|
reflect.ValueOf(tval).Elem().Set(mval)
|
||||||
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
|
default:
|
||||||
val, err := e.valueToToml(mtypef.Type, mvalf)
|
for i := 0; i < mtype.NumField(); i++ {
|
||||||
if err != nil {
|
mtypef, mvalf := mtype.Field(i), mval.Field(i)
|
||||||
return nil, err
|
opts := tomlOptions(mtypef, e.annotation)
|
||||||
}
|
if opts.include && ((mtypef.Type.Kind() != reflect.Interface && !opts.omitempty) || !isZero(mvalf)) {
|
||||||
|
val, err := e.valueToToml(mtypef.Type, mvalf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
tval.SetWithOptions(opts.name, SetOptions{
|
tval.SetWithOptions(opts.name, SetOptions{
|
||||||
Comment: opts.comment,
|
Comment: opts.comment,
|
||||||
Commented: opts.commented,
|
Commented: opts.commented,
|
||||||
Multiline: opts.multiline,
|
Multiline: opts.multiline,
|
||||||
}, val)
|
}, val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
@@ -358,12 +363,15 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
|
|||||||
}
|
}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
mvalf := mval.MapIndex(key)
|
mvalf := mval.MapIndex(key)
|
||||||
|
if (mtype.Elem().Kind() == reflect.Ptr || mtype.Elem().Kind() == reflect.Interface) && mvalf.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if e.quoteMapKeys {
|
if e.quoteMapKeys {
|
||||||
keyStr, err := tomlValueStringRepresentation(key.String(), "", e.arraysOneElementPerLine)
|
keyStr, err := tomlValueStringRepresentation(key.String(), "", "", e.arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -391,6 +399,9 @@ func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*T
|
|||||||
|
|
||||||
// Convert given marshal slice to slice of toml values
|
// Convert given marshal slice to slice of toml values
|
||||||
func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
||||||
|
if mtype.Elem().Kind() == reflect.Interface {
|
||||||
|
return nil, fmt.Errorf("marshal can't handle []interface{}")
|
||||||
|
}
|
||||||
tval := make([]interface{}, mval.Len(), mval.Len())
|
tval := make([]interface{}, mval.Len(), mval.Len())
|
||||||
for i := 0; i < mval.Len(); i++ {
|
for i := 0; i < mval.Len(); i++ {
|
||||||
val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
|
val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
|
||||||
@@ -408,6 +419,9 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
|
|||||||
if mtype.Kind() == reflect.Ptr {
|
if mtype.Kind() == reflect.Ptr {
|
||||||
return e.valueToToml(mtype.Elem(), mval.Elem())
|
return e.valueToToml(mtype.Elem(), mval.Elem())
|
||||||
}
|
}
|
||||||
|
if mtype.Kind() == reflect.Interface {
|
||||||
|
return e.valueToToml(mval.Elem().Type(), mval.Elem())
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case isCustomMarshaler(mtype):
|
case isCustomMarshaler(mtype):
|
||||||
return callCustomMarshaler(mval)
|
return callCustomMarshaler(mval)
|
||||||
@@ -561,11 +575,17 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
|||||||
mval = reflect.New(mtype).Elem()
|
mval = reflect.New(mtype).Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < mtype.NumField(); i++ {
|
switch mval.Interface().(type) {
|
||||||
mtypef := mtype.Field(i)
|
case Tree:
|
||||||
an := annotation{tag: d.tagName}
|
mval.Set(reflect.ValueOf(tval).Elem())
|
||||||
opts := tomlOptions(mtypef, an)
|
default:
|
||||||
if opts.include {
|
for i := 0; i < mtype.NumField(); i++ {
|
||||||
|
mtypef := mtype.Field(i)
|
||||||
|
an := annotation{tag: d.tagName}
|
||||||
|
opts := tomlOptions(mtypef, an)
|
||||||
|
if !opts.include {
|
||||||
|
continue
|
||||||
|
}
|
||||||
baseKey := opts.name
|
baseKey := opts.name
|
||||||
keysToTry := []string{
|
keysToTry := []string{
|
||||||
baseKey,
|
baseKey,
|
||||||
@@ -575,20 +595,22 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
|||||||
}
|
}
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
for _, key := range keysToTry {
|
if tval != nil {
|
||||||
exists := tval.Has(key)
|
for _, key := range keysToTry {
|
||||||
if !exists {
|
exists := tval.Has(key)
|
||||||
continue
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val := tval.Get(key)
|
||||||
|
fval := mval.Field(i)
|
||||||
|
mvalf, err := d.valueFromToml(mtypef.Type, val, &fval)
|
||||||
|
if err != nil {
|
||||||
|
return mval, formatError(err, tval.GetPosition(key))
|
||||||
|
}
|
||||||
|
mval.Field(i).Set(mvalf)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
val := tval.Get(key)
|
|
||||||
fval := mval.Field(i)
|
|
||||||
mvalf, err := d.valueFromToml(mtypef.Type, val, &fval)
|
|
||||||
if err != nil {
|
|
||||||
return mval, formatError(err, tval.GetPosition(key))
|
|
||||||
}
|
|
||||||
mval.Field(i).Set(mvalf)
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found && opts.defaultValue != "" {
|
if !found && opts.defaultValue != "" {
|
||||||
@@ -624,9 +646,13 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V
|
|||||||
mval.Field(i).Set(reflect.ValueOf(val))
|
mval.Field(i).Set(reflect.ValueOf(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the old behavior above and try to check anonymous structs
|
// save the old behavior above and try to check structs
|
||||||
if !found && opts.defaultValue == "" && mtypef.Anonymous && mtypef.Type.Kind() == reflect.Struct {
|
if !found && opts.defaultValue == "" && mtypef.Type.Kind() == reflect.Struct {
|
||||||
v, err := d.valueFromTree(mtypef.Type, tval, nil)
|
tmpTval := tval
|
||||||
|
if !mtypef.Anonymous {
|
||||||
|
tmpTval = nil
|
||||||
|
}
|
||||||
|
v, err := d.valueFromTree(mtypef.Type, tmpTval, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
@@ -692,16 +718,41 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
|||||||
if isTree(mtype) {
|
if isTree(mtype) {
|
||||||
return d.valueFromTree(mtype, t, mval11)
|
return d.valueFromTree(mtype, t, mval11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mtype.Kind() == reflect.Interface {
|
||||||
|
if mval1 == nil || mval1.IsNil() {
|
||||||
|
return d.valueFromTree(reflect.TypeOf(map[string]interface{}{}), t, nil)
|
||||||
|
} else {
|
||||||
|
return d.valueFromToml(mval1.Elem().Type(), t, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
if isTreeSequence(mtype) {
|
if isTreeSequence(mtype) {
|
||||||
return d.valueFromTreeSlice(mtype, t)
|
return d.valueFromTreeSlice(mtype, t)
|
||||||
}
|
}
|
||||||
|
if mtype.Kind() == reflect.Interface {
|
||||||
|
if mval1 == nil || mval1.IsNil() {
|
||||||
|
return d.valueFromTreeSlice(reflect.TypeOf([]map[string]interface{}{}), t)
|
||||||
|
} else {
|
||||||
|
ival := mval1.Elem()
|
||||||
|
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||||
|
}
|
||||||
|
}
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
if isOtherSequence(mtype) {
|
if isOtherSequence(mtype) {
|
||||||
return d.valueFromOtherSlice(mtype, t)
|
return d.valueFromOtherSlice(mtype, t)
|
||||||
}
|
}
|
||||||
|
if mtype.Kind() == reflect.Interface {
|
||||||
|
if mval1 == nil || mval1.IsNil() {
|
||||||
|
return d.valueFromOtherSlice(reflect.TypeOf([]interface{}{}), t)
|
||||||
|
} else {
|
||||||
|
ival := mval1.Elem()
|
||||||
|
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||||
|
}
|
||||||
|
}
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
|
||||||
default:
|
default:
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
@@ -786,6 +837,13 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
|||||||
}
|
}
|
||||||
|
|
||||||
return val.Convert(mtype), nil
|
return val.Convert(mtype), nil
|
||||||
|
case reflect.Interface:
|
||||||
|
if mval1 == nil || mval1.IsNil() {
|
||||||
|
return reflect.ValueOf(tval), nil
|
||||||
|
} else {
|
||||||
|
ival := mval1.Elem()
|
||||||
|
return d.valueFromToml(mval1.Elem().Type(), t, &ival)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
|
||||||
}
|
}
|
||||||
@@ -795,7 +853,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
|||||||
func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) {
|
func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) {
|
||||||
var melem *reflect.Value
|
var melem *reflect.Value
|
||||||
|
|
||||||
if mval1 != nil && !mval1.IsNil() && mtype.Elem().Kind() == reflect.Struct {
|
if mval1 != nil && !mval1.IsNil() && (mtype.Elem().Kind() == reflect.Struct || mtype.Elem().Kind() == reflect.Interface) {
|
||||||
elem := mval1.Elem()
|
elem := mval1.Elem()
|
||||||
melem = &elem
|
melem = &elem
|
||||||
}
|
}
|
||||||
|
|||||||
+637
-5
@@ -157,6 +157,44 @@ var mashalOrderPreserveMapToml = []byte(`title = "TOML Marshal Testing"
|
|||||||
j9 = "10"
|
j9 = "10"
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Inter interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NestedStruct struct {
|
||||||
|
FirstName string
|
||||||
|
LastName string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
|
||||||
|
var doc = []byte(`Name = "rui"
|
||||||
|
Age = 18
|
||||||
|
|
||||||
|
[Inter]
|
||||||
|
FirstName = "wang"
|
||||||
|
LastName = "jl"
|
||||||
|
Age = 100`)
|
||||||
|
|
||||||
|
func TestInterface(t *testing.T) {
|
||||||
|
var config Conf
|
||||||
|
config.Inter = &NestedStruct{}
|
||||||
|
err := Unmarshal(doc, &config)
|
||||||
|
expected := Conf{
|
||||||
|
Name: "rui",
|
||||||
|
Age: 18,
|
||||||
|
Inter: &NestedStruct{
|
||||||
|
FirstName: "wang",
|
||||||
|
LastName: "jl",
|
||||||
|
Age: 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err != nil || !reflect.DeepEqual(config, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBasicMarshal(t *testing.T) {
|
func TestBasicMarshal(t *testing.T) {
|
||||||
result, err := Marshal(basicTestData)
|
result, err := Marshal(basicTestData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -913,6 +951,213 @@ func TestMarshalComment(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMarshalMultilineCommented(t *testing.T) {
|
||||||
|
expectedToml := []byte(`# MultilineArray = [
|
||||||
|
# 100,
|
||||||
|
# 200,
|
||||||
|
# 300,
|
||||||
|
# ]
|
||||||
|
# MultilineNestedArray = [
|
||||||
|
# [
|
||||||
|
# "a",
|
||||||
|
# "b",
|
||||||
|
# "c",
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# "d",
|
||||||
|
# "e",
|
||||||
|
# "f",
|
||||||
|
# ],
|
||||||
|
# ]
|
||||||
|
# MultilineString = """
|
||||||
|
# I
|
||||||
|
# am
|
||||||
|
# Allen"""
|
||||||
|
NonCommented = "Not commented line"
|
||||||
|
`)
|
||||||
|
type StructWithMultiline struct {
|
||||||
|
NonCommented string
|
||||||
|
MultilineString string `commented:"true" multiline:"true"`
|
||||||
|
MultilineArray []int `commented:"true"`
|
||||||
|
MultilineNestedArray [][]string `commented:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
enc := NewEncoder(&buf)
|
||||||
|
if err := enc.ArraysWithOneElementPerLine(true).Encode(StructWithMultiline{
|
||||||
|
NonCommented: "Not commented line",
|
||||||
|
MultilineString: "I\nam\nAllen",
|
||||||
|
MultilineArray: []int{100, 200, 300},
|
||||||
|
MultilineNestedArray: [][]string{
|
||||||
|
{"a", "b", "c"},
|
||||||
|
{"d", "e", "f"},
|
||||||
|
},
|
||||||
|
}); err == nil {
|
||||||
|
result := buf.Bytes()
|
||||||
|
if !bytes.Equal(result, expectedToml) {
|
||||||
|
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalNonPrimitiveTypeCommented(t *testing.T) {
|
||||||
|
expectedToml := []byte(`
|
||||||
|
# [CommentedMapField]
|
||||||
|
|
||||||
|
# [CommentedMapField.CommentedMapField1]
|
||||||
|
# SingleLineString = "This line should be commented out"
|
||||||
|
|
||||||
|
# [CommentedMapField.CommentedMapField2]
|
||||||
|
# SingleLineString = "This line should be commented out"
|
||||||
|
|
||||||
|
# [CommentedStructField]
|
||||||
|
|
||||||
|
# [CommentedStructField.CommentedStructField]
|
||||||
|
# MultilineArray = [
|
||||||
|
# 1,
|
||||||
|
# 2,
|
||||||
|
# ]
|
||||||
|
# MultilineNestedArray = [
|
||||||
|
# [
|
||||||
|
# 10,
|
||||||
|
# 20,
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# 100,
|
||||||
|
# 200,
|
||||||
|
# ],
|
||||||
|
# ]
|
||||||
|
# MultilineString = """
|
||||||
|
# This line
|
||||||
|
# should be
|
||||||
|
# commented out"""
|
||||||
|
|
||||||
|
# [CommentedStructField.NotCommentedStructField]
|
||||||
|
# MultilineArray = [
|
||||||
|
# 1,
|
||||||
|
# 2,
|
||||||
|
# ]
|
||||||
|
# MultilineNestedArray = [
|
||||||
|
# [
|
||||||
|
# 10,
|
||||||
|
# 20,
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# 100,
|
||||||
|
# 200,
|
||||||
|
# ],
|
||||||
|
# ]
|
||||||
|
# MultilineString = """
|
||||||
|
# This line
|
||||||
|
# should be
|
||||||
|
# commented out"""
|
||||||
|
|
||||||
|
[NotCommentedStructField]
|
||||||
|
|
||||||
|
# [NotCommentedStructField.CommentedStructField]
|
||||||
|
# MultilineArray = [
|
||||||
|
# 1,
|
||||||
|
# 2,
|
||||||
|
# ]
|
||||||
|
# MultilineNestedArray = [
|
||||||
|
# [
|
||||||
|
# 10,
|
||||||
|
# 20,
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# 100,
|
||||||
|
# 200,
|
||||||
|
# ],
|
||||||
|
# ]
|
||||||
|
# MultilineString = """
|
||||||
|
# This line
|
||||||
|
# should be
|
||||||
|
# commented out"""
|
||||||
|
|
||||||
|
[NotCommentedStructField.NotCommentedStructField]
|
||||||
|
MultilineArray = [
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
]
|
||||||
|
MultilineNestedArray = [
|
||||||
|
[
|
||||||
|
30,
|
||||||
|
40,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
300,
|
||||||
|
400,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
MultilineString = """
|
||||||
|
This line
|
||||||
|
should NOT be
|
||||||
|
commented out"""
|
||||||
|
`)
|
||||||
|
type InnerStruct struct {
|
||||||
|
MultilineString string `multiline:"true"`
|
||||||
|
MultilineArray []int
|
||||||
|
MultilineNestedArray [][]int
|
||||||
|
}
|
||||||
|
type MiddleStruct struct {
|
||||||
|
NotCommentedStructField InnerStruct
|
||||||
|
CommentedStructField InnerStruct `commented:"true"`
|
||||||
|
}
|
||||||
|
type OuterStruct struct {
|
||||||
|
CommentedStructField MiddleStruct `commented:"true"`
|
||||||
|
NotCommentedStructField MiddleStruct
|
||||||
|
CommentedMapField map[string]struct{ SingleLineString string } `commented:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
commentedTestStruct := OuterStruct{
|
||||||
|
CommentedStructField: MiddleStruct{
|
||||||
|
NotCommentedStructField: InnerStruct{
|
||||||
|
MultilineString: "This line\nshould be\ncommented out",
|
||||||
|
MultilineArray: []int{1, 2},
|
||||||
|
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||||
|
},
|
||||||
|
CommentedStructField: InnerStruct{
|
||||||
|
MultilineString: "This line\nshould be\ncommented out",
|
||||||
|
MultilineArray: []int{1, 2},
|
||||||
|
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NotCommentedStructField: MiddleStruct{
|
||||||
|
NotCommentedStructField: InnerStruct{
|
||||||
|
MultilineString: "This line\nshould NOT be\ncommented out",
|
||||||
|
MultilineArray: []int{3, 4},
|
||||||
|
MultilineNestedArray: [][]int{{30, 40}, {300, 400}},
|
||||||
|
},
|
||||||
|
CommentedStructField: InnerStruct{
|
||||||
|
MultilineString: "This line\nshould be\ncommented out",
|
||||||
|
MultilineArray: []int{1, 2},
|
||||||
|
MultilineNestedArray: [][]int{{10, 20}, {100, 200}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CommentedMapField: map[string]struct{ SingleLineString string }{
|
||||||
|
"CommentedMapField1": {
|
||||||
|
SingleLineString: "This line should be commented out",
|
||||||
|
},
|
||||||
|
"CommentedMapField2": {
|
||||||
|
SingleLineString: "This line should be commented out",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
enc := NewEncoder(&buf)
|
||||||
|
if err := enc.ArraysWithOneElementPerLine(true).Encode(commentedTestStruct); err == nil {
|
||||||
|
result := buf.Bytes()
|
||||||
|
if !bytes.Equal(result, expectedToml) {
|
||||||
|
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expectedToml, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type mapsTestStruct struct {
|
type mapsTestStruct struct {
|
||||||
Simple map[string]string
|
Simple map[string]string
|
||||||
Paths map[string]string
|
Paths map[string]string
|
||||||
@@ -1199,6 +1444,54 @@ func TestMarshalCustomMultiline(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMarshalEmbedTree(t *testing.T) {
|
||||||
|
expected := []byte(`OuterField1 = "Out"
|
||||||
|
OuterField2 = 1024
|
||||||
|
|
||||||
|
[TreeField]
|
||||||
|
InnerField1 = "In"
|
||||||
|
InnerField2 = 2048
|
||||||
|
|
||||||
|
[TreeField.EmbedStruct]
|
||||||
|
EmbedField = "Embed"
|
||||||
|
`)
|
||||||
|
type InnerStruct struct {
|
||||||
|
InnerField1 string
|
||||||
|
InnerField2 int
|
||||||
|
EmbedStruct struct{
|
||||||
|
EmbedField string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OuterStruct struct {
|
||||||
|
OuterField1 string
|
||||||
|
OuterField2 int
|
||||||
|
TreeField *Tree
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err := Load(`
|
||||||
|
InnerField1 = "In"
|
||||||
|
InnerField2 = 2048
|
||||||
|
|
||||||
|
[EmbedStruct]
|
||||||
|
EmbedField = "Embed"
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := OuterStruct{
|
||||||
|
"Out",
|
||||||
|
1024,
|
||||||
|
tree,
|
||||||
|
}
|
||||||
|
actual, _ := Marshal(out)
|
||||||
|
|
||||||
|
if !bytes.Equal(actual, expected){
|
||||||
|
t.Errorf("Bad marshal: expected %s, got %s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var testDocBasicToml = []byte(`
|
var testDocBasicToml = []byte(`
|
||||||
[document]
|
[document]
|
||||||
bool_val = true
|
bool_val = true
|
||||||
@@ -1483,12 +1776,20 @@ func TestUnmarshalCamelCaseKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalDefault(t *testing.T) {
|
func TestUnmarshalDefault(t *testing.T) {
|
||||||
|
type EmbeddedStruct struct {
|
||||||
|
StringField string `default:"c"`
|
||||||
|
}
|
||||||
|
|
||||||
var doc struct {
|
var doc struct {
|
||||||
StringField string `default:"a"`
|
StringField string `default:"a"`
|
||||||
BoolField bool `default:"true"`
|
BoolField bool `default:"true"`
|
||||||
IntField int `default:"1"`
|
IntField int `default:"1"`
|
||||||
Int64Field int64 `default:"2"`
|
Int64Field int64 `default:"2"`
|
||||||
Float64Field float64 `default:"3.1"`
|
Float64Field float64 `default:"3.1"`
|
||||||
|
NonEmbeddedStruct struct {
|
||||||
|
StringField string `default:"b"`
|
||||||
|
}
|
||||||
|
EmbeddedStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
err := Unmarshal([]byte(``), &doc)
|
err := Unmarshal([]byte(``), &doc)
|
||||||
@@ -1510,6 +1811,12 @@ func TestUnmarshalDefault(t *testing.T) {
|
|||||||
if doc.Float64Field != 3.1 {
|
if doc.Float64Field != 3.1 {
|
||||||
t.Errorf("Float64Field should be 3.1, not %f", doc.Float64Field)
|
t.Errorf("Float64Field should be 3.1, not %f", doc.Float64Field)
|
||||||
}
|
}
|
||||||
|
if doc.NonEmbeddedStruct.StringField != "b" {
|
||||||
|
t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField)
|
||||||
|
}
|
||||||
|
if doc.EmbeddedStruct.StringField != "c" {
|
||||||
|
t.Errorf("StringField should be \"c\", not %s", doc.EmbeddedStruct.StringField)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalDefaultFailureBool(t *testing.T) {
|
func TestUnmarshalDefaultFailureBool(t *testing.T) {
|
||||||
@@ -2140,3 +2447,328 @@ func TestMarshalLocalTime(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test case for issue #339
|
||||||
|
func TestUnmarshalSameInnerField(t *testing.T) {
|
||||||
|
type InterStruct2 struct {
|
||||||
|
Test string
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
type Inter2 struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
InterStruct2 InterStruct2
|
||||||
|
}
|
||||||
|
type Server struct {
|
||||||
|
Name string `toml:"name"`
|
||||||
|
Inter2 Inter2 `toml:"inter2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var server Server
|
||||||
|
|
||||||
|
if err := Unmarshal([]byte(`name = "123"
|
||||||
|
[inter2]
|
||||||
|
name = "inter2"
|
||||||
|
age = 222`), &server); err == nil {
|
||||||
|
expected := Server{
|
||||||
|
Name: "123",
|
||||||
|
Inter2: Inter2{
|
||||||
|
Name: "inter2",
|
||||||
|
Age: 222,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(server, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, server)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalInterface(t *testing.T) {
|
||||||
|
type InnerStruct struct {
|
||||||
|
InnerField string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OuterStruct struct {
|
||||||
|
PrimitiveField interface{}
|
||||||
|
ArrayField interface{}
|
||||||
|
StructArrayField interface{}
|
||||||
|
MapField map[string]interface{}
|
||||||
|
StructField interface{}
|
||||||
|
PointerField interface{}
|
||||||
|
NilField interface{}
|
||||||
|
InterfacePointerField *interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShouldNotSupportStruct struct {
|
||||||
|
InterfaceArray []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []byte(`ArrayField = [1,2,3]
|
||||||
|
InterfacePointerField = "hello world"
|
||||||
|
PrimitiveField = "string"
|
||||||
|
|
||||||
|
[MapField]
|
||||||
|
key1 = "value1"
|
||||||
|
key2 = false
|
||||||
|
|
||||||
|
[MapField.key3]
|
||||||
|
InnerField = "value3"
|
||||||
|
|
||||||
|
[PointerField]
|
||||||
|
InnerField = "yyy"
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
InnerField = "s1"
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
InnerField = "s2"
|
||||||
|
|
||||||
|
[StructField]
|
||||||
|
InnerField = "xxx"
|
||||||
|
`)
|
||||||
|
|
||||||
|
var h interface{} = "hello world"
|
||||||
|
if result, err := Marshal(OuterStruct{
|
||||||
|
"string",
|
||||||
|
[]int{1, 2, 3},
|
||||||
|
[]InnerStruct{{"s1"}, {"s2"}},
|
||||||
|
map[string]interface{}{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": false,
|
||||||
|
"key3": InnerStruct{"value3"},
|
||||||
|
"nil value": nil,
|
||||||
|
},
|
||||||
|
InnerStruct{
|
||||||
|
"xxx",
|
||||||
|
},
|
||||||
|
&InnerStruct{
|
||||||
|
"yyy",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
&h,
|
||||||
|
}); err == nil {
|
||||||
|
if !bytes.Equal(result, expected) {
|
||||||
|
t.Errorf("Bad marshal: expected\n----\n%s\n----\ngot\n----\n%s\n----\n", expected, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// according to the toml standard, data types of array may not be mixed
|
||||||
|
if _, err := Marshal(ShouldNotSupportStruct{[]interface{}{1, "a", true}}); err == nil {
|
||||||
|
t.Errorf("Should not support []interface{} marshaling")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalToNilInterface(t *testing.T) {
|
||||||
|
toml := []byte(`
|
||||||
|
PrimitiveField = "Hello"
|
||||||
|
ArrayField = [1,2,3]
|
||||||
|
InterfacePointerField = "World"
|
||||||
|
|
||||||
|
[StructField]
|
||||||
|
Field1 = 123
|
||||||
|
Field2 = "Field2"
|
||||||
|
|
||||||
|
[MapField]
|
||||||
|
MapField1 = [4,5,6]
|
||||||
|
MapField2 = {A = "A"}
|
||||||
|
MapField3 = false
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
Name = "Allen"
|
||||||
|
Age = 20
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
Name = "Jack"
|
||||||
|
Age = 23
|
||||||
|
`)
|
||||||
|
|
||||||
|
type OuterStruct struct {
|
||||||
|
PrimitiveField interface{}
|
||||||
|
ArrayField interface{}
|
||||||
|
StructArrayField interface{}
|
||||||
|
MapField map[string]interface{}
|
||||||
|
StructField interface{}
|
||||||
|
NilField interface{}
|
||||||
|
InterfacePointerField *interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var s interface{} = "World"
|
||||||
|
expected := OuterStruct{
|
||||||
|
PrimitiveField: "Hello",
|
||||||
|
ArrayField: []interface{}{int64(1), int64(2), int64(3)},
|
||||||
|
StructField: map[string]interface{}{
|
||||||
|
"Field1": int64(123),
|
||||||
|
"Field2": "Field2",
|
||||||
|
},
|
||||||
|
MapField: map[string]interface{}{
|
||||||
|
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
||||||
|
"MapField2": map[string]interface{}{
|
||||||
|
"A": "A",
|
||||||
|
},
|
||||||
|
"MapField3": false,
|
||||||
|
},
|
||||||
|
NilField: nil,
|
||||||
|
InterfacePointerField: &s,
|
||||||
|
StructArrayField: []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"Name": "Allen",
|
||||||
|
"Age": int64(20),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Jack",
|
||||||
|
"Age": int64(23),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := OuterStruct{}
|
||||||
|
if err := Unmarshal(toml, &actual); err == nil {
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalToNonNilInterface(t *testing.T) {
|
||||||
|
toml := []byte(`
|
||||||
|
PrimitiveField = "Allen"
|
||||||
|
ArrayField = [1,2,3]
|
||||||
|
|
||||||
|
[StructField]
|
||||||
|
InnerField = "After1"
|
||||||
|
|
||||||
|
[PointerField]
|
||||||
|
InnerField = "After2"
|
||||||
|
|
||||||
|
[InterfacePointerField]
|
||||||
|
InnerField = "After"
|
||||||
|
|
||||||
|
[MapField]
|
||||||
|
MapField1 = [4,5,6]
|
||||||
|
MapField2 = {A = "A"}
|
||||||
|
MapField3 = false
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
InnerField = "After3"
|
||||||
|
|
||||||
|
[[StructArrayField]]
|
||||||
|
InnerField = "After4"
|
||||||
|
`)
|
||||||
|
type InnerStruct struct {
|
||||||
|
InnerField interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OuterStruct struct {
|
||||||
|
PrimitiveField interface{}
|
||||||
|
ArrayField interface{}
|
||||||
|
StructArrayField interface{}
|
||||||
|
MapField map[string]interface{}
|
||||||
|
StructField interface{}
|
||||||
|
PointerField interface{}
|
||||||
|
NilField interface{}
|
||||||
|
InterfacePointerField *interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var s interface{} = InnerStruct{"After"}
|
||||||
|
expected := OuterStruct{
|
||||||
|
PrimitiveField: "Allen",
|
||||||
|
ArrayField: []int{1, 2, 3},
|
||||||
|
StructField: InnerStruct{InnerField: "After1"},
|
||||||
|
MapField: map[string]interface{}{
|
||||||
|
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
||||||
|
"MapField2": map[string]interface{}{
|
||||||
|
"A": "A",
|
||||||
|
},
|
||||||
|
"MapField3": false,
|
||||||
|
},
|
||||||
|
PointerField: &InnerStruct{InnerField: "After2"},
|
||||||
|
NilField: nil,
|
||||||
|
InterfacePointerField: &s,
|
||||||
|
StructArrayField: []InnerStruct{
|
||||||
|
{InnerField: "After3"},
|
||||||
|
{InnerField: "After4"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := OuterStruct{
|
||||||
|
PrimitiveField: "aaa",
|
||||||
|
ArrayField: []int{100, 200, 300, 400},
|
||||||
|
StructField: InnerStruct{InnerField: "Before1"},
|
||||||
|
MapField: map[string]interface{}{
|
||||||
|
"MapField1": []int{4, 5, 6},
|
||||||
|
"MapField2": map[string]string{
|
||||||
|
"B": "BBB",
|
||||||
|
},
|
||||||
|
"MapField3": true,
|
||||||
|
},
|
||||||
|
PointerField: &InnerStruct{InnerField: "Before2"},
|
||||||
|
NilField: nil,
|
||||||
|
InterfacePointerField: &s,
|
||||||
|
StructArrayField: []InnerStruct{
|
||||||
|
{InnerField: "Before3"},
|
||||||
|
{InnerField: "Before4"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := Unmarshal(toml, &actual); err == nil {
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalEmbedTree(t *testing.T) {
|
||||||
|
toml := []byte(`
|
||||||
|
OuterField1 = "Out"
|
||||||
|
OuterField2 = 1024
|
||||||
|
|
||||||
|
[TreeField]
|
||||||
|
InnerField1 = "In"
|
||||||
|
InnerField2 = 2048
|
||||||
|
|
||||||
|
[TreeField.EmbedStruct]
|
||||||
|
EmbedField = "Embed"
|
||||||
|
|
||||||
|
`)
|
||||||
|
type InnerStruct struct {
|
||||||
|
InnerField1 string
|
||||||
|
InnerField2 int
|
||||||
|
EmbedStruct struct{
|
||||||
|
EmbedField string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OuterStruct struct {
|
||||||
|
OuterField1 string
|
||||||
|
OuterField2 int
|
||||||
|
TreeField *Tree
|
||||||
|
}
|
||||||
|
|
||||||
|
out := OuterStruct{}
|
||||||
|
actual := InnerStruct{}
|
||||||
|
expected := InnerStruct{
|
||||||
|
"In",
|
||||||
|
2048,
|
||||||
|
struct{
|
||||||
|
EmbedField string
|
||||||
|
}{
|
||||||
|
EmbedField:"Embed",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := Unmarshal(toml, &out); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := out.TreeField.Unmarshal(&actual); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, expected){
|
||||||
|
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+34
-1
@@ -581,6 +581,39 @@ func TestDoubleInlineGroup(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNestedInlineGroup(t *testing.T) {
|
||||||
|
tree, err := Load("out = {block0 = {x = 99, y = 100}, block1 = {p = \"999\", q = \"1000\"}}")
|
||||||
|
assertTree(t, tree, err, map[string]interface{}{
|
||||||
|
"out": map[string]interface{}{
|
||||||
|
"block0": map[string]interface{}{
|
||||||
|
"x": int64(99),
|
||||||
|
"y": int64(100),
|
||||||
|
},
|
||||||
|
"block1": map[string]interface{}{
|
||||||
|
"p": "999",
|
||||||
|
"q": "1000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrayInNestedInlineGroup(t *testing.T) {
|
||||||
|
tree, err := Load(`image = {name = "xxx", palette = {id = 100, colors = ["red", "blue", "green"]}}`)
|
||||||
|
assertTree(t, tree, err, map[string]interface{}{
|
||||||
|
"image": map[string]interface{}{
|
||||||
|
"name": "xxx",
|
||||||
|
"palette": map[string]interface{}{
|
||||||
|
"id": int64(100),
|
||||||
|
"colors": []string{
|
||||||
|
"red",
|
||||||
|
"blue",
|
||||||
|
"green",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestExampleInlineGroup(t *testing.T) {
|
func TestExampleInlineGroup(t *testing.T) {
|
||||||
tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
|
tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
|
||||||
point = { x = 1, y = 2 }`)
|
point = { x = 1, y = 2 }`)
|
||||||
@@ -864,7 +897,7 @@ func TestTomlValueStringRepresentation(t *testing.T) {
|
|||||||
"[\"gamma\",\"delta\"]"},
|
"[\"gamma\",\"delta\"]"},
|
||||||
{nil, ""},
|
{nil, ""},
|
||||||
} {
|
} {
|
||||||
result, err := tomlValueStringRepresentation(item.Value, "", false)
|
result, err := tomlValueStringRepresentation(item.Value, "", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test %d - unexpected error: %s", idx, err)
|
t.Errorf("Test %d - unexpected error: %s", idx, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,8 +222,12 @@ func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interfac
|
|||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case *Tree:
|
case *Tree:
|
||||||
v.comment = opts.Comment
|
v.comment = opts.Comment
|
||||||
|
v.commented = opts.Commented
|
||||||
toInsert = value
|
toInsert = value
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
|
for i := range v {
|
||||||
|
v[i].commented = opts.Commented
|
||||||
|
}
|
||||||
toInsert = value
|
toInsert = value
|
||||||
case *tomlValue:
|
case *tomlValue:
|
||||||
v.comment = opts.Comment
|
v.comment = opts.Comment
|
||||||
|
|||||||
+27
-21
@@ -28,9 +28,10 @@ type sortNode struct {
|
|||||||
// Encodes a string to a TOML-compliant multi-line string value
|
// Encodes a string to a TOML-compliant multi-line string value
|
||||||
// This function is a clone of the existing encodeTomlString function, except that whitespace characters
|
// This function is a clone of the existing encodeTomlString function, except that whitespace characters
|
||||||
// are preserved. Quotation marks and backslashes are also not escaped.
|
// are preserved. Quotation marks and backslashes are also not escaped.
|
||||||
func encodeMultilineTomlString(value string) string {
|
func encodeMultilineTomlString(value string, commented string) string {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
b.WriteString(commented)
|
||||||
for _, rr := range value {
|
for _, rr := range value {
|
||||||
switch rr {
|
switch rr {
|
||||||
case '\b':
|
case '\b':
|
||||||
@@ -38,7 +39,7 @@ func encodeMultilineTomlString(value string) string {
|
|||||||
case '\t':
|
case '\t':
|
||||||
b.WriteString("\t")
|
b.WriteString("\t")
|
||||||
case '\n':
|
case '\n':
|
||||||
b.WriteString("\n")
|
b.WriteString("\n" + commented)
|
||||||
case '\f':
|
case '\f':
|
||||||
b.WriteString(`\f`)
|
b.WriteString(`\f`)
|
||||||
case '\r':
|
case '\r':
|
||||||
@@ -91,7 +92,7 @@ func encodeTomlString(value string) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) {
|
func tomlValueStringRepresentation(v interface{}, commented string, indent string, arraysOneElementPerLine bool) (string, error) {
|
||||||
// this interface check is added to dereference the change made in the writeTo function.
|
// this interface check is added to dereference the change made in the writeTo function.
|
||||||
// That change was made to allow this function to see formatting options.
|
// That change was made to allow this function to see formatting options.
|
||||||
tv, ok := v.(*tomlValue)
|
tv, ok := v.(*tomlValue)
|
||||||
@@ -123,12 +124,12 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
|||||||
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
|
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
|
||||||
case string:
|
case string:
|
||||||
if tv.multiline {
|
if tv.multiline {
|
||||||
return "\"\"\"\n" + encodeMultilineTomlString(value) + "\"\"\"", nil
|
return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
|
||||||
}
|
}
|
||||||
return "\"" + encodeTomlString(value) + "\"", nil
|
return "\"" + encodeTomlString(value) + "\"", nil
|
||||||
case []byte:
|
case []byte:
|
||||||
b, _ := v.([]byte)
|
b, _ := v.([]byte)
|
||||||
return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine)
|
return tomlValueStringRepresentation(string(b), commented, indent, arraysOneElementPerLine)
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
return "true", nil
|
return "true", nil
|
||||||
@@ -152,7 +153,7 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
|||||||
var values []string
|
var values []string
|
||||||
for i := 0; i < rv.Len(); i++ {
|
for i := 0; i < rv.Len(); i++ {
|
||||||
item := rv.Index(i).Interface()
|
item := rv.Index(i).Interface()
|
||||||
itemRepr, err := tomlValueStringRepresentation(item, indent, arraysOneElementPerLine)
|
itemRepr, err := tomlValueStringRepresentation(item, commented, indent, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -166,12 +167,12 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
|
|||||||
|
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
stringBuffer.WriteString(valueIndent)
|
stringBuffer.WriteString(valueIndent)
|
||||||
stringBuffer.WriteString(value)
|
stringBuffer.WriteString(commented + value)
|
||||||
stringBuffer.WriteString(`,`)
|
stringBuffer.WriteString(`,`)
|
||||||
stringBuffer.WriteString("\n")
|
stringBuffer.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
stringBuffer.WriteString(indent + "]")
|
stringBuffer.WriteString(indent + commented + "]")
|
||||||
|
|
||||||
return stringBuffer.String(), nil
|
return stringBuffer.String(), nil
|
||||||
}
|
}
|
||||||
@@ -270,10 +271,10 @@ func sortAlphabetical(t *Tree) (vals []sortNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
|
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
|
||||||
return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical)
|
return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
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, parentCommented bool) (int64, error) {
|
||||||
var orderedVals []sortNode
|
var orderedVals []sortNode
|
||||||
|
|
||||||
switch ord {
|
switch ord {
|
||||||
@@ -293,10 +294,6 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
if keyspace != "" {
|
if keyspace != "" {
|
||||||
combinedKey = keyspace + "." + combinedKey
|
combinedKey = keyspace + "." + combinedKey
|
||||||
}
|
}
|
||||||
var commented string
|
|
||||||
if t.commented {
|
|
||||||
commented = "# "
|
|
||||||
}
|
|
||||||
|
|
||||||
switch node := v.(type) {
|
switch node := v.(type) {
|
||||||
// node has to be of those two types given how keys are sorted above
|
// node has to be of those two types given how keys are sorted above
|
||||||
@@ -317,24 +314,33 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
return bytesCount, errc
|
return bytesCount, errc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commented string
|
||||||
|
if parentCommented || t.commented || tv.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
bytesCount, err = node.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
|
bytesCount, err = node.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord, parentCommented || t.commented || tv.commented)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
for _, subTree := range node {
|
for _, subTree := range node {
|
||||||
|
var commented string
|
||||||
|
if parentCommented || t.commented || subTree.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesCount, err = subTree.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
|
bytesCount, err = subTree.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord, parentCommented || t.commented || subTree.commented)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
@@ -347,7 +353,11 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
||||||
}
|
}
|
||||||
|
|
||||||
repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine)
|
var commented string
|
||||||
|
if parentCommented || t.commented || v.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
repr, err := tomlValueStringRepresentation(v, commented, indent, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
@@ -365,10 +375,6 @@ func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var commented string
|
|
||||||
if v.commented {
|
|
||||||
commented = "# "
|
|
||||||
}
|
|
||||||
quotedKey := quoteKeyIfNeeded(k)
|
quotedKey := quoteKeyIfNeeded(k)
|
||||||
writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
|
writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
|
|||||||
Reference in New Issue
Block a user