custom-targets/util/applysetters/walk.go (45 lines of code) (raw):
/*
Copyright 2023 The Skaffold Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package applysetters
import (
"fmt"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// visitor is implemented by structs which need to walk the configuration.
// visitor is provided to accept to walk configuration
type visitor interface {
// visitScalar is called for each scalar field value on a resource
// node is the scalar field value
// path is the path to the field; path elements are separated by '.'
visitScalar(node *yaml.RNode, path string) error
// visitMapping is called for each Mapping field value on a resource
// node is the mapping field value
// path is the path to the field
visitMapping(node *yaml.RNode, path string) error
}
// accept invokes the appropriate function on v for each field in object
func accept(v visitor, object *yaml.RNode) error {
// get the OpenAPI for the type if it exists
return acceptImpl(v, object, "")
}
// acceptImpl implements accept using recursion
func acceptImpl(v visitor, object *yaml.RNode, p string) error {
switch object.YNode().Kind {
case yaml.DocumentNode:
// Traverse the child of the document
return accept(v, yaml.NewRNode(object.YNode()))
case yaml.MappingNode:
if err := v.visitMapping(object, p); err != nil {
return err
}
return object.VisitFields(func(node *yaml.MapNode) error {
// Traverse each field value
return acceptImpl(v, node.Value, p+"."+node.Key.YNode().Value)
})
case yaml.SequenceNode:
return VisitElements(object, func(node *yaml.RNode, i int) error {
// Traverse each list element
return acceptImpl(v, node, p+fmt.Sprintf("[%d]", i))
})
case yaml.ScalarNode:
// Visit the scalar field
return v.visitScalar(object, p)
}
return nil
}
// VisitElements calls fn for each element in a SequenceNode.
// Returns an error for non-SequenceNodes
func VisitElements(rn *yaml.RNode, fn func(node *yaml.RNode, i int) error) error {
elements, err := rn.Elements()
if err != nil {
return errors.Wrap(err)
}
for i := range elements {
if err := fn(elements[i], i); err != nil {
return errors.Wrap(err)
}
}
return nil
}