mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Merge pull request #3176 from natasha41575/ElementSetterList
add ElementSetterList and ElementMatcherList to fns.go
This commit is contained in:
@@ -228,7 +228,7 @@ func ExampleElementMatcher_Filter() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
elem, err := obj.Pipe(ElementMatcher{
|
elem, err := obj.Pipe(ElementMatcher{
|
||||||
FieldValue: "c", Create: NewScalarRNode("c"),
|
Values: []string{"c"}, Create: NewScalarRNode("c"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -255,7 +255,9 @@ func ExampleElementMatcher_Filter_primitiveFound() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
elem, err := obj.Pipe(ElementMatcher{
|
elem, err := obj.Pipe(ElementMatcher{
|
||||||
FieldValue: "c", Create: NewScalarRNode("c"),
|
Keys: []string{""},
|
||||||
|
Values: []string{"c"},
|
||||||
|
Create: NewScalarRNode("c"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -287,7 +289,7 @@ image: nginx
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
elem, err := obj.Pipe(ElementMatcher{
|
elem, err := obj.Pipe(ElementMatcher{
|
||||||
FieldName: "name", FieldValue: "baz", Create: append})
|
Keys: []string{"name"}, Values: []string{"baz"}, Create: append})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -321,7 +323,7 @@ image: nginx
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
elem, err := obj.Pipe(ElementMatcher{
|
elem, err := obj.Pipe(ElementMatcher{
|
||||||
FieldName: "name", FieldValue: "baz", Create: append})
|
Keys: []string{"name"}, Values: []string{"baz"}, Create: append})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,19 +48,20 @@ func (a ElementAppender) Filter(rn *RNode) (*RNode, error) {
|
|||||||
// not designed for this purpose. To append an element, please use ElementAppender.
|
// not designed for this purpose. To append an element, please use ElementAppender.
|
||||||
// To replace, set the key-value pair and a non-nil Element.
|
// To replace, set the key-value pair and a non-nil Element.
|
||||||
// To delete, set the key-value pair and leave the Element as nil.
|
// To delete, set the key-value pair and leave the Element as nil.
|
||||||
|
// Every key must have a corresponding value.
|
||||||
type ElementSetter struct {
|
type ElementSetter struct {
|
||||||
Kind string `yaml:"kind,omitempty"`
|
Kind string `yaml:"kind,omitempty"`
|
||||||
|
|
||||||
// Element is the new value to set -- remove the existing element if nil
|
// Element is the new value to set -- remove the existing element if nil
|
||||||
Element *Node
|
Element *Node
|
||||||
|
|
||||||
// Key is a field on the elements. It is used to find the matching element to
|
// Key is a list of fields on the elements. It is used to find matching elements to
|
||||||
// update / delete.
|
// update / delete
|
||||||
Key string `yaml:"key,omitempty"`
|
Keys []string
|
||||||
|
|
||||||
// Value is a field value on the elements. It is used to find matching elements to
|
// Value is a list of field values on the elements corresponding to the keys. It is
|
||||||
// update / delete.
|
// used to find matching elements to update / delete.
|
||||||
Value string `yaml:"value,omitempty"`
|
Values []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// isMappingNode returns whether node is a mapping node
|
// isMappingNode returns whether node is a mapping node
|
||||||
@@ -70,10 +71,15 @@ func (e ElementSetter) isMappingNode(node *RNode) bool {
|
|||||||
|
|
||||||
// isMappingSetter returns is this setter intended to set a mapping node
|
// isMappingSetter returns is this setter intended to set a mapping node
|
||||||
func (e ElementSetter) isMappingSetter() bool {
|
func (e ElementSetter) isMappingSetter() bool {
|
||||||
return e.Key != "" && e.Value != ""
|
return len(e.Keys) > 0 && e.Keys[0] != "" &&
|
||||||
|
len(e.Values) > 0 && e.Values[0] != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ElementSetter) Filter(rn *RNode) (*RNode, error) {
|
func (e ElementSetter) Filter(rn *RNode) (*RNode, error) {
|
||||||
|
if len(e.Keys) == 0 {
|
||||||
|
e.Keys = append(e.Keys, "")
|
||||||
|
}
|
||||||
|
|
||||||
if err := ErrorIfInvalid(rn, SequenceNode); err != nil {
|
if err := ErrorIfInvalid(rn, SequenceNode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -96,13 +102,28 @@ func (e ElementSetter) Filter(rn *RNode) (*RNode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if this is the element we are matching
|
// check if this is the element we are matching
|
||||||
val, err := newNode.Pipe(FieldMatcher{Name: e.Key, StringValue: e.Value})
|
var val *RNode
|
||||||
if err != nil {
|
var err error
|
||||||
return nil, err
|
found := true
|
||||||
|
for j := range e.Keys {
|
||||||
|
if j >= len(e.Values) {
|
||||||
|
val, err = newNode.Pipe(FieldMatcher{Name: e.Keys[j], StringValue: ""})
|
||||||
|
} else {
|
||||||
|
val, err = newNode.Pipe(FieldMatcher{Name: e.Keys[j], StringValue: e.Values[j]})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if val == nil {
|
||||||
|
found = false
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if val == nil {
|
if !found {
|
||||||
// not the element we are looking for, keep it in the Content
|
// not the element we are looking for, keep it in the Content
|
||||||
newContent = append(newContent, elem)
|
if len(e.Values) > 0 {
|
||||||
|
newContent = append(newContent, elem)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matchingElementFound = true
|
matchingElementFound = true
|
||||||
@@ -211,49 +232,58 @@ func (c FieldClearer) Filter(rn *RNode) (*RNode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MatchElement(field, value string) ElementMatcher {
|
func MatchElement(field, value string) ElementMatcher {
|
||||||
return ElementMatcher{FieldName: field, FieldValue: value}
|
return ElementMatcher{Keys: []string{field}, Values: []string{value}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MatchElementList(keys []string, values []string) ElementMatcher {
|
||||||
|
return ElementMatcher{Keys: keys, Values: values}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetElementByKey(key string) ElementMatcher {
|
func GetElementByKey(key string) ElementMatcher {
|
||||||
return ElementMatcher{FieldName: key, MatchAnyValue: true}
|
return ElementMatcher{Keys: []string{key}, MatchAnyValue: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ElementMatcher returns the first element from a Sequence matching the
|
// ElementMatcher returns the first element from a Sequence matching the
|
||||||
// specified field's value. If there's no match, and no configuration error,
|
// specified key-value pairs. If there's no match, and no configuration error,
|
||||||
// the matcher returns nil, nil.
|
// the matcher returns nil, nil.
|
||||||
type ElementMatcher struct {
|
type ElementMatcher struct {
|
||||||
Kind string `yaml:"kind,omitempty"`
|
Kind string `yaml:"kind,omitempty"`
|
||||||
|
|
||||||
// FieldName will attempt to match this field in each list element.
|
// Keys are the list of fields upon which to match this element.
|
||||||
// Optional. Leave empty for lists of primitives (ScalarNode).
|
Keys []string
|
||||||
FieldName string `yaml:"name,omitempty"`
|
|
||||||
|
|
||||||
// FieldValue will attempt to match each element field to this value.
|
// Values are the list of values upon which to match this element.
|
||||||
// For lists of primitives, this will be used to match the primitive value.
|
Values []string
|
||||||
FieldValue string `yaml:"value,omitempty"`
|
|
||||||
|
|
||||||
// Create will create the Element if it is not found
|
// Create will create the Element if it is not found
|
||||||
Create *RNode `yaml:"create,omitempty"`
|
Create *RNode `yaml:"create,omitempty"`
|
||||||
|
|
||||||
// MatchAnyValue indicates that matcher should only consider the key and ignore
|
// MatchAnyValue indicates that matcher should only consider the key and ignore
|
||||||
// the actual value in the list. FieldValue must be empty when NoValue is
|
// the actual value in the list. Values must be empty when MatchAnyValue is
|
||||||
// set to true.
|
// set to true.
|
||||||
MatchAnyValue bool `yaml:"noValue,omitempty"`
|
MatchAnyValue bool `yaml:"noValue,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ElementMatcher) Filter(rn *RNode) (*RNode, error) {
|
func (e ElementMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||||
|
if len(e.Keys) == 0 {
|
||||||
|
e.Keys = append(e.Keys, "")
|
||||||
|
}
|
||||||
|
if len(e.Values) == 0 {
|
||||||
|
e.Values = append(e.Values, "")
|
||||||
|
}
|
||||||
|
|
||||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if e.MatchAnyValue && e.FieldValue != "" {
|
if e.MatchAnyValue && len(e.Values) != 0 && e.Values[0] != "" {
|
||||||
return nil, fmt.Errorf("FieldValue must be empty when NoValue is set to true")
|
return nil, fmt.Errorf("Values must be empty when MatchAnyValue is set to true")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SequenceNode Content is a slice of ScalarNodes. Each ScalarNode has a
|
// SequenceNode Content is a slice of ScalarNodes. Each ScalarNode has a
|
||||||
// YNode containing the primitive data.
|
// YNode containing the primitive data.
|
||||||
if len(e.FieldName) == 0 {
|
if len(e.Keys) == 0 || len(e.Keys[0]) == 0 {
|
||||||
for i := range rn.Content() {
|
for i := range rn.Content() {
|
||||||
if rn.Content()[i].Value == e.FieldValue {
|
if rn.Content()[i].Value == e.Values[0] {
|
||||||
return &RNode{value: rn.Content()[i]}, nil
|
return &RNode{value: rn.Content()[i]}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,20 +298,32 @@ func (e ElementMatcher) Filter(rn *RNode) (*RNode, error) {
|
|||||||
for i := range rn.Content() {
|
for i := range rn.Content() {
|
||||||
// cast the entry to a RNode so we can operate on it
|
// cast the entry to a RNode so we can operate on it
|
||||||
elem := NewRNode(rn.Content()[i])
|
elem := NewRNode(rn.Content()[i])
|
||||||
|
var field *RNode
|
||||||
|
var err error
|
||||||
|
|
||||||
// only check mapping node
|
// only check mapping node
|
||||||
if err := ErrorIfInvalid(elem, yaml.MappingNode); err != nil {
|
if err = ErrorIfInvalid(elem, yaml.MappingNode); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var field *RNode
|
if !e.MatchAnyValue && len(e.Keys) != len(e.Values) {
|
||||||
var err error
|
return nil, fmt.Errorf("length of keys must equal length of values when MatchAnyValue is false")
|
||||||
if e.MatchAnyValue {
|
|
||||||
field, err = elem.Pipe(Get(e.FieldName))
|
|
||||||
} else {
|
|
||||||
field, err = elem.Pipe(MatchField(e.FieldName, e.FieldValue))
|
|
||||||
}
|
}
|
||||||
if IsFoundOrError(field, err) {
|
|
||||||
|
matchesElement := true
|
||||||
|
for i := range e.Keys {
|
||||||
|
if e.MatchAnyValue {
|
||||||
|
field, err = elem.Pipe(Get(e.Keys[i]))
|
||||||
|
} else {
|
||||||
|
field, err = elem.Pipe(MatchField(e.Keys[i], e.Values[i]))
|
||||||
|
}
|
||||||
|
if !IsFoundOrError(field, err) {
|
||||||
|
// this is not the element we are looking for
|
||||||
|
matchesElement = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matchesElement {
|
||||||
return elem, err
|
return elem, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,7 +393,7 @@ func (f FieldMatcher) Filter(rn *RNode) (*RNode, error) {
|
|||||||
return rn, nil
|
return rn, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case rn.value.Value == f.Value.YNode().Value:
|
case GetValue(rn) == GetValue(f.Value):
|
||||||
return rn, nil
|
return rn, nil
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -404,7 +446,7 @@ type PathGetter struct {
|
|||||||
// See FieldMatcher for more on Fields and Map Keys.
|
// See FieldMatcher for more on Fields and Map Keys.
|
||||||
//
|
//
|
||||||
// List Entries can be specified as map entry to match [fieldName=fieldValue]
|
// List Entries can be specified as map entry to match [fieldName=fieldValue]
|
||||||
// or a postional index like 0 to get the element. - (unquoted hyphen) is
|
// or a positional index like 0 to get the element. - (unquoted hyphen) is
|
||||||
// special and means the last element.
|
// special and means the last element.
|
||||||
//
|
//
|
||||||
// See Elem for more on List Entries.
|
// See Elem for more on List Entries.
|
||||||
@@ -504,7 +546,7 @@ func (l PathGetter) elemFilter(part string) (Filter, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Append the Node
|
// Append the Node
|
||||||
return ElementMatcher{FieldName: name, FieldValue: value, Create: elem}, nil
|
return ElementMatcher{Keys: []string{name}, Values: []string{value}, Create: elem}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l PathGetter) fieldFilter(
|
func (l PathGetter) fieldFilter(
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ func TestElementSetter(t *testing.T) {
|
|||||||
// ElementSetter will update node, so make a copy
|
// ElementSetter will update node, so make a copy
|
||||||
node := orig.Copy()
|
node := orig.Copy()
|
||||||
// Remove an element, because ElementSetter.Element is left nil.
|
// Remove an element, because ElementSetter.Element is left nil.
|
||||||
rn, err := node.Pipe(ElementSetter{Key: "a", Value: "b"})
|
rn, err := node.Pipe(ElementSetter{Keys: []string{"a"}, Values: []string{"b"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
assert.Equal(t, `- scalarValue
|
assert.Equal(t, `- scalarValue
|
||||||
@@ -118,7 +118,7 @@ func TestElementSetter(t *testing.T) {
|
|||||||
|
|
||||||
node = orig.Copy()
|
node = orig.Copy()
|
||||||
// Nothing happens because no element is matched
|
// Nothing happens because no element is matched
|
||||||
rn, err = node.Pipe(ElementSetter{Key: "a", Value: "zebra"})
|
rn, err = node.Pipe(ElementSetter{Keys: []string{"a"}, Values: []string{"zebra"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
assert.Equal(t, `- a: b
|
assert.Equal(t, `- a: b
|
||||||
@@ -129,19 +129,24 @@ func TestElementSetter(t *testing.T) {
|
|||||||
node = orig.Copy()
|
node = orig.Copy()
|
||||||
// Return error because ElementSetter doesn't support a single key
|
// Return error because ElementSetter doesn't support a single key
|
||||||
// when there is a scalar value in the list
|
// when there is a scalar value in the list
|
||||||
_, err = node.Pipe(ElementSetter{Key: "a"})
|
_, err = node.Pipe(ElementSetter{Keys: []string{"a"}})
|
||||||
assert.EqualError(t, err, "wrong Node Kind for expected: MappingNode was ScalarNode: value: {scalarValue}")
|
assert.EqualError(t, err, "wrong Node Kind for expected: MappingNode was ScalarNode: value: {scalarValue}")
|
||||||
|
|
||||||
|
// Return error because ElementSetter will assume all elements are scalar when
|
||||||
|
// there is only value provided.
|
||||||
|
_, err = node.Pipe(ElementSetter{Values: []string{"b"}})
|
||||||
|
assert.EqualError(t, err, "wrong Node Kind for expected: ScalarNode was MappingNode: value: {a: b}")
|
||||||
|
|
||||||
node = MustParse(`
|
node = MustParse(`
|
||||||
- a: b
|
- a: b
|
||||||
- c: d
|
- c: d
|
||||||
`)
|
`)
|
||||||
// {a: b} is removed since the value is omitted and only key is used
|
// If given a key and no values, ElementSetter will
|
||||||
// to match and no Element specified.
|
// change node to be an empty list
|
||||||
rn, err = node.Pipe(ElementSetter{Key: "a"})
|
rn, err = node.Pipe(ElementSetter{Keys: []string{"a"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
assert.Equal(t, `- c: d
|
assert.Equal(t, `[]
|
||||||
`, assertNoErrorString(t)(node.String()))
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
node = MustParse(`
|
node = MustParse(`
|
||||||
@@ -150,7 +155,7 @@ func TestElementSetter(t *testing.T) {
|
|||||||
`)
|
`)
|
||||||
// Return error because ElementSetter will assume all elements are scalar when
|
// Return error because ElementSetter will assume all elements are scalar when
|
||||||
// there is only value provided.
|
// there is only value provided.
|
||||||
_, err = node.Pipe(ElementSetter{Value: "b"})
|
_, err = node.Pipe(ElementSetter{Values: []string{"b"}})
|
||||||
assert.EqualError(t, err, "wrong Node Kind for expected: ScalarNode was MappingNode: value: {a: b}")
|
assert.EqualError(t, err, "wrong Node Kind for expected: ScalarNode was MappingNode: value: {a: b}")
|
||||||
|
|
||||||
node = MustParse(`
|
node = MustParse(`
|
||||||
@@ -159,7 +164,7 @@ func TestElementSetter(t *testing.T) {
|
|||||||
`)
|
`)
|
||||||
// b is removed since ElementSetter use the value "b" to match the
|
// b is removed since ElementSetter use the value "b" to match the
|
||||||
// scalar values.
|
// scalar values.
|
||||||
rn, err = node.Pipe(ElementSetter{Value: "b"})
|
rn, err = node.Pipe(ElementSetter{Values: []string{"b"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
assert.Equal(t, `- a
|
assert.Equal(t, `- a
|
||||||
@@ -171,8 +176,8 @@ func TestElementSetter(t *testing.T) {
|
|||||||
"e": "f",
|
"e": "f",
|
||||||
})
|
})
|
||||||
rn, err = node.Pipe(ElementSetter{
|
rn, err = node.Pipe(ElementSetter{
|
||||||
Key: "a",
|
Keys: []string{"a"},
|
||||||
Value: "b",
|
Values: []string{"b"},
|
||||||
Element: newElement.YNode(),
|
Element: newElement.YNode(),
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -186,8 +191,8 @@ func TestElementSetter(t *testing.T) {
|
|||||||
// Set an element with scalar, {"a": "b"} to "foo"
|
// Set an element with scalar, {"a": "b"} to "foo"
|
||||||
newElement = NewScalarRNode("foo")
|
newElement = NewScalarRNode("foo")
|
||||||
rn, err = node.Pipe(ElementSetter{
|
rn, err = node.Pipe(ElementSetter{
|
||||||
Key: "a",
|
Keys: []string{"a"},
|
||||||
Value: "b",
|
Values: []string{"b"},
|
||||||
Element: newElement.YNode(),
|
Element: newElement.YNode(),
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -204,8 +209,8 @@ func TestElementSetter(t *testing.T) {
|
|||||||
"e": "f",
|
"e": "f",
|
||||||
})
|
})
|
||||||
rn, err = node.Pipe(ElementSetter{
|
rn, err = node.Pipe(ElementSetter{
|
||||||
Key: "x",
|
Keys: []string{"x"},
|
||||||
Value: "y",
|
Values: []string{"y"},
|
||||||
Element: newElement.YNode(),
|
Element: newElement.YNode(),
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -217,6 +222,133 @@ func TestElementSetter(t *testing.T) {
|
|||||||
`, assertNoErrorString(t)(node.String()))
|
`, assertNoErrorString(t)(node.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestElementSetterMultipleKeys(t *testing.T) {
|
||||||
|
orig := MustParse(`
|
||||||
|
- a: b
|
||||||
|
c: d
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
# null will be removed
|
||||||
|
- null
|
||||||
|
`)
|
||||||
|
|
||||||
|
// ElementSetter will update node, so make a copy
|
||||||
|
node := orig.Copy()
|
||||||
|
// Remove an element using one key-value pair,
|
||||||
|
// because ElementSetter.Element is left nil.
|
||||||
|
rn, err := node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a"},
|
||||||
|
Values: []string{"b"},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, rn)
|
||||||
|
assert.Equal(t, `- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Remove an element using multiple key-value pairs,
|
||||||
|
// because ElementSetter.Element is left nil.
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a", "c"},
|
||||||
|
Values: []string{"b", "d"},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, rn)
|
||||||
|
assert.Equal(t, `- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Should do nothing, because Element is nil
|
||||||
|
// and there is no element which matches all
|
||||||
|
// give key-value pairs
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a", "c"},
|
||||||
|
Values: []string{"b", "wrong value"},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, rn)
|
||||||
|
assert.Equal(t, `- a: b
|
||||||
|
c: d
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Set an element, with a single key-value pair
|
||||||
|
// replacing 'a: b, c: d' with 'g: h'
|
||||||
|
newElement := NewMapRNode(&map[string]string{
|
||||||
|
"g": "h",
|
||||||
|
})
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a"},
|
||||||
|
Values: []string{"b"},
|
||||||
|
Element: newElement.YNode(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rn, newElement)
|
||||||
|
assert.Equal(t, `- g: h
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Set an element, with multiple key-value pairs
|
||||||
|
// replacing 'a: b, c: d' with 'g: h'
|
||||||
|
newElement = NewMapRNode(&map[string]string{
|
||||||
|
"g": "h",
|
||||||
|
})
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a", "c"},
|
||||||
|
Values: []string{"b", "d"},
|
||||||
|
Element: newElement.YNode(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rn, newElement)
|
||||||
|
assert.Equal(t, `- g: h
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Set an element scalar,
|
||||||
|
// {'a: b, c: d'} to "foo"
|
||||||
|
newElement = NewScalarRNode("foo")
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a", "c"},
|
||||||
|
Values: []string{"b", "d"},
|
||||||
|
Element: newElement.YNode(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rn, newElement)
|
||||||
|
assert.Equal(t, `- foo
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
|
||||||
|
node = orig.Copy()
|
||||||
|
// Append an element
|
||||||
|
// There is no element which matches all given
|
||||||
|
// key-value pairs, so the element will be appended.
|
||||||
|
newElement = NewMapRNode(&map[string]string{
|
||||||
|
"g": "h",
|
||||||
|
})
|
||||||
|
rn, err = node.Pipe(ElementSetter{
|
||||||
|
Keys: []string{"a", "c"},
|
||||||
|
Values: []string{"b", "wrong value"},
|
||||||
|
Element: newElement.YNode(),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rn, newElement)
|
||||||
|
assert.Equal(t, `- a: b
|
||||||
|
c: d
|
||||||
|
- scalarValue
|
||||||
|
- e: f
|
||||||
|
- g: h
|
||||||
|
`, assertNoErrorString(t)(node.String()))
|
||||||
|
}
|
||||||
|
|
||||||
func TestElementMatcherWithNoValue(t *testing.T) {
|
func TestElementMatcherWithNoValue(t *testing.T) {
|
||||||
node, err := Parse(`
|
node, err := Parse(`
|
||||||
- a: c
|
- a: c
|
||||||
@@ -224,21 +356,63 @@ func TestElementMatcherWithNoValue(t *testing.T) {
|
|||||||
`)
|
`)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
rn, err := node.Pipe(ElementMatcher{FieldName: "b"})
|
rn, err := node.Pipe(ElementMatcher{Keys: []string{"b"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "b: \"\"\n", assertNoErrorString(t)(rn.String()))
|
assert.Equal(t, "b: \"\"\n", assertNoErrorString(t)(rn.String()))
|
||||||
|
|
||||||
rn, err = node.Pipe(ElementMatcher{FieldName: "a"})
|
rn, err = node.Pipe(ElementMatcher{Keys: []string{"a"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
|
|
||||||
rn, err = node.Pipe(ElementMatcher{FieldName: "a", MatchAnyValue: true})
|
rn, err = node.Pipe(ElementMatcher{Keys: []string{"a"}, MatchAnyValue: true})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "a: c\n", assertNoErrorString(t)(rn.String()))
|
assert.Equal(t, "a: c\n", assertNoErrorString(t)(rn.String()))
|
||||||
|
|
||||||
_, err = node.Pipe(ElementMatcher{FieldName: "a", FieldValue: "c", MatchAnyValue: true})
|
_, err = node.Pipe(ElementMatcher{Keys: []string{"a"}, Values: []string{"c"}, MatchAnyValue: true})
|
||||||
assert.Errorf(t, err, "FieldValue must be empty when NoValue is set to true")
|
assert.Errorf(t, err, "Values must be empty when MatchAnyValue is set to true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestElementMatcherMultipleKeys(t *testing.T) {
|
||||||
|
node, err := Parse(`
|
||||||
|
- a: b
|
||||||
|
c: d
|
||||||
|
- e: f
|
||||||
|
`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// matches all key-value pairs
|
||||||
|
rn, err := node.Pipe(MatchElementList(
|
||||||
|
[]string{"a", "c"}, // keys
|
||||||
|
[]string{"b", "d"}, // values
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, rn)
|
||||||
|
|
||||||
|
// matches one key value pair but not the other
|
||||||
|
rn, err = node.Pipe(MatchElementList(
|
||||||
|
[]string{"a", "c"}, // keys
|
||||||
|
[]string{"b", "f"}, // values
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, rn)
|
||||||
|
|
||||||
|
// matches single given key value pair
|
||||||
|
rn, err = node.Pipe(MatchElementList(
|
||||||
|
[]string{"e"}, // keys
|
||||||
|
[]string{"f"}, // values
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, rn)
|
||||||
|
|
||||||
|
// matching key, but value doesn't match
|
||||||
|
rn, err = node.Pipe(MatchElementList(
|
||||||
|
[]string{"e"}, // keys
|
||||||
|
[]string{"g"}, // values
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, rn)
|
||||||
|
}
|
||||||
|
|
||||||
func TestClearField_Fn(t *testing.T) {
|
func TestClearField_Fn(t *testing.T) {
|
||||||
node, err := Parse(NodeSampleData)
|
node, err := Parse(NodeSampleData)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func elideMappingPatchDirective(patch *yaml.RNode) error {
|
|||||||
func elideSequencePatchDirective(patch *yaml.RNode, value string) error {
|
func elideSequencePatchDirective(patch *yaml.RNode, value string) error {
|
||||||
return patch.PipeE(yaml.ElementSetter{
|
return patch.PipeE(yaml.ElementSetter{
|
||||||
Element: nil,
|
Element: nil,
|
||||||
Key: strategicMergePatchDirectiveKey,
|
Keys: []string{strategicMergePatchDirectiveKey},
|
||||||
Value: value,
|
Values: []string{value},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ func appendListNode(dst, src *yaml.RNode, key string) (*yaml.RNode, error) {
|
|||||||
// If key is empty, we know this is a scalar value and we can directly set the
|
// If key is empty, we know this is a scalar value and we can directly set the
|
||||||
// node
|
// node
|
||||||
if key == "" {
|
if key == "" {
|
||||||
_, err := dst.Pipe(yaml.ElementSetter{Element: elem, Key: key, Value: elem.Value})
|
_, err := dst.Pipe(yaml.ElementSetter{
|
||||||
|
Element: elem,
|
||||||
|
Keys: []string{key},
|
||||||
|
Values: []string{elem.Value},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -46,7 +50,11 @@ func appendListNode(dst, src *yaml.RNode, key string) (*yaml.RNode, error) {
|
|||||||
// We use the key and value from elem to find the corresponding element in dst.
|
// We use the key and value from elem to find the corresponding element in dst.
|
||||||
// Then we will use ElementSetter to replace the element with elem. If we cannot
|
// Then we will use ElementSetter to replace the element with elem. If we cannot
|
||||||
// find the item, the element will be appended.
|
// find the item, the element will be appended.
|
||||||
_, err = dst.Pipe(yaml.ElementSetter{Element: elem, Key: key, Value: v})
|
_, err = dst.Pipe(yaml.ElementSetter{
|
||||||
|
Element: elem,
|
||||||
|
Keys: []string{key},
|
||||||
|
Values: []string{v},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -76,7 +84,10 @@ func (l *Walker) setAssociativeSequenceElements(values []string, key string, des
|
|||||||
}
|
}
|
||||||
// delete the node from **dest** if it's null or empty
|
// delete the node from **dest** if it's null or empty
|
||||||
if yaml.IsMissingOrNull(val) || yaml.IsEmptyMap(val) {
|
if yaml.IsMissingOrNull(val) || yaml.IsEmptyMap(val) {
|
||||||
_, err = dest.Pipe(yaml.ElementSetter{Key: key, Value: value})
|
_, err = dest.Pipe(yaml.ElementSetter{
|
||||||
|
Keys: []string{key},
|
||||||
|
Values: []string{value},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -94,7 +105,11 @@ func (l *Walker) setAssociativeSequenceElements(values []string, key string, des
|
|||||||
// Add the val to the sequence. val will replace the item in the sequence if
|
// Add the val to the sequence. val will replace the item in the sequence if
|
||||||
// there is an item that matches the key-value pair. Otherwise val will be appended
|
// there is an item that matches the key-value pair. Otherwise val will be appended
|
||||||
// the the sequence.
|
// the the sequence.
|
||||||
_, err = itemsToBeAdded.Pipe(yaml.ElementSetter{Element: val.YNode(), Key: key, Value: value})
|
_, err = itemsToBeAdded.Pipe(yaml.ElementSetter{
|
||||||
|
Element: val.YNode(),
|
||||||
|
Keys: []string{key},
|
||||||
|
Values: []string{value},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user