Skip to content

Commit ed9ba57

Browse files
Ninirapparentlymart
authored andcommitted
core: New interpolation function "chunklist"
This turns a list into a list of lists with each element (apart from possibly the last) being the given length.
1 parent 935890e commit ed9ba57

3 files changed

Lines changed: 94 additions & 0 deletions

File tree

‎config/interpolate_funcs.go‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func Funcs() map[string]ast.Function {
7979
"dirname": interpolationFuncDirname(),
8080
"distinct": interpolationFuncDistinct(),
8181
"element": interpolationFuncElement(),
82+
"chunklist": interpolationFuncChunklist(),
8283
"file": interpolationFuncFile(),
8384
"matchkeys": interpolationFuncMatchKeys(),
8485
"flatten": interpolationFuncFlatten(),
@@ -1129,6 +1130,56 @@ func interpolationFuncElement() ast.Function {
11291130
}
11301131
}
11311132

1133+
// returns the `list` items chunked by `size`.
1134+
func interpolationFuncChunklist() ast.Function {
1135+
return ast.Function{
1136+
ArgTypes: []ast.Type{
1137+
ast.TypeList, // inputList
1138+
ast.TypeInt, // size
1139+
},
1140+
ReturnType: ast.TypeList,
1141+
Callback: func(args []interface{}) (interface{}, error) {
1142+
output := make([]ast.Variable, 0)
1143+
1144+
values, _ := args[0].([]ast.Variable)
1145+
size, _ := args[1].(int)
1146+
1147+
// errors if size is negative
1148+
if size < 0 {
1149+
return nil, fmt.Errorf("The size argument must be positive")
1150+
}
1151+
1152+
// if size is 0, returns a list made of the initial list
1153+
if size == 0 {
1154+
output = append(output, ast.Variable{
1155+
Type: ast.TypeList,
1156+
Value: values,
1157+
})
1158+
return output, nil
1159+
}
1160+
1161+
variables := make([]ast.Variable, 0)
1162+
chunk := ast.Variable{
1163+
Type: ast.TypeList,
1164+
Value: variables,
1165+
}
1166+
l := len(values)
1167+
for i, v := range values {
1168+
variables = append(variables, v)
1169+
1170+
// Chunk when index isn't 0, or when reaching the values's length
1171+
if (i+1)%size == 0 || (i+1) == l {
1172+
chunk.Value = variables
1173+
output = append(output, chunk)
1174+
variables = make([]ast.Variable, 0)
1175+
}
1176+
}
1177+
1178+
return output, nil
1179+
},
1180+
}
1181+
}
1182+
11321183
// interpolationFuncKeys implements the "keys" function that yields a list of
11331184
// keys of map types within a Terraform configuration.
11341185
func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function {

‎config/interpolate_funcs_test.go‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,44 @@ func TestInterpolateFuncElement(t *testing.T) {
21062106
})
21072107
}
21082108

2109+
func TestInterpolateFuncChunklist(t *testing.T) {
2110+
testFunction(t, testFunctionConfig{
2111+
Cases: []testFunctionCase{
2112+
// normal usage
2113+
{
2114+
`${chunklist(list("a", "b", "c"), 1)}`,
2115+
[]interface{}{
2116+
[]interface{}{"a"},
2117+
[]interface{}{"b"},
2118+
[]interface{}{"c"},
2119+
},
2120+
false,
2121+
},
2122+
// `size` is pair and the list has an impair number of items
2123+
{
2124+
`${chunklist(list("a", "b", "c"), 2)}`,
2125+
[]interface{}{
2126+
[]interface{}{"a", "b"},
2127+
[]interface{}{"c"},
2128+
},
2129+
false,
2130+
},
2131+
// list made of the same list, since size is 0
2132+
{
2133+
`${chunklist(list("a", "b", "c"), 0)}`,
2134+
[]interface{}{[]interface{}{"a", "b", "c"}},
2135+
false,
2136+
},
2137+
// negative size of chunks
2138+
{
2139+
`${chunklist(list("a", "b", "c"), -1)}`,
2140+
nil,
2141+
true,
2142+
},
2143+
},
2144+
})
2145+
}
2146+
21092147
func TestInterpolateFuncBasename(t *testing.T) {
21102148
testFunction(t, testFunctionConfig{
21112149
Cases: []testFunctionCase{

‎website/docs/configuration/interpolation.html.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ The supported built-in functions are:
230230
* `element(aws_subnet.foo.*.id, count.index)`
231231
* `element(var.list_of_strings, 2)`
232232

233+
* `chunklist(list, size)` - Returns the `list` items chunked by `size`.
234+
Examples:
235+
* `list(aws_subnet.foo.*.id, 1)`: will outputs `[["id1"], ["id2"], ["id3"]]`
236+
* `list(var.list_of_strings, 2)`: will outputs `[["id1", "id2"], ["id3", "id4"], ["id5"]`
237+
233238
* `file(path)` - Reads the contents of a file into the string. Variables
234239
in this file are _not_ interpolated. The contents of the file are
235240
read as-is. The `path` is interpreted relative to the working directory.

0 commit comments

Comments
 (0)