Parse metadata directly instead of struct serialization hack

This commit is contained in:
Phillip Wittrock
2020-01-07 12:53:23 -08:00
parent e619cec090
commit 4628705494
2 changed files with 125 additions and 13 deletions

View File

@@ -6,7 +6,6 @@ package yaml
import (
"bytes"
"fmt"
"reflect"
"strings"
"gopkg.in/yaml.v3"
@@ -70,6 +69,14 @@ func IsFieldEmpty(node *MapNode) bool {
return false
}
// GetValue returns underlying yaml.Node Value field
func GetValue(node *RNode) string {
if IsEmpty(node) {
return ""
}
return node.YNode().Value
}
func IsFieldNull(node *MapNode) bool {
return node != nil && node.Value != nil && node.Value.YNode() != nil &&
node.Value.YNode().Tag == NullNodeTag
@@ -280,23 +287,79 @@ func (r *ResourceIdentifier) GetKind() string {
var ErrMissingMetadata = fmt.Errorf("missing Resource metadata")
// GetMeta returns the ResourceMeta for a RNode
// Field names
const (
AnnotationsField = "annotations"
APIVersionField = "apiVersion"
KindField = "kind"
MetadataField = "metadata"
NameField = "name"
NamespaceField = "namespace"
LabelsField = "labels"
)
// GetMeta returns the ResourceMeta for an RNode
func (rn *RNode) GetMeta() (ResourceMeta, error) {
if IsEmpty(rn) {
return ResourceMeta{}, nil
}
missingMeta := true
n := rn
if n.YNode().Kind == DocumentNode {
// get the content is this is the document node
n = NewRNode(n.Content()[0])
}
// don't decode into the struct directly or it will fail on UTF-8 issues
// which appear in comments
m := ResourceMeta{}
b := &bytes.Buffer{}
e := NewEncoder(b)
if err := e.Encode(rn.YNode()); err != nil {
return m, errors.Wrap(err)
// TODO: consider optimizing this parsing
if f := n.Field(APIVersionField); !IsFieldEmpty(f) {
m.APIVersion = GetValue(f.Value)
missingMeta = false
}
if err := e.Close(); err != nil {
return m, errors.Wrap(err)
if f := n.Field(KindField); !IsFieldEmpty(f) {
m.Kind = GetValue(f.Value)
missingMeta = false
}
d := yaml.NewDecoder(b)
d.KnownFields(false) // only want to parse the metadata
if err := d.Decode(&m); err != nil {
return m, errors.Wrap(err)
mf := n.Field(MetadataField)
if IsFieldEmpty(mf) {
if missingMeta {
return m, ErrMissingMetadata
}
return m, nil
}
if reflect.DeepEqual(m, ResourceMeta{}) {
meta := mf.Value
if f := meta.Field(NameField); !IsFieldEmpty(f) {
m.Name = f.Value.YNode().Value
missingMeta = false
}
if f := meta.Field(NamespaceField); !IsFieldEmpty(f) {
m.Namespace = GetValue(f.Value)
missingMeta = false
}
if f := meta.Field(LabelsField); !IsFieldEmpty(f) {
m.Labels = map[string]string{}
_ = f.Value.VisitFields(func(node *MapNode) error {
m.Labels[GetValue(node.Key)] = GetValue(node.Value)
return nil
})
missingMeta = false
}
if f := meta.Field(AnnotationsField); !IsFieldEmpty(f) {
m.Annotations = map[string]string{}
_ = f.Value.VisitFields(func(node *MapNode) error {
m.Annotations[GetValue(node.Key)] = GetValue(node.Value)
return nil
})
missingMeta = false
}
if missingMeta {
return m, ErrMissingMetadata
}
return m, nil