How to indent content of included template
Asked Answered
O

4

10

I am using go templates to create yaml definitions for kubernetes. I am trying to nest templates but run into issues where I can't re-use a definition simply because the indention is wrong when included. I.e., in one case the contents need indentation but do not in another. How can I control the indention of included content?

Example below. I am reusing pod.tmpl, in the first case it can be included as is. In the second case I need to indent the entire contents so it becomes member of service

{{ if (eq .Case "pod")
  # NO indenting
  {{ template "pod" }}
{{ end }}

{{ if (eq .Case "service")
  service:
    # need to indent! so contents become members of service:
    {{ template "pod" }}
{{ end }}
Ornate answered 6/5, 2017 at 15:7 Comment(2)
Why not use a YAML parser instead of a generic text template engine? It seems to me you're using the wrong tool for the job here. That being said, if you don't want spaces then ... don't type them?Jounce
There is an issue right now github.com/hairyhenderson/gomplate/issues/…Yale
H
8

@Giovanni Bassi's answer only works in helm. The include function is defined in helm here.

Combining with indent from sprig from @tmirks answer, you get:

func renderTemplate(templatePath string, vars interface{}, out io.Writer) error {
    t := template.New(filepath.Base(templatePath))
    var funcMap template.FuncMap = map[string]interface{}{}
    // copied from: https://github.com/helm/helm/blob/8648ccf5d35d682dcd5f7a9c2082f0aaf071e817/pkg/engine/engine.go#L147-L154
    funcMap["include"] = func(name string, data interface{}) (string, error) {
        buf := bytes.NewBuffer(nil)
        if err := t.ExecuteTemplate(buf, name, data); err != nil {
            return "", err
        }
        return buf.String(), nil
    }

    t, err := t.Funcs(sprig.TxtFuncMap()).Funcs(funcMap).ParseFiles(templatePath)
    if err != nil {
        return err
    }
    err = t.Execute(out, &vars)
    if err != nil {
        return err
    }
    return nil
}

then

{{ include "pod" | indent 4 }}
Harter answered 19/12, 2019 at 0:11 Comment(0)
D
2

You can indent freely, but you need to use include instead of template, as template is an action and can't be passed to other functions:

{{ include "pod" | indent 4 }}

See the Helm guide for more info.

Dionne answered 24/10, 2019 at 2:26 Comment(0)
P
1

You should be able to pipe the output of your template to the indent function available in the sprig package:

{{ if (eq .Case "service")
  service:
    # need to indent! so contents become members of service:
{{ template "pod" | indent 4 }}
{{ end }}
Pardue answered 17/5, 2017 at 14:44 Comment(1)
does it work with template variables? I have something like {{template "T1" .Field | indent 4}} but I got an error wrong type for value; expected string; got FieldTypeMichell
O
0

I found I can work around the issue if I indent the contents of pod.tmpl and then indent the top portion to align as below

{{ if (eq $template "pod.tmpl") }}
    apiVersion: v1
    kind: Pod
{{ end }}
{{ if (eq $template "deployment.tmpl") }}
apiVersion: v1
kind: Deployment
metadata:
  name: {{ .Name }}-deployment
spec:
  replicas: {{ .Scale }}
  template:
{{template "pod" dict "Version" $version "Domain" $domain "Image" $image "ImageDerived" $imageDerived "Service" . }}
Ornate answered 6/5, 2017 at 22:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.