Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: add "yield" function #387

Open
breml opened this issue Oct 31, 2023 · 5 comments
Open

Feature Request: add "yield" function #387

breml opened this issue Oct 31, 2023 · 5 comments

Comments

@breml
Copy link

breml commented Oct 31, 2023

With Go templates it is not possible to dynamically (based on a variable) include other templates (partials). For example the following is not a valid Go template:

{{ define "first" }} First {{ end }}
{{ $template := "first" }}
{{ template $template . }}

and it will produce the following error:

error parsing template: template: base:4: unexpected "$template" in template clause

Since I had this problem already multiple times, I created a function yield, which does the same as template, but allows the template name (first argument) to by dynamic (it can be a variable).

With the new function yield, the following becomes possible:

{{ define "first" }} First {{ end }}
{{ define "second" }} Second {{ end }}
{{ $template := list "first" "second" }}
{{ $randTemplate := index $template (randInt 0 (len $template) ) }}
{{ yield $randTemplate . }} 

I think, this would be a meaning full addition to https://github.com/Masterminds/sprig and I am happy to provide a PR for this. What do you think?

@forquare
Copy link

Not with template, but we have a pattern like this for includes:

{{ include (printf "%s" $template) . }}

It's certainly not as nice as having a dedicated function, but it works well enough for us.

@breml
Copy link
Author

breml commented Feb 13, 2024

@forquare Thanks for your contribution. I am not entirely sure I can follow your example. May I ask you to elaborate. In particular what is $template (filename, name of the thing to include, the content to be included (plain text), the content to be included, but rendered as a Go template, something else) and what does the include function exactly do. Thanks.

@breml
Copy link
Author

breml commented Feb 13, 2024

On a side note: Hugo does provide include functionality for Go templates, see https://gohugo.io/templates/introduction/#includes

@forquare
Copy link

@breml Firstly, let me apologise because I'm not sure how Helm does this, but I think they do some kind of preprocessing - I've tried this with my limited Go knowledge and can't replicate my suggestion simply using Go text/template.

Secondly, apologies for not expanding. Despite the fact that what I said may not be valid! Let me still expand:

include is a function in Helm which "will import the contents of a template into the present pipeline where it can be passed along to other functions in the pipeline" (from the Helm documentation here)

In my example, $template is a variable containing the name of a named template, exactly the same as your first example. I had thought that your original example could have been rewritten like this:

{{ define "first" }} First {{ end }}
{{ $template := "first" }}
{{ template (printf "%s" $template) . }}

However I think you would need to have some sort of preprocessing in place to handle this, as my limited knowledge cant' replicate this simply in Go.

@breml
Copy link
Author

breml commented Feb 14, 2024

@forquare Thanks for the additional context. As you have written, include is a function provided by helm (source code: https://github.com/helm/helm/blob/e81f6140ddb22bc99a08f7409522a8dbe5338ee3/pkg/engine/engine.go#L129), which works similar to the function yield that I am proposing in this issue.
In the documentation you linked above there is a statement about template, which explains why your snippet does not work:

Because template is an action, and not a function, there is no way to pass the output of a template call to other functions; the data is simply inserted inline.

The key is "template is an action, and not a function". Additionally to the limitation, that it does not allow the output to be passed to an other function, it is also more strict about the "arguments" it accepts. The first argument (name of the template) is required to be a string constant and it is not possible to pass the name of the template as a variable. The error, the template action produces, if the name is not a string constant (but a variable) is provided in the initial description of this issue.

Both these limitations are removed by either the yield function proposed here or the include function available in helm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants