k3s/vendor/sigs.k8s.io/kustomize/kyaml/yaml/walk/map.go

174 lines
4.5 KiB
Go
Raw Normal View History

// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package walk
import (
"sort"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/sets"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// walkMap returns the value of VisitMap
//
// - call VisitMap
// - set the return value on l.Dest
// - walk each source field
// - set each source field value on l.Dest
func (l Walker) walkMap() (*yaml.RNode, error) {
// get the new map value
dest, err := l.Sources.setDestNode(l.VisitMap(l.Sources, l.Schema))
if dest == nil || err != nil {
return nil, err
}
// recursively set the field values on the map
for _, key := range l.fieldNames() {
var res *yaml.RNode
var keys []*yaml.RNode
if l.VisitKeysAsScalars {
// visit the map keys as if they were scalars,
// this is necessary if doing things such as copying
// comments
for i := range l.Sources {
// construct the sources from the keys
if l.Sources[i] == nil {
keys = append(keys, nil)
continue
}
field := l.Sources[i].Field(key)
if field == nil || yaml.IsMissingOrNull(field.Key) {
keys = append(keys, nil)
continue
}
keys = append(keys, field.Key)
}
// visit the sources as a scalar
// keys don't have any schema --pass in nil
res, err = l.Visitor.VisitScalar(keys, nil)
if err != nil {
return nil, err
}
}
var s *openapi.ResourceSchema
if l.Schema != nil {
s = l.Schema.Field(key)
}
fv, commentSch := l.fieldValue(key)
if commentSch != nil {
s = commentSch
}
val, err := Walker{
VisitKeysAsScalars: l.VisitKeysAsScalars,
InferAssociativeLists: l.InferAssociativeLists,
Visitor: l,
Schema: s,
Sources: fv,
MergeOptions: l.MergeOptions,
Path: append(l.Path, key)}.Walk()
if err != nil {
return nil, err
}
// transfer the comments of res to dest node
var comments yaml.Comments
if !yaml.IsMissingOrNull(res) {
comments = yaml.Comments{
LineComment: res.YNode().LineComment,
HeadComment: res.YNode().HeadComment,
FootComment: res.YNode().FootComment,
}
if len(keys) > 0 && !yaml.IsMissingOrNull(keys[DestIndex]) {
keys[DestIndex].YNode().HeadComment = res.YNode().HeadComment
keys[DestIndex].YNode().LineComment = res.YNode().LineComment
keys[DestIndex].YNode().FootComment = res.YNode().FootComment
}
}
// this handles empty and non-empty values
_, err = dest.Pipe(yaml.FieldSetter{Name: key, Comments: comments, Value: val})
if err != nil {
return nil, err
}
}
return dest, nil
}
// valueIfPresent returns node.Value if node is non-nil, otherwise returns nil
func (l Walker) valueIfPresent(node *yaml.MapNode) (*yaml.RNode, *openapi.ResourceSchema) {
if node == nil {
return nil, nil
}
// parse the schema for the field if present
var s *openapi.ResourceSchema
fm := fieldmeta.FieldMeta{}
var err error
// check the value for a schema
if err = fm.Read(node.Value); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref, openapi.Schema())
if err == nil && r != nil {
s.Schema = r
}
}
}
// check the key for a schema -- this will be used
// when the value is a Sequence (comments are attached)
// to the key
if fm.IsEmpty() {
if err = fm.Read(node.Key); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref, openapi.Schema())
if err == nil && r != nil {
s.Schema = r
}
}
}
return node.Value, s
}
// fieldNames returns a sorted slice containing the names of all fields that appear in any of
// the sources
func (l Walker) fieldNames() []string {
fields := sets.String{}
for _, s := range l.Sources {
if s == nil {
continue
}
// don't check error, we know this is a mapping node
sFields, _ := s.Fields()
fields.Insert(sFields...)
}
result := fields.List()
sort.Strings(result)
return result
}
// fieldValue returns a slice containing each source's value for fieldName
func (l Walker) fieldValue(fieldName string) ([]*yaml.RNode, *openapi.ResourceSchema) {
var fields []*yaml.RNode
var sch *openapi.ResourceSchema
for i := range l.Sources {
if l.Sources[i] == nil {
fields = append(fields, nil)
continue
}
field := l.Sources[i].Field(fieldName)
f, s := l.valueIfPresent(field)
fields = append(fields, f)
if sch == nil && !s.IsMissingOrNull() {
sch = s
}
}
return fields, sch
}