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
}
func (v *ModuleVariable) GoString() string {
return fmt.Sprintf("*%#v", *v)
}
func NewPathVariable(key string) (*PathVariable, error) {
var fieldType PathValueType
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 {

View File

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

View File

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

View File

@ -127,27 +127,6 @@ func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
config := langEvalConfig(vs)
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
// be able to properly evaluate.
result, err := hil.Eval(root, config)

View File

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