...

Source file src/sigs.k8s.io/kustomize/api/types/fieldspec.go

Documentation: sigs.k8s.io/kustomize/api/types

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package types
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"sigs.k8s.io/kustomize/kyaml/resid"
    10  )
    11  
    12  // FieldSpec completely specifies a kustomizable field in a k8s API object.
    13  // It helps define the operands of transformations.
    14  //
    15  // For example, a directive to add a common label to objects
    16  // will need to know that a 'Deployment' object (in API group
    17  // 'apps', any version) can have labels at field path
    18  // 'spec/template/metadata/labels', and further that it is OK
    19  // (or not OK) to add that field path to the object if the
    20  // field path doesn't exist already.
    21  //
    22  // This would look like
    23  // {
    24  //   group: apps
    25  //   kind: Deployment
    26  //   path: spec/template/metadata/labels
    27  //   create: true
    28  // }
    29  type FieldSpec struct {
    30  	resid.Gvk          `json:",inline,omitempty" yaml:",inline,omitempty"`
    31  	Path               string `json:"path,omitempty" yaml:"path,omitempty"`
    32  	CreateIfNotPresent bool   `json:"create,omitempty" yaml:"create,omitempty"`
    33  
    34  	// Note: If any new pointer based members are added, FsSlice.DeepCopy needs to be updated
    35  }
    36  
    37  func (fs FieldSpec) String() string {
    38  	return fmt.Sprintf(
    39  		"%s:%v:%s", fs.Gvk.String(), fs.CreateIfNotPresent, fs.Path)
    40  }
    41  
    42  // If true, the primary key is the same, but other fields might not be.
    43  func (fs FieldSpec) effectivelyEquals(other FieldSpec) bool {
    44  	return fs.IsSelected(&other.Gvk) && fs.Path == other.Path
    45  }
    46  
    47  type FsSlice []FieldSpec
    48  
    49  func (s FsSlice) Len() int      { return len(s) }
    50  func (s FsSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    51  func (s FsSlice) Less(i, j int) bool {
    52  	return s[i].Gvk.IsLessThan(s[j].Gvk)
    53  }
    54  
    55  // DeepCopy returns a new copy of FsSlice
    56  func (s FsSlice) DeepCopy() FsSlice {
    57  	ret := make(FsSlice, len(s))
    58  	copy(ret, s)
    59  	return ret
    60  }
    61  
    62  // MergeAll merges the argument into this, returning the result.
    63  // Items already present are ignored.
    64  // Items that conflict (primary key matches, but remain data differs)
    65  // result in an error.
    66  func (s FsSlice) MergeAll(incoming FsSlice) (result FsSlice, err error) {
    67  	result = s
    68  	for _, x := range incoming {
    69  		result, err = result.MergeOne(x)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  	}
    74  	return result, nil
    75  }
    76  
    77  // MergeOne merges the argument into this, returning the result.
    78  // If the item's primary key is already present, and there are no
    79  // conflicts, it is ignored (we don't want duplicates).
    80  // If there is a conflict, the merge fails.
    81  func (s FsSlice) MergeOne(x FieldSpec) (FsSlice, error) {
    82  	i := s.index(x)
    83  	if i > -1 {
    84  		// It's already there.
    85  		if s[i].CreateIfNotPresent != x.CreateIfNotPresent {
    86  			return nil, fmt.Errorf("conflicting fieldspecs")
    87  		}
    88  		return s, nil
    89  	}
    90  	return append(s, x), nil
    91  }
    92  
    93  func (s FsSlice) index(fs FieldSpec) int {
    94  	for i, x := range s {
    95  		if x.effectivelyEquals(fs) {
    96  			return i
    97  		}
    98  	}
    99  	return -1
   100  }
   101  

View as plain text