config: use ast.TypeUnknown and don't remove computed values

This commit is contained in:
Mitchell Hashimoto 2016-10-26 23:24:23 -04:00
parent f7d6fb368a
commit b979d8927e
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
6 changed files with 39 additions and 30 deletions

View File

@ -149,6 +149,10 @@ func (v *ModuleVariable) FullKey() string {
return v.key return v.key
} }
func (v *ModuleVariable) GoString() string {
return fmt.Sprintf("*%#v", *v)
}
func NewPathVariable(key string) (*PathVariable, error) { func NewPathVariable(key string) (*PathVariable, error) {
var fieldType PathValueType var fieldType PathValueType
parts := strings.SplitN(key, ".", 2) parts := strings.SplitN(key, ".", 2)

View File

@ -240,6 +240,22 @@ func TestDetectVariables(t *testing.T) {
}, },
}, },
}, },
{
`foo ${module.foo.output["key"]}`,
[]InterpolatedVariable{
&ModuleVariable{
Name: "foo",
Field: "output",
key: "module.foo.output",
},
&ModuleVariable{
Name: "foo",
Field: "output",
key: "module.foo.output",
},
},
},
} }
for _, tc := range cases { for _, tc := range cases {

View File

@ -176,8 +176,11 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
} }
if remove { if remove {
w.removeCurrent() // Append the key to the unknown keys
return nil w.unknownKeys = append(w.unknownKeys, strings.Join(w.key, "."))
//w.removeCurrent()
//return nil
} }
resultVal := reflect.ValueOf(replaceVal) resultVal := reflect.ValueOf(replaceVal)

View File

@ -169,7 +169,13 @@ func TestInterpolationWalker_replace(t *testing.T) {
"bing", "bing",
}, },
}, },
Output: map[string]interface{}{}, Output: map[string]interface{}{
"foo": []interface{}{
UnknownVariableValue,
"baz",
"bing",
},
},
Value: []interface{}{UnknownVariableValue, "baz"}, Value: []interface{}{UnknownVariableValue, "baz"},
}, },
} }

View File

@ -127,27 +127,6 @@ func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
config := langEvalConfig(vs) config := langEvalConfig(vs)
return r.interpolate(func(root ast.Node) (interface{}, error) { return r.interpolate(func(root ast.Node) (interface{}, error) {
// We detect the variables again and check if the value of any
// of the variables is the computed value. If it is, then we
// treat this entire value as computed.
//
// We have to do this here before the `lang.Eval` because
// if any of the variables it depends on are computed, then
// the interpolation can fail at runtime for other reasons. Example:
// `${count.index+1}`: in a world where `count.index` is computed,
// this would fail a type check since the computed placeholder is
// a string, but realistically the whole value is just computed.
vars, err := DetectVariables(root)
if err != nil {
return "", err
}
for _, v := range vars {
varVal, ok := vs[v.FullKey()]
if ok && varVal.Value == UnknownVariableValue {
return UnknownVariableValue, nil
}
}
// None of the variables we need are computed, meaning we should // None of the variables we need are computed, meaning we should
// be able to properly evaluate. // be able to properly evaluate.
result, err := hil.Eval(root, config) result, err := hil.Eval(root, config)

View File

@ -191,7 +191,7 @@ func TestRawConfig_merge(t *testing.T) {
}, },
"var.baz": ast.Variable{ "var.baz": ast.Variable{
Value: UnknownVariableValue, Value: UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeUnknown,
}, },
} }
if err := rc2.Interpolate(vars); err != nil { if err := rc2.Interpolate(vars); err != nil {
@ -216,6 +216,7 @@ func TestRawConfig_merge(t *testing.T) {
expected := map[string]interface{}{ expected := map[string]interface{}{
"foo": "foovalue", "foo": "foovalue",
"bar": "barvalue", "bar": "barvalue",
"baz": UnknownVariableValue,
} }
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
@ -250,7 +251,7 @@ func TestRawConfig_unknown(t *testing.T) {
vars := map[string]ast.Variable{ vars := map[string]ast.Variable{
"var.bar": ast.Variable{ "var.bar": ast.Variable{
Value: UnknownVariableValue, Value: UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeUnknown,
}, },
} }
if err := rc.Interpolate(vars); err != nil { if err := rc.Interpolate(vars); err != nil {
@ -258,7 +259,7 @@ func TestRawConfig_unknown(t *testing.T) {
} }
actual := rc.Config() actual := rc.Config()
expected := map[string]interface{}{} expected := map[string]interface{}{"foo": UnknownVariableValue}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
@ -283,7 +284,7 @@ func TestRawConfig_unknownPartial(t *testing.T) {
vars := map[string]ast.Variable{ vars := map[string]ast.Variable{
"var.bar": ast.Variable{ "var.bar": ast.Variable{
Value: UnknownVariableValue, Value: UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeUnknown,
}, },
} }
if err := rc.Interpolate(vars); err != nil { if err := rc.Interpolate(vars); err != nil {
@ -291,7 +292,7 @@ func TestRawConfig_unknownPartial(t *testing.T) {
} }
actual := rc.Config() actual := rc.Config()
expected := map[string]interface{}{} expected := map[string]interface{}{"foo": UnknownVariableValue}
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)