Only encoding non-wrapped single .json items as JSON

This commit is contained in:
Mattias Öhrn
2021-06-01 20:44:21 +02:00
parent fa3e829eb6
commit 5e4fb4796e
2 changed files with 84 additions and 37 deletions

View File

@@ -12,7 +12,7 @@ import (
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
// Writer writes ResourceNodes to bytes. // ByteWriter writes ResourceNodes to bytes.
type ByteWriter struct { type ByteWriter struct {
// Writer is where ResourceNodes are encoded. // Writer is where ResourceNodes are encoded.
Writer io.Writer Writer io.Writer
@@ -55,24 +55,24 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error {
} }
} }
encoder := yaml.NewEncoder(w.Writer) // Check if the output is a single JSON file so we can force JSON encoding in that case.
// keep // YAML flow style encoding may not be compatible because of unquoted strings and newlines
hasJSONPathExt := make([]bool, len(nodes)) // introduced by the YAML marshaller in long string values. These newlines are insignificant
defer encoder.Close() // when interpreted as YAML but invalid when interpreted as JSON.
for i := range nodes { jsonEncodeSingleNode := false
// Check if the output file is a JSON file so we can force JSON encoding in that case. if w.WrappingKind == "" && len(nodes) == 1 {
// YAML flow style encoding may not be compatible because of newlines introduced by the if path, _, _ := kioutil.GetFileAnnotations(nodes[0]); path != "" {
// YAML marshaller in long double quoted string values. These newlines are insignificant
// when interpreted as YAML but invalid when interpreted as JSON.
if path, _, _ := kioutil.GetFileAnnotations(nodes[i]); path != "" {
filename := filepath.Base(path) filename := filepath.Base(path)
for _, glob := range JSONMatch { for _, glob := range JSONMatch {
if match, _ := filepath.Match(glob, filename); match { if match, _ := filepath.Match(glob, filename); match {
hasJSONPathExt[i] = true jsonEncodeSingleNode = true
break break
} }
} }
} }
}
for i := range nodes {
// clean resources by removing annotations set by the Reader // clean resources by removing annotations set by the Reader
if !w.KeepReaderAnnotations { if !w.KeepReaderAnnotations {
_, err := nodes[i].Pipe(yaml.ClearAnnotation(kioutil.IndexAnnotation)) _, err := nodes[i].Pipe(yaml.ClearAnnotation(kioutil.IndexAnnotation))
@@ -96,10 +96,18 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error {
} }
} }
if jsonEncodeSingleNode {
encoder := json.NewEncoder(w.Writer)
encoder.SetIndent("", " ")
return errors.Wrap(encoder.Encode(nodes[0]))
}
encoder := yaml.NewEncoder(w.Writer)
defer encoder.Close()
// don't wrap the elements // don't wrap the elements
if w.WrappingKind == "" { if w.WrappingKind == "" {
for i := range nodes { for i := range nodes {
if err := w.encode(encoder, hasJSONPathExt[i], nodes[i].Document()); err != nil { if err := encoder.Encode(nodes[i].Document()); err != nil {
return err return err
} }
} }
@@ -133,27 +141,7 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error {
for i := range nodes { for i := range nodes {
items.Content = append(items.Content, nodes[i].YNode()) items.Content = append(items.Content, nodes[i].YNode())
} }
err := w.encode(encoder, false, doc) err := encoder.Encode(doc)
yaml.UndoSerializationHacksOnNodes(nodes) yaml.UndoSerializationHacksOnNodes(nodes)
return err return err
} }
// encode encodes the input document node to appropriate node format
func (w ByteWriter) encode(encoder *yaml.Encoder, forceJSON bool, doc *yaml.Node) error {
rNode := &yaml.RNode{}
rNode.SetYNode(doc)
useJSONEncoder := forceJSON
if !forceJSON {
str, err := rNode.String()
if err != nil {
return errors.Wrap(err)
}
useJSONEncoder = json.Valid([]byte(str))
}
if useJSONEncoder {
je := json.NewEncoder(w.Writer)
je.SetIndent("", " ")
return errors.Wrap(je.Encode(rNode))
}
return encoder.Encode(doc)
}

View File

@@ -198,9 +198,9 @@ metadata:
items: []string{ items: []string{
`{ `{
"a": "a long string that would certainly see a newline introduced by the YAML marshaller abcd123", "a": "a long string that would certainly see a newline introduced by the YAML marshaller abcd123",
"metadata": { metadata: {
"annotations": { annotations: {
"config.kubernetes.io/path": "test.json" config.kubernetes.io/path: test.json
} }
} }
}`, }`,
@@ -215,6 +215,65 @@ metadata:
} }
}`, }`,
}, },
//
// Test Case
//
{
name: "encode_wrapped_json_as_yaml",
instance: ByteWriter{
Sort: true,
WrappingKind: ResourceListKind,
WrappingAPIVersion: ResourceListAPIVersion,
},
items: []string{
`{
"a": "b",
"metadata": {
"annotations": {
"config.kubernetes.io/path": "test.json"
}
}
}`,
},
expectedOutput: `apiVersion: config.kubernetes.io/v1alpha1
kind: ResourceList
items:
- {"a": "b", "metadata": {"annotations": {"config.kubernetes.io/path": "test.json"}}}
`,
},
//
// Test Case
//
{
name: "encode_multi_doc_json_as_yaml",
items: []string{
`{
"a": "b",
"metadata": {
"annotations": {
"config.kubernetes.io/path": "test-1.json"
}
}
}`,
`{
"c": "d",
"metadata": {
"annotations": {
"config.kubernetes.io/path": "test-2.json"
}
}
}`,
},
expectedOutput: `
{"a": "b", "metadata": {"annotations": {"config.kubernetes.io/path": "test-1.json"}}}
---
{"c": "d", "metadata": {"annotations": {"config.kubernetes.io/path": "test-2.json"}}}
`,
},
} }
for i := range testCases { for i := range testCases {