Merge pull request #7905 from hashicorp/jbardin/merge
core: Add merge interpolation function
This commit is contained in:
commit
81bb6b7264
|
@ -73,6 +73,7 @@ func Funcs() map[string]ast.Function {
|
|||
"lower": interpolationFuncLower(),
|
||||
"map": interpolationFuncMap(),
|
||||
"md5": interpolationFuncMd5(),
|
||||
"merge": interpolationFuncMerge(),
|
||||
"uuid": interpolationFuncUUID(),
|
||||
"replace": interpolationFuncReplace(),
|
||||
"sha1": interpolationFuncSha1(),
|
||||
|
@ -898,6 +899,26 @@ func interpolationFuncMd5() ast.Function {
|
|||
}
|
||||
}
|
||||
|
||||
func interpolationFuncMerge() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeMap},
|
||||
ReturnType: ast.TypeMap,
|
||||
Variadic: true,
|
||||
VariadicType: ast.TypeMap,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
outputMap := make(map[string]ast.Variable)
|
||||
|
||||
for _, arg := range args {
|
||||
for k, v := range arg.(map[string]ast.Variable) {
|
||||
outputMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return outputMap, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncUpper implements the "upper" function that does
|
||||
// string upper casing.
|
||||
func interpolationFuncUpper() ast.Function {
|
||||
|
|
|
@ -498,6 +498,103 @@ func TestInterpolateFuncConcat(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncMerge(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
// basic merge
|
||||
{
|
||||
`${merge(map("a", "b"), map("c", "d"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge with conflicts is ok, last in wins.
|
||||
{
|
||||
`${merge(map("a", "b", "c", "X"), map("c", "d"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge variadic
|
||||
{
|
||||
`${merge(map("a", "b"), map("c", "d"), map("e", "f"))}`,
|
||||
map[string]interface{}{"a": "b", "c": "d", "e": "f"},
|
||||
false,
|
||||
},
|
||||
|
||||
// merge with variables
|
||||
{
|
||||
`${merge(var.maps[0], map("c", "d"))}`,
|
||||
map[string]interface{}{"key1": "a", "key2": "b", "c": "d"},
|
||||
false,
|
||||
},
|
||||
|
||||
// only accept maps
|
||||
{
|
||||
`${merge(map("a", "b"), list("c", "d"))}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
// merge maps of maps
|
||||
{
|
||||
`${merge(map("a", var.maps[0]), map("b", var.maps[1]))}`,
|
||||
map[string]interface{}{
|
||||
"b": map[string]interface{}{"key3": "d", "key4": "c"},
|
||||
"a": map[string]interface{}{"key1": "a", "key2": "b"},
|
||||
},
|
||||
false,
|
||||
},
|
||||
// merge maps of lists
|
||||
{
|
||||
`${merge(map("a", list("b")), map("c", list("d", "e")))}`,
|
||||
map[string]interface{}{"a": []interface{}{"b"}, "c": []interface{}{"d", "e"}},
|
||||
false,
|
||||
},
|
||||
// merge map of various kinds
|
||||
{
|
||||
`${merge(map("a", var.maps[0]), map("b", list("c", "d")))}`,
|
||||
map[string]interface{}{"a": map[string]interface{}{"key1": "a", "key2": "b"}, "b": []interface{}{"c", "d"}},
|
||||
false,
|
||||
},
|
||||
},
|
||||
Vars: map[string]ast.Variable{
|
||||
"var.maps": {
|
||||
Type: ast.TypeList,
|
||||
Value: []ast.Variable{
|
||||
{
|
||||
Type: ast.TypeMap,
|
||||
Value: map[string]ast.Variable{
|
||||
"key1": {
|
||||
Type: ast.TypeString,
|
||||
Value: "a",
|
||||
},
|
||||
"key2": {
|
||||
Type: ast.TypeString,
|
||||
Value: "b",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ast.TypeMap,
|
||||
Value: map[string]ast.Variable{
|
||||
"key3": {
|
||||
Type: ast.TypeString,
|
||||
Value: "d",
|
||||
},
|
||||
"key4": {
|
||||
Type: ast.TypeString,
|
||||
Value: "c",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestInterpolateFuncDistinct(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
|
@ -1542,7 +1639,6 @@ type testFunctionCase struct {
|
|||
|
||||
func testFunction(t *testing.T, config testFunctionConfig) {
|
||||
for i, tc := range config.Cases {
|
||||
fmt.Println("running", i)
|
||||
ast, err := hil.Parse(tc.Input)
|
||||
if err != nil {
|
||||
t.Fatalf("Case #%d: input: %#v\nerr: %v", i, tc.Input, err)
|
||||
|
|
|
@ -110,7 +110,7 @@ The supported built-in functions are:
|
|||
variables or when parsing module outputs.
|
||||
Example: `compact(module.my_asg.load_balancer_names)`
|
||||
|
||||
* `concat(list1, list2)` - Combines two or more lists into a single list.
|
||||
* `concat(list1, list2, ...)` - Combines two or more lists into a single list.
|
||||
Example: `concat(aws_instance.db.*.tags.Name, aws_instance.web.*.tags.Name)`
|
||||
|
||||
* `distinct(list)` - Removes duplicate items from a list. Keeps the first
|
||||
|
@ -132,13 +132,13 @@ The supported built-in functions are:
|
|||
module, you generally want to make the path relative to the module base,
|
||||
like this: `file("${path.module}/file")`.
|
||||
|
||||
* `format(format, args...)` - Formats a string according to the given
|
||||
* `format(format, args, ...)` - Formats a string according to the given
|
||||
format. The syntax for the format is standard `sprintf` syntax.
|
||||
Good documentation for the syntax can be [found here](https://golang.org/pkg/fmt/).
|
||||
Example to zero-prefix a count, used commonly for naming servers:
|
||||
`format("web-%03d", count.index + 1)`.
|
||||
|
||||
* `formatlist(format, args...)` - Formats each element of a list
|
||||
* `formatlist(format, args, ...)` - Formats each element of a list
|
||||
according to the given format, similarly to `format`, and returns a list.
|
||||
Non-list arguments are repeated for each list element.
|
||||
For example, to convert a list of DNS addresses to a list of URLs, you might use:
|
||||
|
@ -171,7 +171,7 @@ The supported built-in functions are:
|
|||
* `${length("a,b,c")}` = 5
|
||||
* `${length(map("key", "val"))}` = 1
|
||||
|
||||
* `list(items...)` - Returns a list consisting of the arguments to the function.
|
||||
* `list(items, ...)` - Returns a list consisting of the arguments to the function.
|
||||
This function provides a way of representing list literals in interpolation.
|
||||
* `${list("a", "b", "c")}` returns a list of `"a", "b", "c"`.
|
||||
* `${list()}` returns an empty list.
|
||||
|
@ -193,6 +193,11 @@ The supported built-in functions are:
|
|||
* `map("hello", "world")`
|
||||
* `map("us-east", list("a", "b", "c"), "us-west", list("b", "c", "d"))`
|
||||
|
||||
* `merge(map1, map2, ...)` - Returns the union of 2 or more maps. The maps
|
||||
are consumed in the order provided, and duplciate keys overwrite previous
|
||||
entries.
|
||||
* `${merge(map("a", "b"), map("c", "d"))}` returns `{"a": "b", "c": "d"}`
|
||||
|
||||
* `md5(string)` - Returns a (conventional) hexadecimal representation of the
|
||||
MD5 hash of the given string.
|
||||
|
||||
|
|
Loading…
Reference in New Issue