From aa2c7b2764e6a1feb5d05f6b6ff8d805b096c4ed Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 12 Jan 2015 12:09:30 -0800 Subject: [PATCH] config: DetectVariables to detect interpolated variables in an AST --- config/interpolate.go | 38 ++++++++++++++++++++++++++++++ config/interpolate_test.go | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/config/interpolate.go b/config/interpolate.go index e96b6b76c..3e95642e0 100644 --- a/config/interpolate.go +++ b/config/interpolate.go @@ -5,6 +5,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/hashicorp/terraform/config/lang/ast" ) // We really need to replace this with a real parser. @@ -317,3 +319,39 @@ func (v *UserVariable) FullKey() string { func (v *UserVariable) GoString() string { return fmt.Sprintf("*%#v", *v) } + +// DetectVariables takes an AST root and returns all the interpolated +// variables that are detected in the AST tree. +func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) { + var result []InterpolatedVariable + var resultErr error + + // Visitor callback + fn := func(n ast.Node) { + if resultErr != nil { + return + } + + vn, ok := n.(*ast.VariableAccess) + if !ok { + return + } + + v, err := NewInterpolatedVariable(vn.Name) + if err != nil { + resultErr = err + return + } + + result = append(result, v) + } + + // Visitor pattern + root.Accept(fn) + + if resultErr != nil { + return nil, resultErr + } + + return result, nil +} diff --git a/config/interpolate_test.go b/config/interpolate_test.go index 9ecbb9a71..5af01841f 100644 --- a/config/interpolate_test.go +++ b/config/interpolate_test.go @@ -4,6 +4,8 @@ import ( "reflect" "strings" "testing" + + "github.com/hashicorp/terraform/config/lang" ) func TestNewInterpolatedVariable(t *testing.T) { @@ -291,3 +293,49 @@ func TestVariableInterpolation_missing(t *testing.T) { t.Fatal("should error") } } + +func TestDetectVariables(t *testing.T) { + cases := []struct { + Input string + Result []InterpolatedVariable + }{ + { + "foo ${var.foo}", + []InterpolatedVariable{ + &UserVariable{ + Name: "foo", + key: "var.foo", + }, + }, + }, + + { + "foo ${var.foo} ${var.bar}", + []InterpolatedVariable{ + &UserVariable{ + Name: "foo", + key: "var.foo", + }, + &UserVariable{ + Name: "bar", + key: "var.bar", + }, + }, + }, + } + + for _, tc := range cases { + ast, err := lang.Parse(tc.Input) + if err != nil { + t.Fatalf("%s\n\nInput: %s", err, tc.Input) + } + + actual, err := DetectVariables(ast) + if err != nil { + t.Fatalf("err: %s", err) + } + if !reflect.DeepEqual(actual, tc.Result) { + t.Fatalf("bad: %#v\n\nInput: %s", actual, tc.Input) + } + } +}