Useful template functions for Go templates.

Sprig: Template functions for Go templates

GoDoc Go Report Card Stability: Sustained

The Go language comes with a built-in template language, but not very many template functions. Sprig is a library that provides more than 100 commonly used template functions.

It is inspired by the template functions found in Twig and in various JavaScript libraries, such as underscore.js.

IMPORTANT NOTES

Sprig leverages mergo to handle merges. In its v0.3.9 release there was a behavior change that impacts merging template functions in sprig. It is currently recommended to use v0.3.8 of that package. Using v0.3.9 will cause sprig tests to fail. The issue in mergo is tracked at https://github.com/imdario/mergo/issues/139.

Package Versions

There are two active major versions of the sprig package.

  • v3 is currently stable release series on the master branch. The Go API should remain compatible with v2, the current stable version. Behavior change behind some functions is the reason for the new major version.
  • v2 is the previous stable release series. It has been more than three years since the initial release of v2. You can read the documentation and see the code on the release-2 branch. Bug fixes to this major version will continue for some time.

Usage

Template developers: Please use Sprig's function documentation for detailed instructions and code snippets for the >100 template functions available.

Go developers: If you'd like to include Sprig as a library in your program, our API documentation is available at GoDoc.org.

For standard usage, read on.

Load the Sprig library

To load the Sprig FuncMap:

import (
  "github.com/Masterminds/sprig"
  "html/template"
)

// This example illustrates that the FuncMap *must* be set before the
// templates themselves are loaded.
tpl := template.Must(
  template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html")
)

Calling the functions inside of templates

By convention, all functions are lowercase. This seems to follow the Go idiom for template functions (as opposed to template methods, which are TitleCase). For example, this:

{{ "hello!" | upper | repeat 5 }}

produces this:

HELLO!HELLO!HELLO!HELLO!HELLO!

Principles Driving Our Function Selection

We followed these principles to decide which functions to add and how to implement them:

  • Use template functions to build layout. The following types of operations are within the domain of template functions:
    • Formatting
    • Layout
    • Simple type conversions
    • Utilities that assist in handling common formatting and layout needs (e.g. arithmetic)
  • Template functions should not return errors unless there is no way to print a sensible value. For example, converting a string to an integer should not produce an error if conversion fails. Instead, it should display a default value.
  • Simple math is necessary for grid layouts, pagers, and so on. Complex math (anything other than arithmetic) should be done outside of templates.
  • Template functions only deal with the data passed into them. They never retrieve data from a source.
  • Finally, do not override core Go template functions.
