From e8fe26488a07f21b9551337b0c631205415594df Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 21 Jul 2014 11:30:43 -0700 Subject: [PATCH] config: interpolationWalk seems to work --- config/interpolate_walk.go | 30 ++++++++++++++++++++----- config/interpolate_walk_test.go | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/config/interpolate_walk.go b/config/interpolate_walk.go index 15bc84586..b4ee9ab98 100644 --- a/config/interpolate_walk.go +++ b/config/interpolate_walk.go @@ -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) + result = strings.Replace(result, match[0], replaceVal, -1) } + } - return nil + 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 diff --git a/config/interpolate_walk_test.go b/config/interpolate_walk_test.go index 15fa29d50..77249d71d 100644 --- a/config/interpolate_walk_test.go +++ b/config/interpolate_walk_test.go @@ -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) + } + } +}