Skip to content

Commit

Permalink
simplify multi vars replacer
Browse files Browse the repository at this point in the history
Signed-off-by: dmitriy kalinin <[email protected]>
  • Loading branch information
dpb587-pivotal authored and cppforlife committed Nov 11, 2016
1 parent 0a80a1d commit acb0f0e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 38 deletions.
67 changes: 29 additions & 38 deletions director/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import (
"gopkg.in/yaml.v2"
)

var templateFormatRegex = regexp.MustCompile(`\(\((!?[-\w\p{L}]+)\)\)`)
var (
templateFormatRegex = regexp.MustCompile(`\(\((!?[-\w\p{L}]+)\)\)`)
templateFormatAnchoredRegex = regexp.MustCompile("\\A" + templateFormatRegex.String() + "\\z")
)

type Template struct {
bytes []byte
Expand Down Expand Up @@ -72,11 +75,9 @@ func (t Template) Evaluate(vars Variables, ops patch.Ops, opts EvaluateOpts) ([]
}

func (t Template) interpolate(node interface{}, vars Variables, opts EvaluateOpts, missingVars map[string]struct{}) (interface{}, error) {
switch node.(type) {
switch typedNode := node.(type) {
case map[interface{}]interface{}:
nodeMap := node.(map[interface{}]interface{})

for k, v := range nodeMap {
for k, v := range typedNode {
evaluatedValue, err := t.interpolate(v, vars, opts, missingVars)
if err != nil {
return nil, err
Expand All @@ -86,64 +87,54 @@ func (t Template) interpolate(node interface{}, vars Variables, opts EvaluateOpt
if err != nil {
return nil, err
}
delete(nodeMap, k) // delete in case key has changed
nodeMap[evaluatedKey] = evaluatedValue

delete(typedNode, k) // delete in case key has changed
typedNode[evaluatedKey] = evaluatedValue
}
case []interface{}:
nodeArray := node.([]interface{})

for i, x := range nodeArray {
case []interface{}:
for i, x := range typedNode {
var err error
nodeArray[i], err = t.interpolate(x, vars, opts, missingVars)
typedNode[i], err = t.interpolate(x, vars, opts, missingVars)
if err != nil {
return nil, err
}
}
case string:
nodeString := node.(string)

for key, placeholders := range t.keysToPlaceholders(nodeString) {
case string:
for _, key := range t.keys(typedNode) {
if foundVar, exists := vars[key]; exists {
// ensure that value type is preserved when replacing the entire field
replaceEntireField := (nodeString == fmt.Sprintf("((%s))", key) || nodeString == fmt.Sprintf("((!%s))", key))
if replaceEntireField {
if templateFormatAnchoredRegex.MatchString(typedNode) {
return foundVar, nil
}

for _, placeholder := range placeholders {
switch foundVar.(type) {
case string, int, int16, int32, int64, uint, uint16, uint32, uint64:
nodeString = strings.Replace(nodeString, placeholder, fmt.Sprintf("%v", foundVar), 1)
default:
return nil, fmt.Errorf("Invalid type '%T' for value '%v' and key '%s'. Supported types for interpolation within a string are integers and strings.", foundVar, foundVar, key)
}
switch foundVar.(type) {
case string, int, int16, int32, int64, uint, uint16, uint32, uint64:
foundVarStr := fmt.Sprintf("%v", foundVar)
typedNode = strings.Replace(typedNode, fmt.Sprintf("((%s))", key), foundVarStr, -1)
typedNode = strings.Replace(typedNode, fmt.Sprintf("((!%s))", key), foundVarStr, -1)
default:
errMsg := "Invalid type '%T' for value '%v' and key '%s'. Supported types for interpolation within a string are integers and strings."
return nil, fmt.Errorf(errMsg, foundVar, foundVar, key)
}
} else if opts.ExpectAllKeys {
missingVars[key] = struct{}{}
}
}

return nodeString, nil
return typedNode, nil
}

return node, nil
}

func (t Template) keysToPlaceholders(value string) map[string][]string {
matches := templateFormatRegex.FindAllSubmatch([]byte(value), -1)
func (t Template) keys(value string) []string {
var keys []string

keysToPlaceholders := map[string][]string{}
if matches == nil {
return keysToPlaceholders
}

for _, match := range matches {
capture := match[1]
key := strings.TrimPrefix(string(capture), "!")
if len(key) > 0 {
keysToPlaceholders[key] = append(keysToPlaceholders[key], fmt.Sprintf("((%s))", capture))
}
for _, match := range templateFormatRegex.FindAllSubmatch([]byte(value), -1) {
keys = append(keys, strings.TrimPrefix(string(match[1]), "!"))
}

return keysToPlaceholders
return keys
}
12 changes: 12 additions & 0 deletions director/template/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ dup-key: ((key3))
Expect(result).To(Equal([]byte("uri: nats://nats:[email protected]:4222\n")))
})

It("can interpolate multiple secret keys in the middle of a string even if keys have ! marks", func() {
template := NewTemplate([]byte("uri: nats://nats:((!password))@((ip)):4222"))
vars := Variables{
"password": "secret",
"ip": "10.0.0.0",
}

result, err := template.Evaluate(vars, patch.Ops{}, EvaluateOpts{})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal([]byte("uri: nats://nats:[email protected]:4222\n")))
})

It("can interpolate multiple keys of type string and int in the middle of a string", func() {
template := NewTemplate([]byte("address: ((ip)):((port))"))
vars := Variables{
Expand Down

0 comments on commit acb0f0e

Please sign in to comment.