config: add lookup function back

This commit is contained in:
Mitchell Hashimoto 2015-01-13 12:06:04 -08:00
parent 49fe0d5c7f
commit 4af4c9e16c
3 changed files with 124 additions and 132 deletions

View File

@ -15,9 +15,8 @@ var Funcs map[string]lang.Function
func init() {
Funcs = map[string]lang.Function{
"file": interpolationFuncFile(),
"join": interpolationFuncJoin(),
//"lookup": interpolationFuncLookup(),
"file": interpolationFuncFile(),
"join": interpolationFuncJoin(),
"element": interpolationFuncElement(),
}
}
@ -59,22 +58,22 @@ func interpolationFuncJoin() lang.Function {
// interpolationFuncLookup implements the "lookup" function that allows
// dynamic lookups of map types within a Terraform configuration.
func interpolationFuncLookup(
vs map[string]string, args ...string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf(
"lookup expects 2 arguments, got %d", len(args))
}
func interpolationFuncLookup(vs map[string]string) lang.Function {
return lang.Function{
ArgTypes: []ast.Type{ast.TypeString, ast.TypeString},
ReturnType: ast.TypeString,
Callback: func(args []interface{}) (interface{}, error) {
k := fmt.Sprintf("var.%s.%s", args[0].(string), args[1].(string))
v, ok := vs[k]
if !ok {
return "", fmt.Errorf(
"lookup in '%s' failed to find '%s'",
args[0].(string), args[1].(string))
}
k := fmt.Sprintf("var.%s", strings.Join(args, "."))
v, ok := vs[k]
if !ok {
return "", fmt.Errorf(
"lookup in '%s' failed to find '%s'",
args[0], args[1])
return v, nil
},
}
return v, nil
}
// interpolationFuncElement implements the "element" function that allows

View File

@ -20,163 +20,149 @@ func TestInterpolateFuncFile(t *testing.T) {
tf.Close()
defer os.Remove(path)
testFunction(t, []testFunctionCase{
{
fmt.Sprintf(`${file("%s")}`, path),
"foo",
false,
},
testFunction(t, testFunctionConfig{
Cases: []testFunctionCase{
{
fmt.Sprintf(`${file("%s")}`, path),
"foo",
false,
},
// Invalid path
{
`${file("/i/dont/exist")}`,
nil,
true,
},
// Invalid path
{
`${file("/i/dont/exist")}`,
nil,
true,
},
// Too many args
{
`${file("foo", "bar")}`,
nil,
true,
// Too many args
{
`${file("foo", "bar")}`,
nil,
true,
},
},
})
}
func TestInterpolateFuncJoin(t *testing.T) {
testFunction(t, []testFunctionCase{
{
`${join(",")}`,
nil,
true,
},
{
`${join(",", "foo")}`,
"foo",
false,
},
/*
TODO
testFunction(t, testFunctionConfig{
Cases: []testFunctionCase{
{
`${join(",", "foo", "bar")}`,
"foo,bar",
`${join(",")}`,
nil,
true,
},
{
`${join(",", "foo")}`,
"foo",
false,
},
*/
{
fmt.Sprintf(`${join(".", "%s")}`,
fmt.Sprintf(
"foo%sbar%sbaz",
InterpSplitDelim,
InterpSplitDelim)),
"foo.bar.baz",
false,
/*
TODO
{
`${join(",", "foo", "bar")}`,
"foo,bar",
false,
},
*/
{
fmt.Sprintf(`${join(".", "%s")}`,
fmt.Sprintf(
"foo%sbar%sbaz",
InterpSplitDelim,
InterpSplitDelim)),
"foo.bar.baz",
false,
},
},
})
}
/*
func TestInterpolateFuncLookup(t *testing.T) {
testFunction(t, []testFunctionCase{
cases := []struct {
M map[string]string
Args []string
Result string
Error bool
}{
{
map[string]string{
"var.foo.bar": "baz",
testFunction(t, testFunctionConfig{
Vars: map[string]string{"var.foo.bar": "baz"},
Cases: []testFunctionCase{
{
`${lookup("foo", "bar")}`,
"baz",
false,
},
[]string{"foo", "bar"},
"baz",
false,
},
// Invalid key
{
map[string]string{
"var.foo.bar": "baz",
// Invalid key
{
`${lookup("foo", "baz")}`,
nil,
true,
},
[]string{"foo", "baz"},
"",
true,
},
// Too many args
{
map[string]string{
"var.foo.bar": "baz",
// Too many args
{
`${lookup("foo", "bar", "baz")}`,
nil,
true,
},
[]string{"foo", "bar", "baz"},
"",
true,
},
}
for i, tc := range cases {
actual, err := interpolationFuncLookup(tc.M, tc.Args...)
if (err != nil) != tc.Error {
t.Fatalf("%d: err: %s", i, err)
}
if actual != tc.Result {
t.Fatalf("%d: bad: %#v", i, actual)
}
}
})
}
*/
func TestInterpolateFuncElement(t *testing.T) {
testFunction(t, []testFunctionCase{
{
fmt.Sprintf(`${element("%s", "1")}`,
"foo"+InterpSplitDelim+"baz"),
"baz",
false,
},
testFunction(t, testFunctionConfig{
Cases: []testFunctionCase{
{
fmt.Sprintf(`${element("%s", "1")}`,
"foo"+InterpSplitDelim+"baz"),
"baz",
false,
},
{
`${element("foo", "0")}`,
"foo",
false,
},
{
`${element("foo", "0")}`,
"foo",
false,
},
// Invalid index should wrap vs. out-of-bounds
{
fmt.Sprintf(`${element("%s", "2")}`,
"foo"+InterpSplitDelim+"baz"),
"foo",
false,
},
// Invalid index should wrap vs. out-of-bounds
{
fmt.Sprintf(`${element("%s", "2")}`,
"foo"+InterpSplitDelim+"baz"),
"foo",
false,
},
// Too many args
{
fmt.Sprintf(`${element("%s", "0", "2")}`,
"foo"+InterpSplitDelim+"baz"),
nil,
true,
// Too many args
{
fmt.Sprintf(`${element("%s", "0", "2")}`,
"foo"+InterpSplitDelim+"baz"),
nil,
true,
},
},
})
}
type testFunctionConfig struct {
Cases []testFunctionCase
Vars map[string]string
}
type testFunctionCase struct {
Input string
Result interface{}
Error bool
}
func testFunction(t *testing.T, cases []testFunctionCase) {
for i, tc := range cases {
func testFunction(t *testing.T, config testFunctionConfig) {
for i, tc := range config.Cases {
ast, err := lang.Parse(tc.Input)
if err != nil {
t.Fatalf("%d: err: %s", i, err)
}
engine := langEngine(nil)
engine := langEngine(config.Vars)
out, _, err := engine.Execute(ast)
if (err != nil) != tc.Error {
t.Fatalf("%d: err: %s", i, err)

View File

@ -208,10 +208,17 @@ func langEngine(vs map[string]string) *lang.Engine {
for k, v := range vs {
varMap[k] = lang.Variable{Value: v, Type: ast.TypeString}
}
funcMap := make(map[string]lang.Function)
for k, v := range Funcs {
funcMap[k] = v
}
funcMap["lookup"] = interpolationFuncLookup(vs)
return &lang.Engine{
GlobalScope: &lang.Scope{
VarMap: varMap,
FuncMap: Funcs,
FuncMap: funcMap,
},
}
}