Comments
  • Please Fix Sprig Compatibility with Semver!

    Please Fix Sprig Compatibility with Semver!

    @mattfarina Can you please update sprig to be compatible with the latest Masterminds/semver changes here: https://github.com/Masterminds/semver/pull/105?

    Running go get -u github.com/Masterminds/sprig now returns the following error:

    github.com/Masterminds/sprig ......\github.com\Masterminds\sprig\semver.go:22:2: cannot use semver.Version as type *semver.Version in return argument

    semver.Version now needs to be a non-pointer, and semver_test.go needs to be updated to play nicely with this data type change.

    We have golang applications that haven't migrated to go-modules yet, and that use sprig as a dependency. Can you please fix this compilation error so that our own downstream builds will succeed?

    Thanks!

    Eric

  • dict merge doesn't create a deep copy

    dict merge doesn't create a deep copy

    I have a case where I want a template to take an input dictionary and produce a copy, omitting a few keys at various levels deep in the hierarchy (in this helm chart).

    I ran into a snare, where I didn't realize that after merging two dictionaries, editing the merged dictionary can modify the originals:

    {{- $values := pick .Values "auth" "other"}}
    {{- /* trim secret values. Update here if new secrets are added! */ -}}
    {{- /* make a copy of values.auth to avoid modifying the original */ -}}
    {{- $_ := set $values "auth" (merge dict .Values.auth) }}
    {{- $_ := set $values.auth "state" (omit $values.auth.state "cryptoKey") }}
    

    Without that set $values "auth" (merge dict .Values.auth), the subsequent set $values.auth "state" would modify the original .Values.auth.state, which I found surprising.

    Is there an existing mechanism to produce a deep copy of a dict, to ensure the original doesn't get modified?

  • Add KeyUsageCertSign to genSelfSignedCert

    Add KeyUsageCertSign to genSelfSignedCert

    Closes Masterminds/sprig#95 (selfSignedCert cannot verify itself)

    If it is intentional to leave the key usage out, we can discuss it here. Basically, let a self signed cert verify itself.

  • mergeOverwrite mutates objects it shouldn't

    mergeOverwrite mutates objects it shouldn't

    I'm using helm which depends on sprig. I wrote a simple fiddle which includes the helm template I'm testing with, as well as some go code that emulates how helm parses the template. You can see it here https://play.golang.org/p/imA_4tZJvPN

    So I've got two objects, $app and $deployments, and if I run mergeOverwrite (dict) $app $deployments I would expect the new dict to first be mutated with the contents of $app and then with the contents of $deployments. But it seems that values from $deployments are being written into $app (as well as the new dict)

  • provide a deepCopy() function

    provide a deepCopy() function

    Without deepCopy(), Helm will be unusable for certain fairly simple tasks because of #120 : You cannot repeatedly use merge with the same "base" dict as the first argument unless you can tolerate that that dict will be modified every time. deepCopy() would avoid this.

  • Add float64 arithmetic

    Add float64 arithmetic

    Add float64 arithmetic functions. For clarity, these functions all have the "f" suffix. To avoid precision errors, all floats are converted to a decimal representation value using shopspring/decimal before calculating.

  • Merge function does not overwrite if new value is falsy

    Merge function does not overwrite if new value is falsy

    Given the following code:

    {{ dict "foo" "bar" | merge (dict "foo" "abc") | toPrettyJson }}
    

    The output is as expected:

    {
      "foo": "abc"
    }
    

    But if the second dict's key is falsy, the value is not overwritten:

    {{ dict "foo" "bar" | merge (dict "foo" 0) | toPrettyJson }}
    

    Results in:

    {
      "foo": "bar"
    }
    

    Any falsy value will be skipped:

    {{ dict "foo" "bar" | merge (dict "foo" 0) | toPrettyJson }}
    {{ dict "foo" "bar" | merge (dict "foo" "") | toPrettyJson }}
    {{ dict "foo" "bar" | merge (dict "foo" false) | toPrettyJson }}
    ...etc
    

    This is not the behavior of Javascript's Object.assign:

    Object.assign({}, {foo: "bar"}, {foo: 0}) # <-- {foo: 0}
    

    Sprig's behavior feels extremely counter-intuitive. When I'm merging dicts, if a key has a value assigned, that's the value I care about. It's language-specific falsyness feels irrelevant in this context.

  • can indent work on multi-line template definition?

    can indent work on multi-line template definition?

    Given:

    {{- define "foobar" }}
    foo:
      bar: baz
    {{- end }}
    
    qux:
    {{- template "foobar" . | indent 2 }}
    

    I'd like to get:

    qux:
      foo:
        bar: baz
    

    Given the above, I get:

    executing "test" at <2>: wrong type for value; expected string; got map[string]interface {}
    

    Using {{- template "foobar" . | toString | indent 2 }} I get:

    qux:
    foo:
      bar: baz
    

    Meaning the line(s) never get indented. Even doing {{ template "foobar" . | join "_" | indent 2 }} results in the above, so clearly piping after template isn't working as I hoped it would.

    Are there any ways to solve this?

  • Surface cryptographically secure random strings from goutils

    Surface cryptographically secure random strings from goutils

    This PR surfaces the random string functions that utilize crypto/rand that were added to goutils here: https://github.com/Masterminds/goutils/pull/25. This will allow Go templates to utilize random strings that have been generated in a cryptographically secure way.

    I made the functions accessible by surfacing them through strings.go. I bounced back and forth between thinking they should be in strings.go and crypto.go a few times. If you think they should be made available via crypto.go instead, just let me know.

    @technosophos

  • Feature Request: Have a

    Feature Request: Have a "slim" version, without dependencies outside stdlib

    Thanks for building this lib! I really like it, but I'd like it even more if it haven't any dependency (outside the standard library)

    Some of the current dependencies are to allow functions I don't care at all on templates, like UUID generation

    For others, the following Go proverb applies:

    "A little copying is better than a than a little dependency"

    Rob Pike

    For example, the xstrings package is imported just because of two functions

    Proposal

    Have a github.com/Masterminds/sprig/slim package that have all the functions that doesn't require importing external libraries

  • add getHostByName function to resolve dns names to ips

    add getHostByName function to resolve dns names to ips

    Hi guys!

    This is a proposal to add a function to resolve names to IPs. I'm a heavy user of helm and this is useful where you need to render an IP but you don't want to hardcode it in your templates.

    What do you think?

  • Function similar to nindent but ignoring content's initial new line.

    Function similar to nindent but ignoring content's initial new line.

    The ask is to have a function that acts like nindent, but skips the content's leading new line. The same effect is if the function act s as indent but doesn't indent the first line. This would allow templates to generate a leading new line that is useful in a lot of scenarios. The proposed name is snindent or sindent.

    Explanation

    A common way of using templates:

    env:
      {{- include "my.multiline" . | nindent 2 }}
    extra:
      field: abc
    

    This assumes that "my.multiline" template produces a string without leading and trailing new lines. Let the template generate a list of "items" (line per item), each guarded by some condition.

    {{- define "my.multiline" }}
    {{- if condition1 }}
    - line1
    {{- end }}
    {{- if condition2 }}
    - line2
    {{- end }}
    {{- end }}
    

    It is not possible to keep the two if blocks independent and keep no new lines around generated string for all possible values of boolean condition1 and condition2

    So, the best for template is to generate a new line character per line: leading or trailing. If using trailing, then {{ include "sometemplate" . }} would generate likely unnecessary extra new line. {{ include "sometemplate" . -}} would in turn affect the next line indentation. So, a leading new line is the only option.

    Workarounds

    env:
      {{- include "my.multiline" . | trimPrefix "\n" | nindent 2 }}
    
  • `deepCopy`, will not override an integer value with the value `0`

    `deepCopy`, will not override an integer value with the value `0`

    This issue is ported over from helm issues but i am not sure if the issue I am seeing would be in https://github.com/imdario/mergo?

    Output of helm version:

    version.BuildInfo{Version:"v3.8.2", GitCommit:"6e3701edea09e5d55a8ca2aae03a68917630e91b", GitTreeState:"clean", GoVersion:"go1.18.1"}
    

    Output of kubectl version:

    N/A

    Cloud Provider/Platform (AKS, GKE, Minikube etc.):

    CAPI/Openstack, vanilla k8s.

    Issue:

    When doing a deepCopy, it is not possible to override an integer value with the value 0. I am not sure if this is a bug or a know behaviour (but it is a little annoying :-)).

    We can reproduce this in the helm playground

    With values:

    ---
    rolloutStrategy1:
      type: RollingUpdate
      rollingUpdate:
        maxUnavailable: 1
        maxSurge: 1
    
    rolloutStrategy2:
      type: RollingUpdate
      rollingUpdate:
        maxUnavailable: 0
        maxSurge: 1
    

    and template:

    ---
    {{- $nodeGroup := deepCopy $.Values.rolloutStrategy1 | mustMerge $.Values.rolloutStrategy2 }}
    {{ toYaml $nodeGroup }}
    

    I would expect the values in rolloutStrategy2 to override the values in rolloutStrategy1, which they do, unless the value is a 0.

  • (feat): Add tar.gz support

    (feat): Add tar.gz support

    Summary

    It would be great to have a tar and gzip functions in order archive and compress string content to a tar.gz binary. This would mostly be useful to embed string content that is over the Kubernetes ConfigMap size limit of 1MBytes.

    Proposal

    The tar function would take as input a map[string][]byte where the key represents a file name and the value represents the file content.

    The gzip function would take an array of bytes as input.

    Usage Example

    It could be used as follow in a Helm chart template:

    my_compressed_files.tar.gz: |
      {{ .Files.Glob("foo/**") | tar | gzip }}
    

    NOTE: The go standard library already provides a "archive/tar" package and a "compress/gzip" package.

  • feat(dig): accepts string with dot or arrays as

    feat(dig): accepts string with dot or arrays as "path" parameters

    Hello 👋 ,

    I would like to use the really useful dig function within a range, but because the dig function only accepts "varargs" for path, I'm not able to use it.

    With $someStruct equals to:

    {
      "a": {
        "b": {
          "c": "value"
        }
      },
      "foo": {
        "bar": {
          "zoo": "value2"
        }
      }
    }
    

    First,

        {{- $keysToGet := list
          "foo.bar.zoo"
          "a.b.c"
        -}}
    	{{ range $keysToGet }}
          {{ dig . "~" $someStruct }}
        {{ end }}
    

    The result of this one is nil because dig looks for { "a.b.c": "value" } 🙂. So the result is twice ~ instead of value and value2.

    Second, with array:

        {{- $keysToGet := list
          "foo.bar.zoo"
          "a.b.c.d.e"
        -}}
    	{{ range $keysToGet }}
          {{ dig (splitList "." .) "~" $someStruct }}
        {{ end }}
    

    Here, it's a type cast problem because the first parameter is not a string like expected by the function. I have the following error:

    dig (splitList "." .) "~" $savedValues>: error calling dig: interface conversion: interface {} is []string, not string
    

    It could be cool, especially in dynamic env like a range or with to have the ability to provide "path" coming from another variable dynamically

    Thank you 😇

  • substr doesn't respects runes (utf8 characters)

    substr doesn't respects runes (utf8 characters)

    The current substr (substring) implementation does not respect runes (utf8 characters).

    func main() {
    	hello := "😞-Hello World-😞"
    	fmt.Printf("substring = %s\n", substring(0, 5, hello))
    	fmt.Printf("substringRune = %s\n", substringRune(0, 5, hello))
    	fmt.Printf("substring = %s\n", substring(2, 7, hello))
    	fmt.Printf("substringRune = %s\n", substringRune(2, 7, hello))
    }
    
    func substringRune(start, end int, s string) string {
    	if start < 0 {
    		return string([]rune(s)[:end])
    	}
    	if end < 0 || end > len(s) {
    		return string([]rune(s)[start:])
    	}
    	return string([]rune(s)[start:end])
    }
    
    func substring(start, end int, s string) string {
    	if start < 0 {
    		return s[:end]
    	}
    	if end < 0 || end > len(s) {
    		return s[start:]
    	}
    	return s[start:end]
    }
    

    Output substring = 😞- substringRune = 😞-Hel substring = ??-He substringRune = Hello

    Remarks substring(): current implementation substringRune(): implementation that also works with runes

  • Add location support to toDate and mustToDate

    Add location support to toDate and mustToDate

    It would be useful if toDate and mustToDate functions accepted a parameter to specify the location for a time object that could be used to convert a time object between locations when UTC or the local location cannot be assumed.

    For example, something like this I think would give you the UTC value for a date that was provided in : toDate "2006-01-02 15:04:05" "2017-12-31 01:01:01" "America/New_York" | date "2006-01-02T15:04:05Z"

    Or could be used to convert a time received in Eastern to Pacific explicitly (I think I'm expressing this correctly): dateInZone "2006-01-02 15:04:05" (toDate "2006-01-02 15:04:05" "2017-12-31 01:01:01" "America/New_York") "America/Los_Angeles"

yview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.

wview wview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application. Contents Instal

Dec 5, 2021
Anybool - Useful interface for boolean settings and options

anybool Tricky and fun utilities for Go programs. AnyBool is a small utility wit

Feb 2, 2022
A collection of well-known string hash functions, implemented in Go

This library is a collection of "well-known" 32-bit string hashes, implemented in Go. It includes: Java string hash ELF-32 Jenkins' One-A

Mar 3, 2022
Package sanitize provides functions for sanitizing text in golang strings.

sanitize Package sanitize provides functions to sanitize html and paths with go (golang). FUNCTIONS sanitize.Accents(s string) string Accents replaces

Dec 5, 2022
Golang metrics for calculating string similarity and other string utility functions

strutil strutil provides string metrics for calculating string similarity as well as other string utility functions. Full documentation can be found a

Jan 3, 2023
Helpful functions to work with emoji in Golang

GoMoji work with emoji in the most convenient way GoMoji is a Go package that provides a fast and simple way to work with emojis in strings. It has fe

Jan 6, 2023
A complete Liquid template engine in Go
A complete Liquid template engine in Go

Liquid Template Parser liquid is a pure Go implementation of Shopify Liquid templates. It was developed for use in the Gojekyll port of the Jekyll sta

Dec 15, 2022
export stripTags from html/template as strip.StripTags

HTML StripTags for Go This is a Go package containing an extracted version of the unexported stripTags function in html/template/html.go. ⚠ī¸ This pack

Dec 4, 2022
Experimental parser Angular template

Experimental parser Angular template This repository only shows what a parser on the Go might look like Benchmark 100k line of template Parser ms @ang

Dec 15, 2021
Enhanced Markdown template processor for golang

emd Enhanced Markdown template processor. See emd README file TOC Install glide

Jan 2, 2022
Useful template functions for Go templates.

Sprig: Template functions for Go templates The Go language comes with a built-in template language, but not very many template functions. Sprig is a l

Dec 31, 2022
Go implementation for Soy templates (Google Closure templates)

soy Go implementation for Soy templates aka Google Closure Templates. See godoc for more details and usage examples. This project requires Go 1.12 or

Dec 1, 2022
Community edition nuclei templates, a simple tool that allows you to organize all the Nuclei templates offered by the community in one place

cent Community edition nuclei templates, a simple tool that allows you to organize all the Nuclei templates offered by the community in one place Inst

Jan 9, 2023
📮 Simple (but useful) email sender written in pure Go v1.17. Support HTML templates and attachments.

?? Go Email Sender Simple (but useful) email sender written in pure Go v1.17. Yes, yet another email package here! ?? Support HTML templates and attac

Dec 31, 2021
Go templates invoked as functions

Package tmplfunc provides an extension of Go templates in which templates can be invoked as if they were functions. See the package documentation for

Dec 22, 2022
This package provides Go (golang) types and helper functions to do some basic but useful things with mxGraph diagrams in XML, which is most famously used by app.diagrams.net, the new name of draw.io.

Go Draw - Golang MX This package provides types and helper functions to do some basic but useful things with mxGraph diagrams in XML, which is most fa

Aug 30, 2022
A library containing useful functions for working with Go types.

Go Type Tools A library containing useful functions for working with Go types. Table of Contents Reasoning Examples Array Map Int String Usage License

Feb 18, 2022
Useful collection functions for golang, based on generic types

go-collection English | įŽ€äŊ“中文 go-collection provides developers with a convenient set of functions for working with common slices, maps, and arrays dat

Jul 21, 2022
PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. You can use PHP like functions in your app, module etc. when you add this module to your project.

PHP Functions for Golang - phpfuncs PHP functions implementation to Golang. This package is for the Go beginners who have developed PHP code before. Y

Dec 30, 2022
Nov 9, 2022