...

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

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

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package yaml
     5  
     6  import (
     7  	"bytes"
     8  	"strings"
     9  
    10  	"sigs.k8s.io/kustomize/kyaml/errors"
    11  	"sigs.k8s.io/kustomize/kyaml/sets"
    12  	yaml "sigs.k8s.io/yaml/goyaml.v3"
    13  )
    14  
    15  // CopyYNode returns a distinct copy of its argument.
    16  // Use https://github.com/jinzhu/copier instead?
    17  func CopyYNode(n *yaml.Node) *yaml.Node {
    18  	if n == nil {
    19  		return nil
    20  	}
    21  	c := *n
    22  	if len(n.Content) > 0 {
    23  		// Using Go 'copy' here doesn't yield independent slices.
    24  		c.Content = make([]*Node, len(n.Content))
    25  		for i, item := range n.Content {
    26  			c.Content[i] = CopyYNode(item)
    27  		}
    28  	}
    29  	return &c
    30  }
    31  
    32  // IsYNodeTaggedNull returns true if the node is explicitly tagged Null.
    33  func IsYNodeTaggedNull(n *yaml.Node) bool {
    34  	return n != nil && n.Tag == NodeTagNull
    35  }
    36  
    37  // IsYNodeEmptyMap is true if the Node is a non-nil empty map.
    38  func IsYNodeEmptyMap(n *yaml.Node) bool {
    39  	return n != nil && n.Kind == yaml.MappingNode && len(n.Content) == 0
    40  }
    41  
    42  // IsYNodeEmptySeq is true if the Node is a non-nil empty sequence.
    43  func IsYNodeEmptySeq(n *yaml.Node) bool {
    44  	return n != nil && n.Kind == yaml.SequenceNode && len(n.Content) == 0
    45  }
    46  
    47  // IsYNodeNilOrEmpty is true if the Node is nil or appears empty.
    48  func IsYNodeNilOrEmpty(n *yaml.Node) bool {
    49  	return n == nil ||
    50  		IsYNodeTaggedNull(n) ||
    51  		IsYNodeEmptyMap(n) ||
    52  		IsYNodeEmptySeq(n) ||
    53  		IsYNodeZero(n)
    54  }
    55  
    56  // IsYNodeEmptyDoc is true if the node is a Document with no content.
    57  // E.g.: "---\n---"
    58  func IsYNodeEmptyDoc(n *yaml.Node) bool {
    59  	return n.Kind == yaml.DocumentNode && n.Content[0].Tag == NodeTagNull
    60  }
    61  
    62  func IsYNodeString(n *yaml.Node) bool {
    63  	return n.Kind == yaml.ScalarNode &&
    64  		(n.Tag == NodeTagString || n.Tag == NodeTagEmpty)
    65  }
    66  
    67  // IsYNodeZero is true if all the public fields in the Node are empty.
    68  // Which means it's not initialized and should be omitted when marshal.
    69  // The Node itself has a method IsZero but it is not released
    70  // in yaml.v3. https://pkg.go.dev/gopkg.in/yaml.v3#Node.IsZero
    71  func IsYNodeZero(n *yaml.Node) bool {
    72  	// TODO: Change this to use IsZero when it's avaialable.
    73  	return n != nil && n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" &&
    74  		n.Anchor == "" && n.Alias == nil && n.Content == nil &&
    75  		n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" &&
    76  		n.Line == 0 && n.Column == 0
    77  }
    78  
    79  // Parser parses values into configuration.
    80  type Parser struct {
    81  	Kind  string `yaml:"kind,omitempty"`
    82  	Value string `yaml:"value,omitempty"`
    83  }
    84  
    85  func (p Parser) Filter(_ *RNode) (*RNode, error) {
    86  	d := yaml.NewDecoder(bytes.NewBuffer([]byte(p.Value)))
    87  	o := &RNode{value: &yaml.Node{}}
    88  	return o, d.Decode(o.value)
    89  }
    90  
    91  // TODO(pwittrock): test this
    92  func GetStyle(styles ...string) Style {
    93  	var style Style
    94  	for _, s := range styles {
    95  		switch s {
    96  		case "TaggedStyle":
    97  			style |= TaggedStyle
    98  		case "DoubleQuotedStyle":
    99  			style |= DoubleQuotedStyle
   100  		case "SingleQuotedStyle":
   101  			style |= SingleQuotedStyle
   102  		case "LiteralStyle":
   103  			style |= LiteralStyle
   104  		case "FoldedStyle":
   105  			style |= FoldedStyle
   106  		case "FlowStyle":
   107  			style |= FlowStyle
   108  		}
   109  	}
   110  	return style
   111  }
   112  
   113  // Filter defines a function to manipulate an individual RNode such as by changing
   114  // its values, or returning a field.
   115  //
   116  // When possible, Filters should be serializable to yaml so that they can be described
   117  // declaratively as data.
   118  //
   119  // Analogous to http://www.linfo.org/filters.html
   120  type Filter interface {
   121  	Filter(object *RNode) (*RNode, error)
   122  }
   123  
   124  type FilterFunc func(object *RNode) (*RNode, error)
   125  
   126  func (f FilterFunc) Filter(object *RNode) (*RNode, error) {
   127  	return f(object)
   128  }
   129  
   130  // TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
   131  // No need for a direct dependence; the fields are stable.
   132  type TypeMeta struct {
   133  	// APIVersion is the apiVersion field of a Resource
   134  	APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
   135  	// Kind is the kind field of a Resource
   136  	Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
   137  }
   138  
   139  // NameMeta contains name information.
   140  type NameMeta struct {
   141  	// Name is the metadata.name field of a Resource
   142  	Name string `json:"name,omitempty" yaml:"name,omitempty"`
   143  	// Namespace is the metadata.namespace field of a Resource
   144  	Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
   145  }
   146  
   147  // ResourceMeta contains the metadata for a both Resource Type and Resource.
   148  type ResourceMeta struct {
   149  	TypeMeta `json:",inline" yaml:",inline"`
   150  	// ObjectMeta is the metadata field of a Resource
   151  	ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
   152  }
   153  
   154  // ObjectMeta contains metadata about a Resource
   155  type ObjectMeta struct {
   156  	NameMeta `json:",inline" yaml:",inline"`
   157  	// Labels is the metadata.labels field of a Resource
   158  	Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
   159  	// Annotations is the metadata.annotations field of a Resource.
   160  	Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
   161  }
   162  
   163  // GetIdentifier returns a ResourceIdentifier that includes
   164  // the information needed to uniquely identify a resource in a cluster.
   165  func (m *ResourceMeta) GetIdentifier() ResourceIdentifier {
   166  	return ResourceIdentifier{
   167  		TypeMeta: m.TypeMeta,
   168  		NameMeta: m.NameMeta,
   169  	}
   170  }
   171  
   172  // ResourceIdentifier contains the information needed to uniquely
   173  // identify a resource in a cluster.
   174  type ResourceIdentifier struct {
   175  	TypeMeta `json:",inline" yaml:",inline"`
   176  	NameMeta `json:",inline" yaml:",inline"`
   177  }
   178  
   179  // Comments struct is comment yaml comment types
   180  type Comments struct {
   181  	LineComment string `yaml:"lineComment,omitempty"`
   182  	HeadComment string `yaml:"headComment,omitempty"`
   183  	FootComment string `yaml:"footComment,omitempty"`
   184  }
   185  
   186  func (r *ResourceIdentifier) GetName() string {
   187  	return r.Name
   188  }
   189  
   190  func (r *ResourceIdentifier) GetNamespace() string {
   191  	return r.Namespace
   192  }
   193  
   194  func (r *ResourceIdentifier) GetAPIVersion() string {
   195  	return r.APIVersion
   196  }
   197  
   198  func (r *ResourceIdentifier) GetKind() string {
   199  	return r.Kind
   200  }
   201  
   202  const (
   203  	Trim = "Trim"
   204  	Flow = "Flow"
   205  )
   206  
   207  // String returns a string value for a Node, applying the supplied formatting options
   208  func String(node *yaml.Node, opts ...string) (string, error) {
   209  	if node == nil {
   210  		return "", nil
   211  	}
   212  	optsSet := sets.String{}
   213  	optsSet.Insert(opts...)
   214  	if optsSet.Has(Flow) {
   215  		oldStyle := node.Style
   216  		defer func() {
   217  			node.Style = oldStyle
   218  		}()
   219  		node.Style = yaml.FlowStyle
   220  	}
   221  
   222  	b := &bytes.Buffer{}
   223  	e := NewEncoder(b)
   224  	err := e.Encode(node)
   225  	errClose := e.Close()
   226  	if err == nil {
   227  		err = errClose
   228  	}
   229  	val := b.String()
   230  	if optsSet.Has(Trim) {
   231  		val = strings.TrimSpace(val)
   232  	}
   233  	return val, errors.Wrap(err)
   234  }
   235  
   236  // MergeOptionsListIncreaseDirection is the type of list growth in merge
   237  type MergeOptionsListIncreaseDirection int
   238  
   239  const (
   240  	MergeOptionsListAppend MergeOptionsListIncreaseDirection = iota
   241  	MergeOptionsListPrepend
   242  )
   243  
   244  // MergeOptions is a struct which contains the options for merge
   245  type MergeOptions struct {
   246  	// ListIncreaseDirection indicates should merge function prepend the items from
   247  	// source list to destination or append.
   248  	ListIncreaseDirection MergeOptionsListIncreaseDirection
   249  }
   250  
   251  // Since ObjectMeta and TypeMeta are stable, we manually create DeepCopy funcs for ResourceMeta and ObjectMeta.
   252  // For TypeMeta and NameMeta no DeepCopy funcs are required, as they only contain basic types.
   253  
   254  // DeepCopyInto copies the receiver, writing into out. in must be non-nil.
   255  func (in *ObjectMeta) DeepCopyInto(out *ObjectMeta) {
   256  	*out = *in
   257  	out.NameMeta = in.NameMeta
   258  	if in.Labels != nil {
   259  		in, out := &in.Labels, &out.Labels
   260  		*out = make(map[string]string, len(*in))
   261  		for key, val := range *in {
   262  			(*out)[key] = val
   263  		}
   264  	}
   265  	if in.Annotations != nil {
   266  		in, out := &in.Annotations, &out.Annotations
   267  		*out = make(map[string]string, len(*in))
   268  		for key, val := range *in {
   269  			(*out)[key] = val
   270  		}
   271  	}
   272  }
   273  
   274  // DeepCopy copies the receiver, creating a new ObjectMeta.
   275  func (in *ObjectMeta) DeepCopy() *ObjectMeta {
   276  	if in == nil {
   277  		return nil
   278  	}
   279  	out := new(ObjectMeta)
   280  	in.DeepCopyInto(out)
   281  	return out
   282  }
   283  
   284  // DeepCopyInto copies the receiver, writing into out. in must be non-nil.
   285  func (in *ResourceMeta) DeepCopyInto(out *ResourceMeta) {
   286  	*out = *in
   287  	out.TypeMeta = in.TypeMeta
   288  	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
   289  }
   290  
   291  // DeepCopy copies the receiver, creating a new ResourceMeta.
   292  func (in *ResourceMeta) DeepCopy() *ResourceMeta {
   293  	if in == nil {
   294  		return nil
   295  	}
   296  	out := new(ResourceMeta)
   297  	in.DeepCopyInto(out)
   298  	return out
   299  }
   300  

View as plain text