Skip to content

Commit

Permalink
replacements allow to replace multi values
Browse files Browse the repository at this point in the history
  • Loading branch information
koba1t committed Feb 3, 2022
1 parent b79d77a commit 22f9daa
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
28 changes: 26 additions & 2 deletions api/filters/replacement/replacement.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,20 +119,42 @@ func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelect
if target.Options != nil && target.Options.Create {
t, err = node.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
} else {
t, err = node.Pipe(yaml.Lookup(fieldPath...))
// t, err = node.Pipe(yaml.Lookup(fieldPath...))
t, err = node.Pipe(&yaml.PathMatcher{Path: fieldPath})
}
if err != nil {
return err
}
if t != nil {
if err = setTargetValue(target.Options, t, value); err != nil {
if err = applyToOneNode(target.Options, t, value); err != nil {
return err
}
}
}
return nil
}

func applyToOneNode(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
if len(t.YNode().Content) == 0 {
if err := setTargetValue(options, t, value); err != nil {
return err
}
return nil
}

for _, scalarNode := range t.YNode().Content {
if options != nil && options.Create {
return fmt.Errorf("cannot use create option in a multi-value target")
}
rn := yaml.NewRNode(scalarNode)
if err := setTargetValue(options, rn, value); err != nil {
return err
}
}

return nil
}

func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
value = value.Copy()
if options != nil && options.Delimiter != "" {
Expand All @@ -152,7 +174,9 @@ func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNod
}
value.YNode().Value = strings.Join(tv, options.Delimiter)
}

t.SetYNode(value.YNode())

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions kyaml/yaml/fns.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,13 @@ func IsListIndex(p string) bool {
return strings.HasPrefix(p, "[") && strings.HasSuffix(p, "]")
}

// IsIdxNumber returns true if p is an index number.
// e.g. 1
func IsIdxNumber(p string) bool {
idx, err := strconv.Atoi(p)
return err == nil && idx >= 0
}

// SplitIndexNameValue splits a lookup part Val index into the field name
// and field value to match.
// e.g. splits [name=nginx] into (name, nginx)
Expand Down
43 changes: 39 additions & 4 deletions kyaml/yaml/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package yaml

import (
"regexp"
"strconv"
"strings"
)

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

val *RNode
field string
matchRegex string
val *RNode
field string
matchRegex string
indexNumber int
}

func (p *PathMatcher) stripComments(n *Node) {
Expand Down Expand Up @@ -79,6 +81,10 @@ func (p *PathMatcher) filter(rn *RNode) (*RNode, error) {
return p.val, nil
}

if IsIdxNumber(p.Path[0]) {
return p.doIndexSeq(rn)
}

if IsListIndex(p.Path[0]) {
// match seq elements
return p.doSeq(rn)
Expand All @@ -98,7 +104,6 @@ func (p *PathMatcher) doMatchEvery(rn *RNode) (*RNode, error) {
return nil, err
}

// fmt.Println(p.val.String())
return p.val, nil
}

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

// doIndexSeq iterates over a sequence and appends elements matching the index p.Val
func (p *PathMatcher) doIndexSeq(rn *RNode) (*RNode, error) {
// parse to index number
idx, err := strconv.Atoi(p.Path[0])
if err != nil {
return nil, err
}
p.indexNumber = idx

elements, err := rn.Elements()
if err != nil {
return nil, err
}

// get target element
element := elements[idx]

// recurse on the matching element
pm := &PathMatcher{Path: p.Path[1:]}
add, err := pm.filter(element)
for k, v := range pm.Matches {
p.Matches[k] = v
}
if err != nil || add == nil {
return nil, err
}
p.append("", add.Content()...)
return p.val, nil
}

// doSeq iterates over a sequence and appends elements matching the path regex to p.Val
func (p *PathMatcher) doSeq(rn *RNode) (*RNode, error) {
// parse the field + match pair
Expand Down

0 comments on commit 22f9daa

Please sign in to comment.