mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
174 lines
4.5 KiB
Go
174 lines
4.5 KiB
Go
|
// 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
|
||
|
}
|