Files
kustomize/kyaml/fieldmeta/fieldmeta.go
2019-12-17 11:50:18 -08:00

138 lines
3.6 KiB
Go

// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fieldmeta
import (
"bytes"
"encoding/json"
"strconv"
"strings"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// FieldMeta contains metadata that may be attached to fields as comments
type FieldMeta struct {
// Substitutions are substitutions that may be performed against this field
Substitutions []Substitution `yaml:"substitutions,omitempty" json:"substitutions,omitempty"`
// OwnedBy records the owner of this field
OwnedBy string `yaml:"setBy,omitempty" json:"setBy,omitempty"`
// DefaultedBy records that this field was default, but may be changed by other owners
DefaultedBy string `yaml:"defaultedBy,omitempty" json:"defaultedBy,omitempty"`
// Description is a description of the current field value, e.g. why it was set
Description string `yaml:"description,omitempty" json:"description,omitempty"`
// Type is the type of the field value
Type FieldValueType `yaml:"type,omitempty" json:"type,omitempty"`
}
// Substitution defines a substitution that may be performed against the field
type Substitution struct {
// Name is the name of the substitution and read by tools
Name string `yaml:"name,omitempty" json:"name,omitempty"`
// Marker is the marker used for replacement
Marker string `yaml:"marker,omitempty" json:"marker,omitempty"`
// Value is the current value that has been substituted for the Marker
Value string `yaml:"value,omitempty" json:"value,omitempty"`
}
// Read reads the FieldMeta from a node
func (fm *FieldMeta) Read(n *yaml.RNode) error {
if n.YNode().LineComment != "" {
v := strings.TrimLeft(n.YNode().LineComment, "#")
// if it doesn't Unmarshal that is fine, it means there is no metadata
// other comments are valid, they just don't parse
d := yaml.NewDecoder(bytes.NewBuffer([]byte(v)))
d.KnownFields(false)
_ = d.Decode(fm)
}
return nil
}
// Write writes the FieldMeta to a node
func (fm *FieldMeta) Write(n *yaml.RNode) error {
b, err := json.Marshal(fm)
if err != nil {
return err
}
n.YNode().LineComment = string(b)
return nil
}
// FieldValueType defines the type of input to register
type FieldValueType string
const (
// String defines a string flag
String FieldValueType = "string"
// Bool defines a bool flag
Bool = "bool"
// Float defines a float flag
Float = "float"
// Int defines an int flag
Int = "int"
)
func (it FieldValueType) String() string {
if it == "" {
return "string"
}
return string(it)
}
func (it FieldValueType) Validate(value string) error {
switch it {
case Int:
if _, err := strconv.Atoi(value); err != nil {
return errors.WrapPrefixf(err, "value must be an int")
}
case Bool:
if _, err := strconv.ParseBool(value); err != nil {
return errors.WrapPrefixf(err, "value must be a bool")
}
case Float:
if _, err := strconv.ParseFloat(value, 64); err != nil {
return errors.WrapPrefixf(err, "value must be a float")
}
}
return nil
}
func (it FieldValueType) Tag() string {
switch it {
case String:
return "!!str"
case Bool:
return "!!bool"
case Int:
return "!!int"
case Float:
return "!!float"
}
return ""
}
func (it FieldValueType) TagForValue(value string) string {
switch it {
case String:
return "!!str"
case Bool:
if _, err := strconv.ParseBool(string(it)); err != nil {
return ""
}
return "!!bool"
case Int:
if _, err := strconv.ParseInt(string(it), 0, 32); err != nil {
return ""
}
return "!!int"
case Float:
if _, err := strconv.ParseFloat(string(it), 64); err != nil {
return ""
}
return "!!float"
}
return ""
}