config: use new API

This commit is contained in:
Mitchell Hashimoto 2015-01-14 22:01:42 -08:00
parent 61ee63d842
commit 2abeb2d9ac
12 changed files with 67 additions and 68 deletions

View File

@ -359,9 +359,10 @@ func (c *Config) Validate() error {
r.RawCount.interpolate(func(root ast.Node) (string, error) { r.RawCount.interpolate(func(root ast.Node) (string, error) {
// Execute the node but transform the AST so that it returns // Execute the node but transform the AST so that it returns
// a fixed value of "5" for all interpolations. // a fixed value of "5" for all interpolations.
var engine lang.Engine out, _, err := lang.Eval(
out, _, err := engine.Execute(lang.FixedValueTransform( lang.FixedValueTransform(
root, &ast.LiteralNode{Value: "5", Type: ast.TypeString})) root, &ast.LiteralNode{Value: "5", Typex: ast.TypeString}),
nil)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -230,23 +230,24 @@ func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) {
var resultErr error var resultErr error
// Visitor callback // Visitor callback
fn := func(n ast.Node) { fn := func(n ast.Node) ast.Node {
if resultErr != nil { if resultErr != nil {
return return n
} }
vn, ok := n.(*ast.VariableAccess) vn, ok := n.(*ast.VariableAccess)
if !ok { if !ok {
return return n
} }
v, err := NewInterpolatedVariable(vn.Name) v, err := NewInterpolatedVariable(vn.Name)
if err != nil { if err != nil {
resultErr = err resultErr = err
return return n
} }
result = append(result, v) result = append(result, v)
return n
} }
// Visitor pattern // Visitor pattern

View File

@ -7,15 +7,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast" "github.com/hashicorp/terraform/config/lang/ast"
) )
// Funcs is the mapping of built-in functions for configuration. // Funcs is the mapping of built-in functions for configuration.
var Funcs map[string]lang.Function var Funcs map[string]ast.Function
func init() { func init() {
Funcs = map[string]lang.Function{ Funcs = map[string]ast.Function{
"concat": interpolationFuncConcat(), "concat": interpolationFuncConcat(),
"file": interpolationFuncFile(), "file": interpolationFuncFile(),
"join": interpolationFuncJoin(), "join": interpolationFuncJoin(),
@ -27,8 +26,8 @@ func init() {
// concatenates multiple strings. This isn't actually necessary anymore // concatenates multiple strings. This isn't actually necessary anymore
// since our language supports string concat natively, but for backwards // since our language supports string concat natively, but for backwards
// compat we do this. // compat we do this.
func interpolationFuncConcat() lang.Function { func interpolationFuncConcat() ast.Function {
return lang.Function{ return ast.Function{
ArgTypes: []ast.Type{ast.TypeString}, ArgTypes: []ast.Type{ast.TypeString},
ReturnType: ast.TypeString, ReturnType: ast.TypeString,
Variadic: true, Variadic: true,
@ -46,8 +45,8 @@ func interpolationFuncConcat() lang.Function {
// interpolationFuncFile implements the "file" function that allows // interpolationFuncFile implements the "file" function that allows
// loading contents from a file. // loading contents from a file.
func interpolationFuncFile() lang.Function { func interpolationFuncFile() ast.Function {
return lang.Function{ return ast.Function{
ArgTypes: []ast.Type{ast.TypeString}, ArgTypes: []ast.Type{ast.TypeString},
ReturnType: ast.TypeString, ReturnType: ast.TypeString,
Callback: func(args []interface{}) (interface{}, error) { Callback: func(args []interface{}) (interface{}, error) {
@ -63,8 +62,8 @@ func interpolationFuncFile() lang.Function {
// interpolationFuncJoin implements the "join" function that allows // interpolationFuncJoin implements the "join" function that allows
// multi-variable values to be joined by some character. // multi-variable values to be joined by some character.
func interpolationFuncJoin() lang.Function { func interpolationFuncJoin() ast.Function {
return lang.Function{ return ast.Function{
ArgTypes: []ast.Type{ast.TypeString, ast.TypeString}, ArgTypes: []ast.Type{ast.TypeString, ast.TypeString},
ReturnType: ast.TypeString, ReturnType: ast.TypeString,
Callback: func(args []interface{}) (interface{}, error) { Callback: func(args []interface{}) (interface{}, error) {
@ -81,8 +80,8 @@ func interpolationFuncJoin() lang.Function {
// interpolationFuncLookup implements the "lookup" function that allows // interpolationFuncLookup implements the "lookup" function that allows
// dynamic lookups of map types within a Terraform configuration. // dynamic lookups of map types within a Terraform configuration.
func interpolationFuncLookup(vs map[string]lang.Variable) lang.Function { func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
return lang.Function{ return ast.Function{
ArgTypes: []ast.Type{ast.TypeString, ast.TypeString}, ArgTypes: []ast.Type{ast.TypeString, ast.TypeString},
ReturnType: ast.TypeString, ReturnType: ast.TypeString,
Callback: func(args []interface{}) (interface{}, error) { Callback: func(args []interface{}) (interface{}, error) {
@ -107,8 +106,8 @@ func interpolationFuncLookup(vs map[string]lang.Variable) lang.Function {
// interpolationFuncElement implements the "element" function that allows // interpolationFuncElement implements the "element" function that allows
// a specific index to be looked up in a multi-variable value. Note that this will // a specific index to be looked up in a multi-variable value. Note that this will
// wrap if the index is larger than the number of elements in the multi-variable value. // wrap if the index is larger than the number of elements in the multi-variable value.
func interpolationFuncElement() lang.Function { func interpolationFuncElement() ast.Function {
return lang.Function{ return ast.Function{
ArgTypes: []ast.Type{ast.TypeString, ast.TypeString}, ArgTypes: []ast.Type{ast.TypeString, ast.TypeString},
ReturnType: ast.TypeString, ReturnType: ast.TypeString,
Callback: func(args []interface{}) (interface{}, error) { Callback: func(args []interface{}) (interface{}, error) {

View File

@ -109,8 +109,8 @@ func TestInterpolateFuncJoin(t *testing.T) {
func TestInterpolateFuncLookup(t *testing.T) { func TestInterpolateFuncLookup(t *testing.T) {
testFunction(t, testFunctionConfig{ testFunction(t, testFunctionConfig{
Vars: map[string]lang.Variable{ Vars: map[string]ast.Variable{
"var.foo.bar": lang.Variable{ "var.foo.bar": ast.Variable{
Value: "baz", Value: "baz",
Type: ast.TypeString, Type: ast.TypeString,
}, },
@ -176,7 +176,7 @@ func TestInterpolateFuncElement(t *testing.T) {
type testFunctionConfig struct { type testFunctionConfig struct {
Cases []testFunctionCase Cases []testFunctionCase
Vars map[string]lang.Variable Vars map[string]ast.Variable
} }
type testFunctionCase struct { type testFunctionCase struct {
@ -192,8 +192,7 @@ func testFunction(t *testing.T, config testFunctionConfig) {
t.Fatalf("%d: err: %s", i, err) t.Fatalf("%d: err: %s", i, err)
} }
engine := langEngine(config.Vars) out, _, err := lang.Eval(ast, langEvalConfig(config.Vars))
out, _, err := engine.Execute(ast)
if (err != nil) != tc.Error { if (err != nil) != tc.Error {
t.Fatalf("%d: err: %s", i, err) t.Fatalf("%d: err: %s", i, err)
} }

View File

@ -25,7 +25,7 @@ func (n *LiteralNode) GoString() string {
} }
func (n *LiteralNode) String() string { func (n *LiteralNode) String() string {
return fmt.Sprintf("Literal(%s, %v)", n.Type, n.Value) return fmt.Sprintf("Literal(%s, %v)", n.Typex, n.Value)
} }
func (n *LiteralNode) Type(Scope) (Type, error) { func (n *LiteralNode) Type(Scope) (Type, error) {

View File

@ -40,7 +40,7 @@ func (c *IdentifierCheck) visit(raw ast.Node) ast.Node {
case *ast.LiteralNode: case *ast.LiteralNode:
// Ignore // Ignore
default: default:
c.createErr(n, fmt.Sprintf("unknown node: %#v", raw)) // Ignore
} }
// We never do replacement with this visitor // We never do replacement with this visitor

View File

@ -27,6 +27,9 @@ type SemanticChecker func(ast.Node) error
// of the output, and any error that occurred. // of the output, and any error that occurred.
func Eval(root ast.Node, config *EvalConfig) (interface{}, ast.Type, error) { func Eval(root ast.Node, config *EvalConfig) (interface{}, ast.Type, error) {
// Copy the scope so we can add our builtins // Copy the scope so we can add our builtins
if config == nil {
config = new(EvalConfig)
}
scope := registerBuiltins(config.GlobalScope) scope := registerBuiltins(config.GlobalScope)
implicitMap := map[ast.Type]map[ast.Type]string{ implicitMap := map[ast.Type]map[ast.Type]string{
ast.TypeInt: { ast.TypeInt: {

View File

@ -80,10 +80,10 @@ func (r *RawConfig) Config() map[string]interface{} {
// Any prior calls to Interpolate are replaced with this one. // Any prior calls to Interpolate are replaced with this one.
// //
// If a variable key is missing, this will panic. // If a variable key is missing, this will panic.
func (r *RawConfig) Interpolate(vs map[string]lang.Variable) error { func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
engine := langEngine(vs) config := langEvalConfig(vs)
return r.interpolate(func(root ast.Node) (string, error) { return r.interpolate(func(root ast.Node) (string, error) {
out, _, err := engine.Execute(root) out, _, err := lang.Eval(root, config)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -202,16 +202,16 @@ type gobRawConfig struct {
Raw map[string]interface{} Raw map[string]interface{}
} }
// langEngine returns the lang.Engine to use for evaluating configurations. // langEvalConfig returns the evaluation configuration we use to execute.
func langEngine(vs map[string]lang.Variable) *lang.Engine { func langEvalConfig(vs map[string]ast.Variable) *lang.EvalConfig {
funcMap := make(map[string]lang.Function) funcMap := make(map[string]ast.Function)
for k, v := range Funcs { for k, v := range Funcs {
funcMap[k] = v funcMap[k] = v
} }
funcMap["lookup"] = interpolationFuncLookup(vs) funcMap["lookup"] = interpolationFuncLookup(vs)
return &lang.Engine{ return &lang.EvalConfig{
GlobalScope: &lang.Scope{ GlobalScope: &ast.BasicScope{
VarMap: vs, VarMap: vs,
FuncMap: funcMap, FuncMap: funcMap,
}, },

View File

@ -5,7 +5,6 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast" "github.com/hashicorp/terraform/config/lang/ast"
) )
@ -43,8 +42,8 @@ func TestRawConfig(t *testing.T) {
t.Fatalf("bad: %#v", rc.Config()) t.Fatalf("bad: %#v", rc.Config())
} }
vars := map[string]lang.Variable{ vars := map[string]ast.Variable{
"var.bar": lang.Variable{ "var.bar": ast.Variable{
Value: "baz", Value: "baz",
Type: ast.TypeString, Type: ast.TypeString,
}, },
@ -76,8 +75,8 @@ func TestRawConfig_double(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
vars := map[string]lang.Variable{ vars := map[string]ast.Variable{
"var.bar": lang.Variable{ "var.bar": ast.Variable{
Value: "baz", Value: "baz",
Type: ast.TypeString, Type: ast.TypeString,
}, },
@ -95,8 +94,8 @@ func TestRawConfig_double(t *testing.T) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
vars = map[string]lang.Variable{ vars = map[string]ast.Variable{
"var.bar": lang.Variable{ "var.bar": ast.Variable{
Value: "what", Value: "what",
Type: ast.TypeString, Type: ast.TypeString,
}, },
@ -135,8 +134,8 @@ func TestRawConfig_unknown(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
vars := map[string]lang.Variable{ vars := map[string]ast.Variable{
"var.bar": lang.Variable{ "var.bar": ast.Variable{
Value: UnknownVariableValue, Value: UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeString,
}, },
@ -178,8 +177,8 @@ func TestRawConfigValue(t *testing.T) {
t.Fatalf("err: %#v", rc.Value()) t.Fatalf("err: %#v", rc.Value())
} }
vars := map[string]lang.Variable{ vars := map[string]ast.Variable{
"var.bar": lang.Variable{ "var.bar": ast.Variable{
Value: "baz", Value: "baz",
Type: ast.TypeString, Type: ast.TypeString,
}, },

View File

@ -8,7 +8,6 @@ import (
"testing" "testing"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast" "github.com/hashicorp/terraform/config/lang/ast"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -23,9 +22,9 @@ func testConfig(
} }
if len(vs) > 0 { if len(vs) > 0 {
vars := make(map[string]lang.Variable) vars := make(map[string]ast.Variable)
for k, v := range vs { for k, v := range vs {
vars[k] = lang.Variable{Value: v, Type: ast.TypeString} vars[k] = ast.Variable{Value: v, Type: ast.TypeString}
} }
if err := rc.Interpolate(vars); err != nil { if err := rc.Interpolate(vars); err != nil {

View File

@ -5,7 +5,6 @@ import (
"testing" "testing"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast" "github.com/hashicorp/terraform/config/lang/ast"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -1808,9 +1807,9 @@ func TestSchemaMap_Diff(t *testing.T) {
} }
if len(tc.ConfigVariables) > 0 { if len(tc.ConfigVariables) > 0 {
vars := make(map[string]lang.Variable) vars := make(map[string]ast.Variable)
for k, v := range tc.ConfigVariables { for k, v := range tc.ConfigVariables {
vars[k] = lang.Variable{Value: v, Type: ast.TypeString} vars[k] = ast.Variable{Value: v, Type: ast.TypeString}
} }
if err := c.Interpolate(vars); err != nil { if err := c.Interpolate(vars); err != nil {
@ -2585,9 +2584,9 @@ func TestSchemaMap_Validate(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if tc.Vars != nil { if tc.Vars != nil {
vars := make(map[string]lang.Variable) vars := make(map[string]ast.Variable)
for k, v := range tc.Vars { for k, v := range tc.Vars {
vars[k] = lang.Variable{Value: v, Type: ast.TypeString} vars[k] = ast.Variable{Value: v, Type: ast.TypeString}
} }
if err := c.Interpolate(vars); err != nil { if err := c.Interpolate(vars); err != nil {

View File

@ -11,7 +11,6 @@ import (
"sync/atomic" "sync/atomic"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast" "github.com/hashicorp/terraform/config/lang/ast"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/depgraph" "github.com/hashicorp/terraform/depgraph"
@ -1522,9 +1521,9 @@ func (c *walkContext) computeVars(
} }
// Copy the default variables // Copy the default variables
vs := make(map[string]lang.Variable) vs := make(map[string]ast.Variable)
for k, v := range c.defaultVariables { for k, v := range c.defaultVariables {
vs[k] = lang.Variable{ vs[k] = ast.Variable{
Value: v, Value: v,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1537,7 +1536,7 @@ func (c *walkContext) computeVars(
switch v.Type { switch v.Type {
case config.CountValueIndex: case config.CountValueIndex:
if r != nil { if r != nil {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: int(r.CountIndex), Value: int(r.CountIndex),
Type: ast.TypeInt, Type: ast.TypeInt,
} }
@ -1545,7 +1544,7 @@ func (c *walkContext) computeVars(
} }
case *config.ModuleVariable: case *config.ModuleVariable:
if c.Operation == walkValidate { if c.Operation == walkValidate {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: config.UnknownVariableValue, Value: config.UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1557,7 +1556,7 @@ func (c *walkContext) computeVars(
return err return err
} }
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: value, Value: value,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1571,26 +1570,26 @@ func (c *walkContext) computeVars(
v.FullKey(), err) v.FullKey(), err)
} }
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: wd, Value: wd,
Type: ast.TypeString, Type: ast.TypeString,
} }
case config.PathValueModule: case config.PathValueModule:
if t := c.Context.module.Child(c.Path[1:]); t != nil { if t := c.Context.module.Child(c.Path[1:]); t != nil {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: t.Config().Dir, Value: t.Config().Dir,
Type: ast.TypeString, Type: ast.TypeString,
} }
} }
case config.PathValueRoot: case config.PathValueRoot:
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: c.Context.module.Config().Dir, Value: c.Context.module.Config().Dir,
Type: ast.TypeString, Type: ast.TypeString,
} }
} }
case *config.ResourceVariable: case *config.ResourceVariable:
if c.Operation == walkValidate { if c.Operation == walkValidate {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: config.UnknownVariableValue, Value: config.UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1608,14 +1607,14 @@ func (c *walkContext) computeVars(
return err return err
} }
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: attr, Value: attr,
Type: ast.TypeString, Type: ast.TypeString,
} }
case *config.UserVariable: case *config.UserVariable:
val, ok := c.Variables[v.Name] val, ok := c.Variables[v.Name]
if ok { if ok {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: val, Value: val,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1623,7 +1622,7 @@ func (c *walkContext) computeVars(
} }
if _, ok := vs[n]; !ok && c.Operation == walkValidate { if _, ok := vs[n]; !ok && c.Operation == walkValidate {
vs[n] = lang.Variable{ vs[n] = ast.Variable{
Value: config.UnknownVariableValue, Value: config.UnknownVariableValue,
Type: ast.TypeString, Type: ast.TypeString,
} }
@ -1634,7 +1633,7 @@ func (c *walkContext) computeVars(
// those are map overrides. Include those. // those are map overrides. Include those.
for k, val := range c.Variables { for k, val := range c.Variables {
if strings.HasPrefix(k, v.Name+".") { if strings.HasPrefix(k, v.Name+".") {
vs["var."+k] = lang.Variable{ vs["var."+k] = ast.Variable{
Value: val, Value: val,
Type: ast.TypeString, Type: ast.TypeString,
} }