config: interpolationWalk seems to work

This commit is contained in:
Mitchell Hashimoto 2014-07-21 11:30:43 -07:00
parent 4c9e0f395c
commit e8fe26488a
2 changed files with 65 additions and 5 deletions

View File

@ -3,6 +3,7 @@ package config
import (
"reflect"
"regexp"
"strings"
"github.com/mitchellh/reflectwalk"
)
@ -15,8 +16,6 @@ var interpRegexp *regexp.Regexp = regexp.MustCompile(
// (github.com/mitchellh/reflectwalk) that can be used to automatically
// execute a callback for an interpolation.
type interpolationWalker struct {
// F must be one of interpolationWalkerFunc or
// interpolationReplaceWalkerFunc.
F interpolationWalkerFunc
Replace bool
@ -26,6 +25,12 @@ type interpolationWalker struct {
csData interface{}
}
// interpolationWalkerFunc is the callback called by interpolationWalk.
// It is called with any interpolation found. It should return a value
// to replace the interpolation with, along with any errors.
//
// If Replace is set to false in interpolationWalker, then the replace
// value can be anything as it will have no effect.
type interpolationWalkerFunc func(Interpolation) (string, error)
func (w *interpolationWalker) Enter(loc reflectwalk.Location) error {
@ -58,8 +63,11 @@ func (w *interpolationWalker) MapElem(m, k, v reflect.Value) error {
}
func (w *interpolationWalker) Primitive(v reflect.Value) error {
setV := v
// We only care about strings
if v.Kind() == reflect.Interface {
setV = v
v = v.Elem()
}
if v.Kind() != reflect.String {
@ -74,6 +82,7 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
return nil
}
result := v.String()
for _, match := range matches {
dollars := len(match[1])
@ -96,11 +105,22 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
}
if w.Replace {
// TODO(mitchellh): replace
println(replaceVal)
}
return nil
result = strings.Replace(result, match[0], replaceVal, -1)
}
}
if w.Replace {
resultVal := reflect.ValueOf(result)
if w.loc == reflectwalk.MapValue {
// If we're in a map, then the only way to set a map value is
// to set it directly.
m := w.cs[len(w.cs)-1]
mk := w.csData.(reflect.Value)
m.SetMapIndex(mk, resultVal)
} else {
// Otherwise, we should be addressable
setV.Set(resultVal)
}
}
return nil

View File

@ -53,3 +53,43 @@ func TestInterpolationWalker_detect(t *testing.T) {
}
}
}
func TestInterpolationWalker_replace(t *testing.T) {
cases := []struct {
Input interface{}
Output interface{}
}{
{
Input: map[string]interface{}{
"foo": "$${var.foo}",
},
Output: map[string]interface{}{
"foo": "$${var.foo}",
},
},
{
Input: map[string]interface{}{
"foo": "${var.foo}",
},
Output: map[string]interface{}{
"foo": "bar",
},
},
}
for i, tc := range cases {
fn := func(i Interpolation) (string, error) {
return "bar", nil
}
w := &interpolationWalker{F: fn, Replace: true}
if err := reflectwalk.Walk(tc.Input, w); err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(tc.Input, tc.Output) {
t.Fatalf("%d: bad:\n\n%#v", i, tc.Input)
}
}
}