config: parsing of local.foo variables for interpolation

This commit is contained in:
Martin Atkins 2017-07-01 09:23:42 -07:00
parent f6797d6cb0
commit d41d58967f
2 changed files with 56 additions and 12 deletions

View File

@ -101,6 +101,12 @@ type UserVariable struct {
key string key string
} }
// A LocalVariable is a variable that references a local value defined within
// the current module, via a "locals" block. This looks like "${local.foo}".
type LocalVariable struct {
Name string
}
func NewInterpolatedVariable(v string) (InterpolatedVariable, error) { func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
if strings.HasPrefix(v, "count.") { if strings.HasPrefix(v, "count.") {
return NewCountVariable(v) return NewCountVariable(v)
@ -112,6 +118,8 @@ func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
return NewTerraformVariable(v) return NewTerraformVariable(v)
} else if strings.HasPrefix(v, "var.") { } else if strings.HasPrefix(v, "var.") {
return NewUserVariable(v) return NewUserVariable(v)
} else if strings.HasPrefix(v, "local.") {
return NewLocalVariable(v)
} else if strings.HasPrefix(v, "module.") { } else if strings.HasPrefix(v, "module.") {
return NewModuleVariable(v) return NewModuleVariable(v)
} else if !strings.ContainsRune(v, '.') { } else if !strings.ContainsRune(v, '.') {
@ -331,6 +339,25 @@ func (v *UserVariable) GoString() string {
return fmt.Sprintf("*%#v", *v) return fmt.Sprintf("*%#v", *v)
} }
func NewLocalVariable(key string) (*LocalVariable, error) {
name := key[len("local."):]
if idx := strings.Index(name, "."); idx > -1 {
return nil, fmt.Errorf("Can't use dot (.) attribute access in local.%s; use square bracket indexing", name)
}
return &LocalVariable{
Name: name,
}, nil
}
func (v *LocalVariable) FullKey() string {
return fmt.Sprintf("local.%s", v.Name)
}
func (v *LocalVariable) GoString() string {
return fmt.Sprintf("*%#v", *v)
}
// DetectVariables takes an AST root and returns all the interpolated // DetectVariables takes an AST root and returns all the interpolated
// variables that are detected in the AST tree. // variables that are detected in the AST tree.
func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) { func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) {

View File

@ -9,10 +9,10 @@ import (
) )
func TestNewInterpolatedVariable(t *testing.T) { func TestNewInterpolatedVariable(t *testing.T) {
cases := []struct { tests := []struct {
Input string Input string
Result InterpolatedVariable Want InterpolatedVariable
Error bool Error bool
}{ }{
{ {
"var.foo", "var.foo",
@ -22,6 +22,18 @@ func TestNewInterpolatedVariable(t *testing.T) {
}, },
false, false,
}, },
{
"local.foo",
&LocalVariable{
Name: "foo",
},
false,
},
{
"local.foo.nope",
nil,
true,
},
{ {
"module.foo.bar", "module.foo.bar",
&ModuleVariable{ &ModuleVariable{
@ -73,14 +85,19 @@ func TestNewInterpolatedVariable(t *testing.T) {
}, },
} }
for i, tc := range cases { for i, test := range tests {
actual, err := NewInterpolatedVariable(tc.Input) t.Run(test.Input, func(t *testing.T) {
if err != nil != tc.Error { got, err := NewInterpolatedVariable(test.Input)
t.Fatalf("%d. Error: %s", i, err) if err != nil != test.Error {
} t.Errorf("%d. Error: %s", i, err)
if !reflect.DeepEqual(actual, tc.Result) { }
t.Fatalf("%d bad: %#v", i, actual) if !test.Error && !reflect.DeepEqual(got, test.Want) {
} t.Errorf(
"wrong result\ninput: %s\ngot: %#v\nwant: %#v",
test.Input, got, test.Want,
)
}
})
} }
} }