...

Source file src/sigs.k8s.io/kustomize/kyaml/yaml/merge2/smpdirective.go

Documentation: sigs.k8s.io/kustomize/kyaml/yaml/merge2

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package merge2
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"sigs.k8s.io/kustomize/kyaml/yaml"
    10  )
    11  
    12  // A strategic merge patch directive.
    13  // See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
    14  //
    15  //go:generate stringer -type=smpDirective -linecomment
    16  type smpDirective int
    17  
    18  const (
    19  	smpUnknown smpDirective = iota // unknown
    20  	smpReplace                     // replace
    21  	smpDelete                      // delete
    22  	smpMerge                       // merge
    23  )
    24  
    25  const strategicMergePatchDirectiveKey = "$patch"
    26  
    27  // Examine patch for a strategic merge patch directive.
    28  // If found, return it, and remove the directive from the patch.
    29  func determineSmpDirective(patch *yaml.RNode) (smpDirective, error) {
    30  	if patch == nil {
    31  		return smpMerge, nil
    32  	}
    33  	switch patch.YNode().Kind {
    34  	case yaml.SequenceNode:
    35  		return determineSequenceNodePatchStrategy(patch)
    36  	case yaml.MappingNode:
    37  		return determineMappingNodePatchStrategy(patch)
    38  	default:
    39  		return smpUnknown, fmt.Errorf(
    40  			"no implemented strategic merge patch strategy for '%s' ('%s')",
    41  			patch.YNode().ShortTag(), patch.MustString())
    42  	}
    43  }
    44  
    45  func determineSequenceNodePatchStrategy(patch *yaml.RNode) (smpDirective, error) {
    46  	// get the $patch element
    47  	node, err := patch.Pipe(yaml.GetElementByKey(strategicMergePatchDirectiveKey))
    48  	// if there are more than 1 key/value pair in the map, then this $patch
    49  	// is not for the sequence
    50  	if err != nil || node == nil || node.YNode() == nil || len(node.Content()) > 2 {
    51  		return smpMerge, nil
    52  	}
    53  	// get the value
    54  	value, err := node.Pipe(yaml.Get(strategicMergePatchDirectiveKey))
    55  	if err != nil || value == nil || value.YNode() == nil {
    56  		return smpMerge, nil
    57  	}
    58  	v := value.YNode().Value
    59  	if v == smpDelete.String() {
    60  		return smpDelete, elideSequencePatchDirective(patch, v)
    61  	}
    62  	if v == smpReplace.String() {
    63  		return smpReplace, elideSequencePatchDirective(patch, v)
    64  	}
    65  	if v == smpMerge.String() {
    66  		return smpMerge, elideSequencePatchDirective(patch, v)
    67  	}
    68  	return smpUnknown, fmt.Errorf(
    69  		"unknown patch strategy '%s'", v)
    70  }
    71  
    72  func determineMappingNodePatchStrategy(patch *yaml.RNode) (smpDirective, error) {
    73  	node, err := patch.Pipe(yaml.Get(strategicMergePatchDirectiveKey))
    74  	if err != nil || node == nil || node.YNode() == nil {
    75  		return smpMerge, nil
    76  	}
    77  	v := node.YNode().Value
    78  	if v == smpDelete.String() {
    79  		return smpDelete, elideMappingPatchDirective(patch)
    80  	}
    81  	if v == smpReplace.String() {
    82  		return smpReplace, elideMappingPatchDirective(patch)
    83  	}
    84  	if v == smpMerge.String() {
    85  		return smpMerge, elideMappingPatchDirective(patch)
    86  	}
    87  	return smpUnknown, fmt.Errorf(
    88  		"unknown patch strategy '%s'", v)
    89  }
    90  
    91  func elideMappingPatchDirective(patch *yaml.RNode) error {
    92  	return patch.PipeE(yaml.Clear(strategicMergePatchDirectiveKey))
    93  }
    94  
    95  func elideSequencePatchDirective(patch *yaml.RNode, value string) error {
    96  	return patch.PipeE(yaml.ElementSetter{
    97  		Element: nil,
    98  		Keys:    []string{strategicMergePatchDirectiveKey},
    99  		Values:  []string{value},
   100  	})
   101  }
   102  

View as plain text