Skip to content

Commit

Permalink
Add additional template functions
Browse files Browse the repository at this point in the history
Adds templat functions which:
- to exec an inline template
- indent a template
- remove n continuous empty lines from a template

An example would be a template like:
```
{{define "my-template"}}new template

content

with empty lines

to
remove
{{end}}
Some other template content and add the rendered from my-template
{{$var := execTempl "my-template" . | removeNewLines 1}}
{{$var}}
```

Signed-off-by: Martin Schuppert <[email protected]>
  • Loading branch information
stuggi committed Oct 11, 2024
1 parent 66e6544 commit 8b17f18
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 7 deletions.
6 changes: 5 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ repos:
exclude: ^vendor
- id: no-commit-to-branch
- id: trailing-whitespace
exclude: ^vendor
exclude: |
(?x)(
^vendor|
^modules/common/util/template_util_test.go
)
71 changes: 65 additions & 6 deletions modules/common/util/template_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package util

import (
"bufio"
"bytes"
"fmt"
"os"
Expand Down Expand Up @@ -138,6 +139,57 @@ func ExecuteTemplate(templateFile string, data interface{}) (string, error) {
return renderedTemplate, nil
}

// template functions
var tmpl *template.Template

// template function which allows to execute a template from within
// a template file.
// name - name of the template as defined with with `{{define "some-template"}}your template{{end}}
// data - data to pass into to render the template for all can use `.`
func execTempl(name string, data interface{}) (string, error) {
buf := &bytes.Buffer{}
err := tmpl.ExecuteTemplate(buf, name, data)
return buf.String(), err
}

// template function to indent the template with n tabs
func indent(n int, in string) (out string) {
s := bufio.NewScanner(bytes.NewReader([]byte(in)))
for s.Scan() {
line := strings.TrimSpace(s.Text())
for i := 0; i < n; i++ {
line = "\t" + line
}
out += line + "\n"
}
return out
}

// template function to remove empty lines if there are > n continuous empty lines
func removeNewLines(n int, in string) (out string) {
s := bufio.NewScanner(bytes.NewReader([]byte(in)))

// Variable to keep track of consecutive empty lines
emptyLineCount := 0
for s.Scan() {
line := s.Text()

if strings.TrimSpace(line) == "" {
emptyLineCount++
// If we have already seen more then n empty lines, skip this one
if emptyLineCount > n {
continue
}
} else {
// Reset the empty line counter when we encounter a non-empty line
emptyLineCount = 0
}

out += line + "\n"
}
return out
}

// template function to increment an int
func add(x, y int) int {
return x + y
Expand All @@ -153,11 +205,15 @@ func lower(s string) string {
func ExecuteTemplateData(templateData string, data interface{}) (string, error) {

var buff bytes.Buffer
var err error
funcs := template.FuncMap{
"add": add,
"lower": lower,
"add": add,
"execTempl": execTempl,
"indent": indent,
"lower": lower,
"removeNewLines": removeNewLines,
}
tmpl, err := template.New("tmp").Option("missingkey=error").Funcs(funcs).Parse(templateData)
tmpl, err = template.New("tmp").Option("missingkey=error").Funcs(funcs).Parse(templateData)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -193,10 +249,13 @@ func ExecuteTemplateFile(filename string, data interface{}) (string, error) {
file := string(b)
var buff bytes.Buffer
funcs := template.FuncMap{
"add": add,
"lower": lower,
"add": add,
"execTempl": execTempl,
"indent": indent,
"lower": lower,
"removeNewLines": removeNewLines,
}
tmpl, err := template.New("tmp").Option("missingkey=error").Funcs(funcs).Parse(file)
tmpl, err = template.New("tmp").Option("missingkey=error").Funcs(funcs).Parse(file)
if err != nil {
return "", err
}
Expand Down
99 changes: 99 additions & 0 deletions modules/common/util/template_util_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package util

import (
"bytes"
"os"
"path"
"path/filepath"
"runtime"
"testing"
"text/template"

. "github.com/onsi/gomega"
)
Expand Down Expand Up @@ -37,6 +39,103 @@ func TestLower(t *testing.T) {
})
}

func TestIndent(t *testing.T) {

t.Run("Indent string", func(t *testing.T) {
g := NewWithT(t)
const in = `foo
bar`
// 5 tabs and line break
const expct = ` foo
bar
`

s := indent(5, in)

g.Expect(s).To(BeIdenticalTo(expct))
})
}

func TestRemoveNewLines(t *testing.T) {

t.Run("Remove duplicate new lines", func(t *testing.T) {
g := NewWithT(t)
const in = ` foo
bar
foo
bar`

const expct = ` foo
bar
foo
bar
`

s := removeNewLines(1, in)

g.Expect(s).To(BeIdenticalTo(expct))
})
}

func TestExecTempl(t *testing.T) {

t.Run("ExecTempl", func(t *testing.T) {
g := NewWithT(t)
const myTmpl = `{{define "my-template"}}my-template
content
with empty lines
to
remove
{{end}}
See result:
{{$var := execTempl "my-template" . | removeNewLines 1}}
{{$var}}`

// render template using execTempl and remove more then 1 continuous empty lines
const expct = `
See result:
my-template
content
with empty lines
to
remove
`
var buff bytes.Buffer

tmpl = template.Must(template.New("").Funcs(template.FuncMap{
"execTempl": execTempl,
"removeNewLines": removeNewLines,
}).Parse(myTmpl))
if err := tmpl.Execute(&buff, nil); err != nil {
panic(err)
}

g.Expect(buff.String()).To(BeIdenticalTo(expct))
})
}

func TestGetTemplatesPath(t *testing.T) {
// set the env var used to specify the template path in the container case
os.Setenv("OPERATOR_TEMPLATES", templatePath)
Expand Down

0 comments on commit 8b17f18

Please sign in to comment.