config: get rid of the variable*Walkers, replace with more generic
This commit is contained in:
parent
4099c64833
commit
cabc007ec4
|
@ -19,10 +19,11 @@ type interpolationWalker struct {
|
||||||
F interpolationWalkerFunc
|
F interpolationWalkerFunc
|
||||||
Replace bool
|
Replace bool
|
||||||
|
|
||||||
key []string
|
key []string
|
||||||
loc reflectwalk.Location
|
loc reflectwalk.Location
|
||||||
cs []reflect.Value
|
cs []reflect.Value
|
||||||
csData interface{}
|
csData interface{}
|
||||||
|
unknownKeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// interpolationWalkerFunc is the callback called by interpolationWalk.
|
// interpolationWalkerFunc is the callback called by interpolationWalk.
|
||||||
|
@ -105,6 +106,13 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.Replace {
|
if w.Replace {
|
||||||
|
// If this is an unknown variable, then we remove it from
|
||||||
|
// the configuration.
|
||||||
|
if replaceVal == UnknownVariableValue {
|
||||||
|
w.removeCurrent()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
result = strings.Replace(result, match[0], replaceVal, -1)
|
result = strings.Replace(result, match[0], replaceVal, -1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,3 +133,19 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *interpolationWalker) removeCurrent() {
|
||||||
|
c := w.cs[len(w.cs)-1]
|
||||||
|
switch c.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
// Zero value so that we delete the map key
|
||||||
|
var val reflect.Value
|
||||||
|
|
||||||
|
// Get the key and delete it
|
||||||
|
k := w.csData.(reflect.Value)
|
||||||
|
c.SetMapIndex(k, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the key to the unknown keys
|
||||||
|
w.unknownKeys = append(w.unknownKeys, strings.Join(w.key, "."))
|
||||||
|
}
|
||||||
|
|
|
@ -70,10 +70,10 @@ func TestInterpolationWalker_replace(t *testing.T) {
|
||||||
|
|
||||||
{
|
{
|
||||||
Input: map[string]interface{}{
|
Input: map[string]interface{}{
|
||||||
"foo": "${var.foo}",
|
"foo": "hello, ${var.foo}",
|
||||||
},
|
},
|
||||||
Output: map[string]interface{}{
|
Output: map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "hello, bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,26 +69,43 @@ func (r *RawConfig) Interpolate(vs map[string]string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w := &variableReplaceWalker{Values: vs}
|
|
||||||
r.config = config.(map[string]interface{})
|
r.config = config.(map[string]interface{})
|
||||||
|
|
||||||
|
fn := func(i Interpolation) (string, error) {
|
||||||
|
return i.Interpolate(vs)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &interpolationWalker{F: fn, Replace: true}
|
||||||
err = reflectwalk.Walk(r.config, w)
|
err = reflectwalk.Walk(r.config, w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.unknownKeys = w.UnknownKeys
|
r.unknownKeys = w.unknownKeys
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RawConfig) init() error {
|
func (r *RawConfig) init() error {
|
||||||
walker := new(variableDetectWalker)
|
r.config = r.Raw
|
||||||
|
r.Variables = nil
|
||||||
|
|
||||||
|
fn := func(i Interpolation) (string, error) {
|
||||||
|
for k, v := range i.Variables() {
|
||||||
|
if r.Variables == nil {
|
||||||
|
r.Variables = make(map[string]InterpolatedVariable)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Variables[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
walker := &interpolationWalker{F: fn}
|
||||||
if err := reflectwalk.Walk(r.Raw, walker); err != nil {
|
if err := reflectwalk.Walk(r.Raw, walker); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Variables = walker.Variables
|
|
||||||
r.config = r.Raw
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/mitchellh/reflectwalk"
|
|
||||||
)
|
|
||||||
|
|
||||||
// varRegexp is a regexp that matches variables such as ${foo.bar}
|
|
||||||
var varRegexp *regexp.Regexp
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
varRegexp = regexp.MustCompile(`(?i)(\$+)\{([*-.a-z0-9_]+)\}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceVariables takes a configuration and a mapping of variables
|
|
||||||
// and performs the structure walking necessary to properly replace
|
|
||||||
// all the variables.
|
|
||||||
func ReplaceVariables(
|
|
||||||
c interface{},
|
|
||||||
vs map[string]string) ([]string, error) {
|
|
||||||
w := &variableReplaceWalker{Values: vs}
|
|
||||||
if err := reflectwalk.Walk(c, w); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.UnknownKeys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// variableDetectWalker implements interfaces for the reflectwalk package
|
|
||||||
// (github.com/mitchellh/reflectwalk) that can be used to automatically
|
|
||||||
// pull out the variables that need replacing.
|
|
||||||
type variableDetectWalker struct {
|
|
||||||
Variables map[string]InterpolatedVariable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableDetectWalker) Primitive(v reflect.Value) error {
|
|
||||||
// We only care about strings
|
|
||||||
if v.Kind() == reflect.Interface {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
if v.Kind() != reflect.String {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: This can be a lot more efficient if we used a real
|
|
||||||
// parser. A regexp is a hammer though that will get this working.
|
|
||||||
|
|
||||||
matches := varRegexp.FindAllStringSubmatch(v.String(), -1)
|
|
||||||
if len(matches) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
dollars := len(match[1])
|
|
||||||
|
|
||||||
// If there are even amounts of dollar signs, then it is escaped
|
|
||||||
if dollars%2 == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, record it
|
|
||||||
key := match[2]
|
|
||||||
if w.Variables == nil {
|
|
||||||
w.Variables = make(map[string]InterpolatedVariable)
|
|
||||||
}
|
|
||||||
if _, ok := w.Variables[key]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var iv InterpolatedVariable
|
|
||||||
if strings.Index(key, ".") == -1 {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Interpolated variable '%s' has bad format. "+
|
|
||||||
"Did you mean 'var.%s'?",
|
|
||||||
key, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(key, "var.") {
|
|
||||||
iv, err = NewResourceVariable(key)
|
|
||||||
} else {
|
|
||||||
varKey := key[len("var."):]
|
|
||||||
if strings.Index(varKey, ".") == -1 {
|
|
||||||
iv, err = NewUserVariable(key)
|
|
||||||
} else {
|
|
||||||
iv, err = NewUserMapVariable(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Variables[key] = iv
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// variableReplaceWalker implements interfaces for reflectwalk that
|
|
||||||
// is used to replace variables with their values.
|
|
||||||
//
|
|
||||||
// If Values does not have every available value, then the program
|
|
||||||
// will _panic_. The variableDetectWalker will tell you all variables
|
|
||||||
// you need.
|
|
||||||
type variableReplaceWalker struct {
|
|
||||||
Variables map[string]InterpolatedVariable
|
|
||||||
Values map[string]string
|
|
||||||
UnknownKeys []string
|
|
||||||
|
|
||||||
key []string
|
|
||||||
loc reflectwalk.Location
|
|
||||||
cs []reflect.Value
|
|
||||||
csData interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Enter(loc reflectwalk.Location) error {
|
|
||||||
w.loc = loc
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Exit(loc reflectwalk.Location) error {
|
|
||||||
w.loc = reflectwalk.None
|
|
||||||
|
|
||||||
switch loc {
|
|
||||||
case reflectwalk.Map:
|
|
||||||
w.cs = w.cs[:len(w.cs)-1]
|
|
||||||
case reflectwalk.MapValue:
|
|
||||||
w.key = w.key[:len(w.key)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Map(m reflect.Value) error {
|
|
||||||
w.cs = append(w.cs, m)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) MapElem(m, k, v reflect.Value) error {
|
|
||||||
w.csData = k
|
|
||||||
w.key = append(w.key, k.String())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Primitive(v reflect.Value) error {
|
|
||||||
// We only care about strings
|
|
||||||
setV := v
|
|
||||||
if v.Kind() == reflect.Interface {
|
|
||||||
setV = v
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
if v.Kind() != reflect.String {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
matches := varRegexp.FindAllStringSubmatch(v.String(), -1)
|
|
||||||
if len(matches) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result := v.String()
|
|
||||||
for _, match := range matches {
|
|
||||||
dollars := len(match[1])
|
|
||||||
|
|
||||||
// If there are even amounts of dollar signs, then it is escaped
|
|
||||||
if dollars%2 == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the key
|
|
||||||
key := match[2]
|
|
||||||
value, ok := w.Values[key]
|
|
||||||
if !ok {
|
|
||||||
panic("no value for variable key: " + key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an unknown variable, then we remove it from
|
|
||||||
// the configuration.
|
|
||||||
if value == UnknownVariableValue {
|
|
||||||
w.removeCurrent()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace
|
|
||||||
result = strings.Replace(result, match[0], value, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *variableReplaceWalker) removeCurrent() {
|
|
||||||
c := w.cs[len(w.cs)-1]
|
|
||||||
switch c.Kind() {
|
|
||||||
case reflect.Map:
|
|
||||||
// Zero value so that we delete the map key
|
|
||||||
var val reflect.Value
|
|
||||||
|
|
||||||
// Get the key and delete it
|
|
||||||
k := w.csData.(reflect.Value)
|
|
||||||
c.SetMapIndex(k, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the key to the unknown keys
|
|
||||||
w.UnknownKeys = append(w.UnknownKeys, strings.Join(w.key, "."))
|
|
||||||
}
|
|
|
@ -1,306 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/mitchellh/reflectwalk"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkVariableDetectWalker(b *testing.B) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
str := reflect.ValueOf(`foo ${var.bar} bar ${bar.baz.bing} $${escaped}`)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
w.Variables = nil
|
|
||||||
w.Primitive(str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkVariableReplaceWalker(b *testing.B) {
|
|
||||||
w := &variableReplaceWalker{
|
|
||||||
Values: map[string]string{
|
|
||||||
"var.bar": "bar",
|
|
||||||
"bar.baz.bing": "baz",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
str := `foo ${var.bar} bar ${bar.baz.bing} $${escaped}`
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
if err := reflectwalk.Walk(&str, w); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReplaceVariables(t *testing.T) {
|
|
||||||
input := "foo-${var.bar}"
|
|
||||||
expected := "foo-bar"
|
|
||||||
|
|
||||||
unk, err := ReplaceVariables(&input, map[string]string{
|
|
||||||
"var.bar": "bar",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
if len(unk) > 0 {
|
|
||||||
t.Fatal("bad: %#v", unk)
|
|
||||||
}
|
|
||||||
|
|
||||||
if input != expected {
|
|
||||||
t.Fatalf("bad: %#v", input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo ${var.bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) != 1 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
if w.Variables["var.bar"].(*UserVariable).FullKey() != "var.bar" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_resource(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo ${ec2.foo.bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) != 1 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
if w.Variables["ec2.foo.bar"].(*ResourceVariable).FullKey() != "ec2.foo.bar" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_resourceMulti(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo ${ec2.foo.*.bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) != 1 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
if w.Variables["ec2.foo.*.bar"].(*ResourceVariable).FullKey() != "ec2.foo.*.bar" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_bad(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo ${bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err == nil {
|
|
||||||
t.Fatal("should error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_escaped(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo $${var.bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_empty(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableDetectWalker_userMap(t *testing.T) {
|
|
||||||
w := new(variableDetectWalker)
|
|
||||||
|
|
||||||
str := `foo ${var.foo.bar}`
|
|
||||||
if err := w.Primitive(reflect.ValueOf(str)); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Variables) != 1 {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
|
|
||||||
v := w.Variables["var.foo.bar"].(*UserMapVariable)
|
|
||||||
if v.FullKey() != "var.foo.bar" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
if v.Name != "foo" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
if v.Elem != "bar" {
|
|
||||||
t.Fatalf("bad: %#v", w.Variables)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableReplaceWalker(t *testing.T) {
|
|
||||||
w := &variableReplaceWalker{
|
|
||||||
Values: map[string]string{
|
|
||||||
"var.bar": "bar",
|
|
||||||
"var.unknown": UnknownVariableValue,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
Input interface{}
|
|
||||||
Output interface{}
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
`foo ${var.bar}`,
|
|
||||||
"foo bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]string{"foo", "${var.bar}"},
|
|
||||||
[]string{"foo", "bar"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"ami": "${var.bar}",
|
|
||||||
"security_groups": []interface{}{
|
|
||||||
"foo",
|
|
||||||
"${var.bar}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"ami": "bar",
|
|
||||||
"security_groups": []interface{}{
|
|
||||||
"foo",
|
|
||||||
"bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": map[string]interface{}{
|
|
||||||
"foo": []string{"${var.bar}"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": map[string]interface{}{
|
|
||||||
"foo": []string{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
"bar": "hello${var.unknown}world",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": []string{"foo", "${var.unknown}", "bar"},
|
|
||||||
},
|
|
||||||
map[string]interface{}{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
var input interface{} = tc.Input
|
|
||||||
if reflect.ValueOf(tc.Input).Kind() == reflect.String {
|
|
||||||
input = &tc.Input
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := reflectwalk.Walk(input, w); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tc.Input, tc.Output) {
|
|
||||||
t.Fatalf("bad %d: %#v", i, tc.Input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariableReplaceWalker_unknown(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Input interface{}
|
|
||||||
Output interface{}
|
|
||||||
Keys []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
"bar": "hello${var.unknown}world",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
[]string{"bar"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": []string{"foo", "${var.unknown}", "bar"},
|
|
||||||
},
|
|
||||||
map[string]interface{}{},
|
|
||||||
[]string{"foo"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": map[string]interface{}{
|
|
||||||
"bar": "${var.unknown}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"foo": map[string]interface{}{},
|
|
||||||
},
|
|
||||||
[]string{"foo.bar"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
var input interface{} = tc.Input
|
|
||||||
w := &variableReplaceWalker{
|
|
||||||
Values: map[string]string{
|
|
||||||
"var.unknown": UnknownVariableValue,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if reflect.ValueOf(tc.Input).Kind() == reflect.String {
|
|
||||||
input = &tc.Input
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := reflectwalk.Walk(input, w); err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tc.Input, tc.Output) {
|
|
||||||
t.Fatalf("bad %d: %#v", i, tc.Input)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(tc.Keys, w.UnknownKeys) {
|
|
||||||
t.Fatalf("bad: %#v", w.UnknownKeys)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue