diff --git a/CHANGELOG.md b/CHANGELOG.md index 10369e7a1..5f1cac98b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ BACKWARDS INCOMPATIBILITIES: * Keys cannot be double-quoted strings: `"foo" = "bar"` is no longer valid. +FEATURES: + + * **New Function: `concat`**: Concatenate multiple strings together. + Example: `concat(var.region, "-", var.channel)`. + IMPROVEMENTS: * core: "~/.terraformrc" (Unix) or "%APPDATA%/terraform.rc" (Windows) diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index ef0d06ee6..20014aa2f 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -1,6 +1,7 @@ package config import ( + "bytes" "fmt" "io/ioutil" "strings" @@ -11,11 +12,27 @@ var Funcs map[string]InterpolationFunc func init() { Funcs = map[string]InterpolationFunc{ + "concat": interpolationFuncConcat, "file": interpolationFuncFile, "lookup": interpolationFuncLookup, } } +// interpolationFuncConcat implements the "concat" function that allows +// strings to be joined together. +func interpolationFuncConcat( + vs map[string]string, args ...string) (string, error) { + var buf bytes.Buffer + + for _, a := range args { + if _, err := buf.WriteString(a); err != nil { + return "", err + } + } + + return buf.String(), nil +} + // interpolationFuncFile implements the "file" function that allows // loading contents from a file. func interpolationFuncFile( diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index f301283c8..0bb230e0a 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -6,6 +6,43 @@ import ( "testing" ) +func TestInterpolateFuncConcat(t *testing.T) { + cases := []struct { + Args []string + Result string + Error bool + }{ + { + []string{"foo", "bar", "baz"}, + "foobarbaz", + false, + }, + + { + []string{"foo", "bar"}, + "foobar", + false, + }, + + { + []string{"foo"}, + "foo", + false, + }, + } + + for i, tc := range cases { + actual, err := interpolationFuncConcat(nil, tc.Args...) + if (err != nil) != tc.Error { + t.Fatalf("%d: err: %s", i, err) + } + + if actual != tc.Result { + t.Fatalf("%d: bad: %#v", i, actual) + } + } +} + func TestInterpolateFuncFile(t *testing.T) { tf, err := ioutil.TempFile("", "tf") if err != nil {