Skip to content

Commit 22f9daa

Browse files
committed
replacements allow to replace multi values
1 parent b79d77a commit 22f9daa

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

api/filters/replacement/replacement.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,42 @@ func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelect
119119
if target.Options != nil && target.Options.Create {
120120
t, err = node.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
121121
} else {
122-
t, err = node.Pipe(yaml.Lookup(fieldPath...))
122+
// t, err = node.Pipe(yaml.Lookup(fieldPath...))
123+
t, err = node.Pipe(&yaml.PathMatcher{Path: fieldPath})
123124
}
124125
if err != nil {
125126
return err
126127
}
127128
if t != nil {
128-
if err = setTargetValue(target.Options, t, value); err != nil {
129+
if err = applyToOneNode(target.Options, t, value); err != nil {
129130
return err
130131
}
131132
}
132133
}
133134
return nil
134135
}
135136

137+
func applyToOneNode(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
138+
if len(t.YNode().Content) == 0 {
139+
if err := setTargetValue(options, t, value); err != nil {
140+
return err
141+
}
142+
return nil
143+
}
144+
145+
for _, scalarNode := range t.YNode().Content {
146+
if options != nil && options.Create {
147+
return fmt.Errorf("cannot use create option in a multi-value target")
148+
}
149+
rn := yaml.NewRNode(scalarNode)
150+
if err := setTargetValue(options, rn, value); err != nil {
151+
return err
152+
}
153+
}
154+
155+
return nil
156+
}
157+
136158
func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
137159
value = value.Copy()
138160
if options != nil && options.Delimiter != "" {
@@ -152,7 +174,9 @@ func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNod
152174
}
153175
value.YNode().Value = strings.Join(tv, options.Delimiter)
154176
}
177+
155178
t.SetYNode(value.YNode())
179+
156180
return nil
157181
}
158182

kyaml/yaml/fns.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,13 @@ func IsListIndex(p string) bool {
782782
return strings.HasPrefix(p, "[") && strings.HasSuffix(p, "]")
783783
}
784784

785+
// IsIdxNumber returns true if p is an index number.
786+
// e.g. 1
787+
func IsIdxNumber(p string) bool {
788+
idx, err := strconv.Atoi(p)
789+
return err == nil && idx >= 0
790+
}
791+
785792
// SplitIndexNameValue splits a lookup part Val index into the field name
786793
// and field value to match.
787794
// e.g. splits [name=nginx] into (name, nginx)

kyaml/yaml/match.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package yaml
55

66
import (
77
"regexp"
8+
"strconv"
89
"strings"
910
)
1011

@@ -42,9 +43,10 @@ type PathMatcher struct {
4243
// This is useful for if the nodes are to be printed in FlowStyle.
4344
StripComments bool
4445

45-
val *RNode
46-
field string
47-
matchRegex string
46+
val *RNode
47+
field string
48+
matchRegex string
49+
indexNumber int
4850
}
4951

5052
func (p *PathMatcher) stripComments(n *Node) {
@@ -79,6 +81,10 @@ func (p *PathMatcher) filter(rn *RNode) (*RNode, error) {
7981
return p.val, nil
8082
}
8183

84+
if IsIdxNumber(p.Path[0]) {
85+
return p.doIndexSeq(rn)
86+
}
87+
8288
if IsListIndex(p.Path[0]) {
8389
// match seq elements
8490
return p.doSeq(rn)
@@ -98,7 +104,6 @@ func (p *PathMatcher) doMatchEvery(rn *RNode) (*RNode, error) {
98104
return nil, err
99105
}
100106

101-
// fmt.Println(p.val.String())
102107
return p.val, nil
103108
}
104109

@@ -134,6 +139,36 @@ func (p *PathMatcher) doField(rn *RNode) (*RNode, error) {
134139
return p.val, err
135140
}
136141

142+
// doIndexSeq iterates over a sequence and appends elements matching the index p.Val
143+
func (p *PathMatcher) doIndexSeq(rn *RNode) (*RNode, error) {
144+
// parse to index number
145+
idx, err := strconv.Atoi(p.Path[0])
146+
if err != nil {
147+
return nil, err
148+
}
149+
p.indexNumber = idx
150+
151+
elements, err := rn.Elements()
152+
if err != nil {
153+
return nil, err
154+
}
155+
156+
// get target element
157+
element := elements[idx]
158+
159+
// recurse on the matching element
160+
pm := &PathMatcher{Path: p.Path[1:]}
161+
add, err := pm.filter(element)
162+
for k, v := range pm.Matches {
163+
p.Matches[k] = v
164+
}
165+
if err != nil || add == nil {
166+
return nil, err
167+
}
168+
p.append("", add.Content()...)
169+
return p.val, nil
170+
}
171+
137172
// doSeq iterates over a sequence and appends elements matching the path regex to p.Val
138173
func (p *PathMatcher) doSeq(rn *RNode) (*RNode, error) {
139174
// parse the field + match pair

0 commit comments

Comments
 (0)