diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index cc09e384c..bc2c49f45 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -58,6 +58,7 @@ func Funcs() map[string]ast.Function { "base64encode": interpolationFuncBase64Encode(), "base64sha256": interpolationFuncBase64Sha256(), "ceil": interpolationFuncCeil(), + "chomp": interpolationFuncChomp(), "cidrhost": interpolationFuncCidrHost(), "cidrnetmask": interpolationFuncCidrNetmask(), "cidrsubnet": interpolationFuncCidrSubnet(), @@ -459,6 +460,18 @@ func interpolationFuncCeil() ast.Function { } } +// interpolationFuncChomp removes trailing newlines from the given string +func interpolationFuncChomp() ast.Function { + newlines := regexp.MustCompile(`(?:\r\n?|\n)*\z`) + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeString}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + return newlines.ReplaceAllString(args[0].(string), ""), nil + }, + } +} + // interpolationFuncFloorreturns returns the greatest integer value less than or equal to the argument func interpolationFuncFloor() ast.Function { return ast.Function{ diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 04e85a6d5..78816b6dd 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -370,6 +370,60 @@ func TestInterpolateFuncCeil(t *testing.T) { }) } +func TestInterpolateFuncChomp(t *testing.T) { + testFunction(t, testFunctionConfig{ + Cases: []testFunctionCase{ + { + `${chomp()}`, + nil, + true, + }, + + { + `${chomp("hello world")}`, + "hello world", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\ncruel\nworld"), + "goodbye\ncruel\nworld", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\r\nwindows\r\nworld"), + "goodbye\r\nwindows\r\nworld", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\ncruel\nworld\n"), + "goodbye\ncruel\nworld", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\ncruel\nworld\n\n\n\n"), + "goodbye\ncruel\nworld", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\r\nwindows\r\nworld\r\n"), + "goodbye\r\nwindows\r\nworld", + false, + }, + + { + fmt.Sprintf(`${chomp("%s")}`, "goodbye\r\nwindows\r\nworld\r\n\r\n\r\n\r\n"), + "goodbye\r\nwindows\r\nworld", + false, + }, + }, + }) +} + func TestInterpolateFuncMap(t *testing.T) { testFunction(t, testFunctionConfig{ Cases: []testFunctionCase{ diff --git a/website/source/docs/configuration/interpolation.html.md b/website/source/docs/configuration/interpolation.html.md index 896fdbee6..473cc7f2b 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -154,6 +154,8 @@ The supported built-in functions are: * `ceil(float)` - Returns the least integer value greater than or equal to the argument. + * `chomp(string)` - Removes trailing newlines from the given string. + * `cidrhost(iprange, hostnum)` - Takes an IP address range in CIDR notation and creates an IP address with the given host number. For example, `cidrhost("10.0.0.0/8", 2)` returns `10.0.0.2`.