...

Source file src/sigs.k8s.io/kustomize/kyaml/yaml/merge3/visitor.go

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

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package merge3
     5  
     6  import (
     7  	"sigs.k8s.io/kustomize/kyaml/openapi"
     8  	"sigs.k8s.io/kustomize/kyaml/yaml"
     9  	"sigs.k8s.io/kustomize/kyaml/yaml/walk"
    10  )
    11  
    12  type ConflictStrategy uint
    13  
    14  const (
    15  	// TODO: Support more strategies
    16  	TakeUpdate ConflictStrategy = 1 + iota
    17  )
    18  
    19  type Visitor struct{}
    20  
    21  func (m Visitor) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
    22  	if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() {
    23  		// explicitly cleared from either dest or update
    24  		return walk.ClearNode, nil
    25  	}
    26  	if nodes.Dest() == nil && nodes.Updated() == nil {
    27  		// implicitly cleared missing from both dest and update
    28  		return walk.ClearNode, nil
    29  	}
    30  
    31  	if nodes.Dest() == nil {
    32  		// not cleared, but missing from the dest
    33  		// initialize a new value that can be recursively merged
    34  		return yaml.NewRNode(&yaml.Node{Kind: yaml.MappingNode}), nil
    35  	}
    36  
    37  	// recursively merge the dest with the original and updated
    38  	return nodes.Dest(), nil
    39  }
    40  
    41  func (m Visitor) visitAList(nodes walk.Sources, _ *openapi.ResourceSchema) (*yaml.RNode, error) {
    42  	if yaml.IsMissingOrNull(nodes.Updated()) && !yaml.IsMissingOrNull(nodes.Origin()) {
    43  		// implicitly cleared from update -- element was deleted
    44  		return walk.ClearNode, nil
    45  	}
    46  	if yaml.IsMissingOrNull(nodes.Dest()) {
    47  		// not cleared, but missing from the dest
    48  		// initialize a new value that can be recursively merged
    49  		return yaml.NewRNode(&yaml.Node{Kind: yaml.SequenceNode}), nil
    50  	}
    51  
    52  	// recursively merge the dest with the original and updated
    53  	return nodes.Dest(), nil
    54  }
    55  
    56  func (m Visitor) VisitScalar(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) {
    57  	if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() {
    58  		// explicitly cleared from either dest or update
    59  		return nil, nil
    60  	}
    61  	if yaml.IsMissingOrNull(nodes.Updated()) != yaml.IsMissingOrNull(nodes.Origin()) {
    62  		// value added or removed in update
    63  		return nodes.Updated(), nil
    64  	}
    65  	if yaml.IsMissingOrNull(nodes.Updated()) && yaml.IsMissingOrNull(nodes.Origin()) {
    66  		// value added or removed in update
    67  		return nodes.Dest(), nil
    68  	}
    69  
    70  	values, err := m.getStrValues(nodes)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	if (values.Dest == "" || values.Dest == values.Origin) && values.Origin != values.Update {
    76  		// if local is nil or is unchanged but there is new update
    77  		return nodes.Updated(), nil
    78  	}
    79  
    80  	if nodes.Updated().YNode().Value != nodes.Origin().YNode().Value {
    81  		// value changed in update
    82  		return nodes.Updated(), nil
    83  	}
    84  
    85  	// unchanged between origin and update, keep the dest
    86  	return nodes.Dest(), nil
    87  }
    88  
    89  func (m Visitor) visitNAList(nodes walk.Sources) (*yaml.RNode, error) {
    90  	if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() {
    91  		// explicitly cleared from either dest or update
    92  		return walk.ClearNode, nil
    93  	}
    94  
    95  	if yaml.IsMissingOrNull(nodes.Updated()) != yaml.IsMissingOrNull(nodes.Origin()) {
    96  		// value added or removed in update
    97  		return nodes.Updated(), nil
    98  	}
    99  	if yaml.IsMissingOrNull(nodes.Updated()) && yaml.IsMissingOrNull(nodes.Origin()) {
   100  		// value not present in source or dest
   101  		return nodes.Dest(), nil
   102  	}
   103  
   104  	// compare origin and update values to see if they have changed
   105  	values, err := m.getStrValues(nodes)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	if values.Update != values.Origin {
   110  		// value changed in update
   111  		return nodes.Updated(), nil
   112  	}
   113  
   114  	// unchanged between origin and update, keep the dest
   115  	return nodes.Dest(), nil
   116  }
   117  
   118  func (m Visitor) VisitList(nodes walk.Sources, s *openapi.ResourceSchema, kind walk.ListKind) (*yaml.RNode, error) {
   119  	if kind == walk.AssociativeList {
   120  		return m.visitAList(nodes, s)
   121  	}
   122  	// non-associative list
   123  	return m.visitNAList(nodes)
   124  }
   125  
   126  func (m Visitor) getStrValues(nodes walk.Sources) (strValues, error) {
   127  	var uStr, oStr, dStr string
   128  	var err error
   129  	if nodes.Updated() != nil && nodes.Updated().YNode() != nil {
   130  		s := nodes.Updated().YNode().Style
   131  		defer func() {
   132  			nodes.Updated().YNode().Style = s
   133  		}()
   134  		nodes.Updated().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle
   135  		uStr, err = nodes.Updated().String()
   136  		if err != nil {
   137  			return strValues{}, err
   138  		}
   139  	}
   140  	if nodes.Origin() != nil && nodes.Origin().YNode() != nil {
   141  		s := nodes.Origin().YNode().Style
   142  		defer func() {
   143  			nodes.Origin().YNode().Style = s
   144  		}()
   145  		nodes.Origin().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle
   146  		oStr, err = nodes.Origin().String()
   147  		if err != nil {
   148  			return strValues{}, err
   149  		}
   150  	}
   151  	if nodes.Dest() != nil && nodes.Dest().YNode() != nil {
   152  		s := nodes.Dest().YNode().Style
   153  		defer func() {
   154  			nodes.Dest().YNode().Style = s
   155  		}()
   156  		nodes.Dest().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle
   157  		dStr, err = nodes.Dest().String()
   158  		if err != nil {
   159  			return strValues{}, err
   160  		}
   161  	}
   162  
   163  	return strValues{Origin: oStr, Update: uStr, Dest: dStr}, nil
   164  }
   165  
   166  type strValues struct {
   167  	Origin string
   168  	Update string
   169  	Dest   string
   170  }
   171  
   172  var _ walk.Visitor = Visitor{}
   173  

View as plain text