Merge pull request #9627 from hashicorp/f-format-map

core: Add zipmap interpolation function
This commit is contained in:
James Nugent 2016-10-26 11:39:00 -05:00 committed by GitHub
commit 9eb5c69849
3 changed files with 150 additions and 0 deletions

View File

@ -84,6 +84,7 @@ func Funcs() map[string]ast.Function {
"title": interpolationFuncTitle(),
"trimspace": interpolationFuncTrimSpace(),
"upper": interpolationFuncUpper(),
"zipmap": interpolationFuncZipMap(),
}
}
@ -386,6 +387,39 @@ func interpolationFuncFormat() ast.Function {
}
}
func interpolationFuncZipMap() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{
ast.TypeList, // Keys
ast.TypeList, // Values
},
ReturnType: ast.TypeMap,
Callback: func(args []interface{}) (interface{}, error) {
keys := args[0].([]ast.Variable)
values := args[1].([]ast.Variable)
if len(keys) != len(values) {
return nil, fmt.Errorf("count of keys (%d) does not match count of values (%d)",
len(keys), len(values))
}
for i, val := range keys {
if val.Type != ast.TypeString {
return nil, fmt.Errorf("keys must be strings. value at position %d is %s",
i, val.Type.Printable())
}
}
result := map[string]ast.Variable{}
for i := 0; i < len(keys); i++ {
result[keys[i].Value.(string)] = values[i]
}
return result, nil
},
}
}
// interpolationFuncFormatList implements the "formatlist" function that does
// string formatting on lists.
func interpolationFuncFormatList() ast.Function {

View File

@ -11,6 +11,115 @@ import (
"github.com/hashicorp/hil/ast"
)
func TestInterpolateFuncZipMap(t *testing.T) {
testFunction(t, testFunctionConfig{
Cases: []testFunctionCase{
{
`${zipmap(var.list, var.list2)}`,
map[string]interface{}{
"Hello": "bar",
"World": "baz",
},
false,
},
{
`${zipmap(var.list, var.nonstrings)}`,
map[string]interface{}{
"Hello": []interface{}{"bar", "baz"},
"World": []interface{}{"boo", "foo"},
},
false,
},
{
`${zipmap(var.nonstrings, var.list2)}`,
nil,
true,
},
{
`${zipmap(var.list, var.differentlengthlist)}`,
nil,
true,
},
},
Vars: map[string]ast.Variable{
"var.list": {
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeString,
Value: "Hello",
},
{
Type: ast.TypeString,
Value: "World",
},
},
},
"var.list2": {
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeString,
Value: "bar",
},
{
Type: ast.TypeString,
Value: "baz",
},
},
},
"var.differentlengthlist": {
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeString,
Value: "bar",
},
{
Type: ast.TypeString,
Value: "baz",
},
{
Type: ast.TypeString,
Value: "boo",
},
},
},
"var.nonstrings": {
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeString,
Value: "bar",
},
{
Type: ast.TypeString,
Value: "baz",
},
},
},
{
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeString,
Value: "boo",
},
{
Type: ast.TypeString,
Value: "foo",
},
},
},
},
},
},
})
}
func TestInterpolateFuncList(t *testing.T) {
testFunction(t, testFunctionConfig{
Cases: []testFunctionCase{

View File

@ -252,6 +252,13 @@ The supported built-in functions are:
returned by the `keys` function. This function only works on flat maps and
will return an error for maps that include nested lists or maps.
* `zipmap(list, list)` - Creates a map from a list of keys and a list of
values. The keys must all be of type string, and the length of the lists
must be the same.
For example, to output a mapping of AWS IAM user names to the fingerprint
of the key used to encrypt their initial password, you might use:
`zipmap(aws_iam_user.users.*.name, aws_iam_user_login_profile.users.*.key_fingerprint)`.
<a id="templates"></a>
## Templates