1. What is SprigX?

SprigX are extensions to the sprig library (Go docs).

They provide functions that offer more enriched use cases and domain-specific data.

Tip

If you are reading this README on the Go Module Directory documentation (https://pkg.go.dev/r00t2.io/goutils/tplx/sprigx) or the directory landing page (https://git.r00t2.io/r00t2/go_goutils/src/branch/master/tplx/sprigx), it may not render correctly.

Be sure to view it at properly via the AsciiDoc rendering or by downloading and viewing the HTML version.

2. How do I Use SprigX?

The same way you would sprig!

Like this.
package main

import (
	htmlTplLib "html/template"
	txtTplLib "text/template"

	"r00t2.io/goutils/tplx/sprigx"
)

var (
	txtTpl *txtTplLib.Template = txtTplLib.
		New("").
		Funcs(
			sprigx.TxtFuncMap(),
		)
	htmlTpl *htmlTplLib.Template = htmlTplLib.
		New("").
		Funcs(
			sprigx.HtmlFuncMap(),
		)
)

They can even be combined/used together.

Like this.
package main

import (
	"text/template"

	"github.com/Masterminds/sprig/v3"
	"r00t2.io/goutils/tplx/sprigx"
)

var txtTpl *template.Template = template.
		New("").
		Funcs(
			sprigx.TxtFuncMap(),
		).
		Funcs(
			sprig.TxtFuncMap(),
		)
// Or:
/*
var txtTpl *template.Template = template.
		New("").
		Funcs(
			sprig.TxtFuncMap(),
		).
		Funcs(
			sprigx.TxtFuncMap(),
		)
 */

If a <template>.FuncMap is added via .Funcs() after template parsing, it will override any functions of the same name of a <template>.FuncMap before parsing.

For example, if both sprig and sprigx provide a function foo:

this will use foo from sprigx

(show)
package main

import (
	"text/template"

	"github.com/Masterminds/sprig/v3"
	"r00t2.io/goutils/tplx/sprigx"
)

const (
	myTpl string = `{{ "This is an example template string." | foo }}`
)

var (
	tpl *template.Template = template.Must(
					template.
						New("").
						Funcs(sprig.TxtFuncMap()).
						Parse(myTpl),
				).
				Funcs(sprigx.TxtFuncMap())
)

whereas this will use foo from sprig

(show)
package main

import (
	"text/template"

	"github.com/Masterminds/sprig/v3"
	"r00t2.io/goutils/tplx/sprigx"
)

const (
	myTpl string = `{{ "This is an example template string." | foo }}`
)

var (
	tpl *template.Template = template.Must(
					template.
						New("").
						Funcs(sprigx.TxtFuncMap()).
						Parse(myTpl),
					).
					Funcs(sprig.TxtFuncMap())
)

and a function can even be explicitly overridden.

(show)

This would override a function foo and foo2 in sprigx from foo and foo2 from sprig, but leave all other sprig functions untouched.

package main

import (
	"text/template"

	"github.com/Masterminds/sprig/v3"
	"r00t2.io/goutils/tplx/sprigx"
)

const (
	myTpl string = `{{ "This is an example template string." | foo }}`
)

var (
	overrideFuncs template.FuncMap = sprig.TxtFuncMap()
	tpl *template.Template = template.Must(
					template.
						New("").
						Funcs(sprigx.TxtFuncMap()).
						Parse(myTpl),
					).
					Funcs(
						template.FuncMap(
							map[string]any{
								"foo": overrideFuncs["foo"],
								"foo2": overrideFuncs["foo2"],
							},
						),
					)
)

3. Functions

Expect this list to grow over time, and potentially more frequently than the sprigx functions.

3.1. Operating System

3.1.1. osHostname

osHostname simply wraps and returns the result of calling os.Hostname.

As such, it comes with the same caveats - it’s possible for it to error, and it isn’t guaranteed to be an FQDN — it will be precisely/exactly whatever the kernel’s hostname is set as.

3.2. System/Platform/Architecture

3.2.1. sysArch

Returns the runtime.GOARCH constant.

3.2.2. sysNumCpu

Returns the value from runtime.NumCPU.

3.2.3. sysOsName

Returns the runtime.GOOS constant.

3.2.4. sysRuntime

This function returns a map[string]string of various information from the runtime stdlib library.

Specifically, the following are returned.

Tip

The value type is a direct link to the runtime documentation providing more detail about the associated value.

Because all values are mapped as strings, they can be converted back to their native type via e.g. the Sprig conversion functions if necessary.

Table 1. sysRuntime Values
Key Value Type

compiler

string

arch

string

os

string

maxprocs

int [1]

cpu_cnt

int

num_cgo

int

num_go

int

go_ver

string

As a convenience, some of these values also have their own dedicated functions as well:

3.3. Paths

3.3.1. Generic

These operate similar to the path stdlib library and use a fixed / path separator.

3.3.1.1. pathJoin

pathJoin operates exactly like path.Join in stdlib.

Warning

If you are joining paths in a pipeline, you almost assuredly want pathPipeJoin or pathSlicePipeJoin instead unless you are explicitly appending a pipeline result to a path.

{{- pathJoin "a" "b" "c" }}
{{- pathJoin "/" "a" "b" "c" }}
{{- pathJoin "/a/b" "c" }}

renders as:

a/b/c
/a/b/c
/a/b/c
3.3.1.2. pathPipeJoin

pathPipeJoin operates like pathJoin with one deviation: the root/base path is expected to be last in the arguments.

This makes it much more suitable for use in template pipelines, as the previous value in a pipeline is passed in as the last element to the next pipe function.

{{- $myBase := "/a" -}}
{{- pathPipeJoin "b" "c" "a" }}
{{- pathPipeJoin "a" "b" "c" "/" }}
{{- $myBase | pathPipeJoin "b" "c" }}

renders as:

a/b/c
/a/b/c
/a/b/c
3.3.1.3. pathSliceJoin

pathSliceJoin joins a slice of path segment strings ([]string) instead of a variadic sequence of strings.

Tip

The splitList function shown below is from the sprig string slice functions.

{{- $myList := "a,b,c" | splitList "," -}}
{{- $myList | pathSliceJoin }}
{{- ("a,b,c" | splitList ",") | pathSliceJoin }}
{{- ("/,a,b,c" | splitList ",") | pathSliceJoin }}

renders as:

a/b/c
a/b/c
/a/b/c
3.3.1.4. pathSlicePipeJoin

pathSlicePipeJoin operates like pathPipeJoin in that it is suitable for pipeline use in which the root/base path is passed in from the pipeline, but it is like pathSliceJoin in that it then also accepts a slice of path segments ([]string) to append to that base path.

Tip

The splitList function shown below is from the sprig string slice functions.

{{- $myBase := "/a" -}}
{{- $myList := "b,c,d" | splitList "." -}}
{{- pathSlicePipeJoin $myList $myBase }}
{{- $myBase | pathSlicePipeJoin $myList }}

renders as:

/a/b/c
/a/b/c
3.3.1.5. pathSubJoin

pathSubJoin operates like pathJoin but it expects an explicit root/base path.

The pipeline-friendly equivalent of this is pathPipeJoin.

{{- pathSubJoin "/a/b" "c" }}
{{- pathSubJoin "/" "a" "b" "c" }}
{{- "c" | pathSubJoin "/" "a" "b" }}

renders as:

/a/b/c
/a/b/c
/a/b/c

3.3.2. OS/Platform-Tailored

These operate similar to the path/filepath stdlib library, and use the OS-specific os.PathSeparator.

Warning

Take special note of the oddness around specifying Windows paths and drive letters in e.g. osPathJoin!

It is recommended to make use of sysOsName to conditionally format path bases/roots if needed.

3.3.2.1. osPathJoin

osPathJoin operates exactly like path/filepath.Join in stdlib.

Warning

If you are joining paths in a pipeline, you almost assuredly want osPathPipeJoin or osPathSlicePipeJoin instead unless you are explicitly appending a pipeline result to a path.

{{- osPathJoin "a" "b" "c" }}
{{- osPathJoin "/" "a" "b" "c" }}
{{- osPathJoin "C:\\" "a" "b" "c" }}
{{- osPathJoin "C:" "a" "b" "c" }}

renders as:

OS Result

Windows

a\b\c
\a\b\c
\a\b\c
C:\a\b\c
C:a\b\c

Others (e.g. Linux, macOS)

a/b/c
/a/b/c
C:\/a/b/c
C:/a/b/c
3.3.2.2. osPathPipeJoin

osPathPipeJoin operates like pathPipeJoin (except using OS-specific path separators).

This makes it much more suitable for use in template pipelines, as the previous value in a pipeline is passed in as the last element to the next pipe function.

{{- $myBase := "/a" -}}
{{- osPathPipeJoin "b" "c" "a" }}
{{- osPathPipeJoin "a" "b" "c" "/" }}
{{- $myBase | osPathPipeJoin "b" "c" }}

renders as:

OS Result

Windows

a\b\c
\a\b\c
\a\b\c

Others (e.g. Linux, macOS)

a/b/c
/a/b/c
/a/b/c
3.3.2.3. osPathSep

osPathSep returns the os.PathSeparator for this OS.

{{- osPathSep }}

renders as:

OS Result

Windows

\

Others (e.g. Linux, macOS)

/
3.3.2.4. osPathSliceJoin

osPathSliceJoin operates like pathSliceJoin but with OS-specific path separators.

Tip

The splitList function shown below is from the sprig string slice functions.

{{- $myList := "a,b,c" | splitList "," -}}
{{- $myList | osPathSliceJoin }}
{{- ("a,b,c" | splitList ",") | osPathSliceJoin }}
{{- ("/,a,b,c" | splitList ",") | osPathSliceJoin }}

renders as:

OS Result

Windows

a\b\c
a\b\c
\a\b\c

Others (e.g. Linux, macOS)

a/b/c
a/b/c
/a/b/c
3.3.2.5. osPathSlicePipeJoin

osPathSlicePipeJoin operates like pathSlicePipeJoin but with OS-specific separators.

Tip

The splitList function shown below is from the sprig string slice functions.

{{- $myBase := "/a" -}}
{{- $myList := "b,c,d" | splitList "." -}}
{{- osPathSlicePipeJoin $myList $myBase }}
{{- $myBase | osPathSlicePipeJoin $myList }}

renders as:

OS Result

Windows

\a\b\c\d
\a\b\c\d

Others (e.g. Linux, macOS)

/a/b/c/d
/a/b/c/d
3.3.2.6. osPathSubJoin

osPathSubJoin operates like pathSubJoin but with OS-specific separators.

The pipeline-friendly equivalent of this is osPathPipeJoin.

{{- osPathSubJoin "/a/b" "c" }}
{{- osPathSubJoin "/" "a" "b" "c" }}
{{- "c" | osPathSubJoin "/" "a" "b" }}

renders as:

OS Result

Windows

\a\b\c
\a\b\c
\a\b\c

Others (e.g. Linux, macOS)

/a/b/c
/a/b/c
/a/b/c

3.4. Strings

3.4.1. extIndent

extIndent allows for a MUCH more flexible indenter than the sprig indent function.

It works with both Windows (\r\n) and POSIX (\n) linebreaks.

Tip

If <indentString> is set to \n and <levels> is always set to 1, this function can even be used to doubelspace text!

It has quite a few arguments, however:

{{ extIndent <levels> <skipFirst> <skipEmpty> <skipWhitespace> <indentString> <input> }}

Where:

  • <levels>: The level of indentation for the text. If less than or equal to 0, extIndent just returns <input> as-is and NO-OPs otherwise.

  • <skipFirst>: If true, skip indenting the first line. This is particularly handy if you like to visually align your function calls in your templates.

  • <skipEmpty>: If true, do not add an indent to empty lines (where an "empty line" means "only has a linebreak").

  • <skipWhitespace>: If true, do not add an indent to lines that only consist of whitespace (spaces, tabs, etc.) and a linebreak.

  • <indentString>: The string to use as the "indent character". This can be any string, such as " ", "\t", ".", "|", "==" etc.

  • <input>: The text to be indented. Because it is the last argument, extIndent works with pipelined text as well.

3.5. Debugging

3.5.1. dump

The dump function calls the Sdump function from go-spew (github.com/davecgh/go-spew/spew) for whatever object(s) is/are passed to it.


1. For safety concerns, sprigx does not allow setting GOMAXPROCS, this value only contains the current GOMAXPROCS value.