From 549cff56d02a2f72b244aafbbdd6b458417c5d9d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 13 Feb 2017 16:20:02 -0500 Subject: [PATCH] Add 'slice' interpolation function. (#9729) --- config/interpolate_funcs.go | 37 ++++++++++++ config/interpolate_funcs_test.go | 60 +++++++++++++++++++ .../docs/configuration/interpolation.html.md | 5 +- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index 4dd257a8c..ad543c308 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -85,6 +85,7 @@ func Funcs() map[string]ast.Function { "sha1": interpolationFuncSha1(), "sha256": interpolationFuncSha256(), "signum": interpolationFuncSignum(), + "slice": interpolationFuncSlice(), "sort": interpolationFuncSort(), "split": interpolationFuncSplit(), "timestamp": interpolationFuncTimestamp(), @@ -793,6 +794,42 @@ func interpolationFuncSignum() ast.Function { } } +// interpolationFuncSlice returns a portion of the input list between from, inclusive and to, exclusive. +func interpolationFuncSlice() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ + ast.TypeList, // inputList + ast.TypeInt, // from + ast.TypeInt, // to + }, + ReturnType: ast.TypeList, + Variadic: false, + Callback: func(args []interface{}) (interface{}, error) { + inputList := args[0].([]ast.Variable) + from := args[1].(int) + to := args[2].(int) + + if from < 0 { + return nil, fmt.Errorf("from index must be >= 0") + } + if to > len(inputList) { + return nil, fmt.Errorf("to index must be <= length of the input list") + } + if from > to { + return nil, fmt.Errorf("from index must be <= to index") + } + + var outputList []ast.Variable + for i, val := range inputList { + if i >= from && i < to { + outputList = append(outputList, val) + } + } + return outputList, nil + }, + } +} + // interpolationFuncSort sorts a list of a strings lexographically func interpolationFuncSort() ast.Function { return ast.Function{ diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 0efd6f2fe..193fcd147 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -1330,6 +1330,66 @@ func TestInterpolateFuncSignum(t *testing.T) { }) } +func TestInterpolateFuncSlice(t *testing.T) { + testFunction(t, testFunctionConfig{ + Cases: []testFunctionCase{ + // Negative from index + { + `${slice(list("a"), -1, 0)}`, + nil, + true, + }, + // From index > to index + { + `${slice(list("a", "b", "c"), 2, 1)}`, + nil, + true, + }, + // To index too large + { + `${slice(var.list_of_strings, 1, 4)}`, + nil, + true, + }, + // Empty slice + { + `${slice(var.list_of_strings, 1, 1)}`, + []interface{}{}, + false, + }, + { + `${slice(var.list_of_strings, 1, 2)}`, + []interface{}{"b"}, + false, + }, + { + `${slice(var.list_of_strings, 0, length(var.list_of_strings) - 1)}`, + []interface{}{"a", "b"}, + false, + }, + }, + Vars: map[string]ast.Variable{ + "var.list_of_strings": { + Type: ast.TypeList, + Value: []ast.Variable{ + { + Type: ast.TypeString, + Value: "a", + }, + { + Type: ast.TypeString, + Value: "b", + }, + { + Type: ast.TypeString, + Value: "c", + }, + }, + }, + }, + }) +} + func TestInterpolateFuncSort(t *testing.T) { testFunction(t, testFunctionConfig{ Vars: map[string]ast.Variable{ diff --git a/website/source/docs/configuration/interpolation.html.md b/website/source/docs/configuration/interpolation.html.md index d84be2f4f..2d1e3052b 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -296,7 +296,10 @@ The supported built-in functions are: Example: `element(split(",", var.r53_failover_policy), signum(count.index))` where the 0th index points to `PRIMARY` and 1st to `FAILOVER` - * `sort(list)` - Returns a lexicographically sorted list of the strings contained in + * `slice(list, from, to)` - Returns the portion of `list` between `from` (inclusive) and `to` (exclusive). + Example: `slice(var.list_of_strings, 0, length(var.list_of_strings) - 1)` + + * `sort(list)` - Returns a lexographically sorted list of the strings contained in the list passed as an argument. Sort may only be used with lists which contain only strings. Examples: `sort(aws_instance.foo.*.id)`, `sort(var.list_of_strings)`