ADDED:
* math, time functions to tplx/sprigx
FIXED:
* logging not initializing properly on some BSDs
This commit is contained in:
brent saner
2026-01-30 06:35:23 -05:00
parent 1bd6e1256c
commit 07e0e587fa
16 changed files with 6831 additions and 260 deletions

View File

@@ -17,7 +17,7 @@ Last rendered {localdatetime}
[id="wat"]
== What is SprigX?
SprigX are extensions to https://masterminds.github.io/sprig/[the `sprig` library^] (https://pkg.go.dev/github.com/Masterminds/sprig/v3[Go docs^]).
SprigX is a suite of extensions to https://masterminds.github.io/sprig/[the `sprig` library^] (https://pkg.go.dev/github.com/Masterminds/sprig/v3[Go docs^]).
They provide functions that offer more enriched use cases and domain-specific data.
@@ -102,6 +102,8 @@ var txtTpl *template.Template = template.
----
====
Or, as a convenience, you can simply use the <<lib_cmbtfmap, `sprigx.CombinedTxtFuncMap`>> and/or <<lib_cmbhfmap, `sprigx.CombinedHtmlFuncMap`>> functions.
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`:
@@ -212,8 +214,103 @@ var (
----
====
[id="lib"]
== Library Functions
These are generally intended to be used *outside* the template in the actual Go code.
[id="lib_cmbfmap"]
=== `CombinedFuncMap`
[source,go]
.Function Signature
----
func CombinedFuncMap(preferSprigX bool) (fmap map[string]any)
----
This function returns a generic function map (like <<lib_fmap>>) combined with
https://pkg.go.dev/github.com/Masterminds/sprig/v3#GenericFuncMap[`github.com/Masterminds/sprig/v3.GenericFuncMap`^].
If `preferSprigx` is true, SprigX function names will override Sprig functions with the same name.
If false, Sprig functions will override conflicting SprigX functions with the same name.
You probably want <<lib_cmbtfmap>> or <<lib_cmbhfmap>> instead,
as they wrap this with the appropriate type.
[id="lib_cmbhfmap"]
=== `CombinedHtmlFuncMap`
[source,go]
.Function Signature
----
func CombinedHtmlFuncMap(preferSprigX bool) (fmap (html/template).FuncMap)
----
This function returns an https://pkg.go.dev/html/template#FuncMap[`(html/template).FuncMap`] function map (like <<lib_hfmap>>) combined with
https://pkg.go.dev/github.com/Masterminds/sprig/v3#HtmlFuncMap[`github.com/Masterminds/sprig/v3.HtmlFuncMap`^].
If `preferSprigx` is true, SprigX function names will override Sprig functions with the same name.
If false, Sprig functions will override conflicting SprigX functions with the same name.
[id="lib_cmbtfmap"]
=== `CombinedTxtFuncMap`
[source,go]
.Function Signature
----
func CombinedTxtFuncMap(preferSprigX bool) (fmap (text/template).FuncMap)
----
This function returns a https://pkg.go.dev/text/template#FuncMap[`(text/template).FuncMap`] function map (like <<lib_tfmap>>) combined with
https://pkg.go.dev/github.com/Masterminds/sprig/v3#TxtFuncMap[`github.com/Masterminds/sprig/v3.TxtFuncMap`^].
If `preferSprigx` is true, SprigX function names will override Sprig functions with the same name.
If false, Sprig functions will override conflicting SprigX functions with the same name.
[id="lib_fmap"]
=== `FuncMap`
[source,go]
.Function Signature
----
func FuncMap() (fmap map[string]any)
----
This function returns a generic SprigX function map.
You probably want <<lib_tfmap>> or <<lib_hfmap>> instead,
as they wrap this with the appropriate type.
[id="lib_hfmap"]
=== `HtmlFuncMap`
[source,go]
.Function Signature
----
func HtmlFuncMap() (fmap (html/template).FuncMap)
----
This function returns a SprigX https://pkg.go.dev/html/template#FuncMap[`(html/template).FuncMap`^].
[id="lib_nop"]
==== `Nop`
[source,go]
.Function Signature
----
func Nop(obj ...any) (s string)
----
`Nop` is a NO-OP function that one can use in an <<override, override map>> to explicitly disable
certain Sprig/SprigX functions that may be deemed "unsafe" and/or to sanitize templates from untrusted input.
It will *never* error or panic, and `s` is *always* an empty string.
[id="lib_tfmap"]
=== `TxtFuncMap`
[source,go]
.Function Signature
----
func TxtFuncMap() (fmap (text/template).FuncMap)
----
This function returns a SprigX https://pkg.go.dev/text/template#FuncMap[`(text/template).FuncMap`^].
[id="fn"]
== Functions
== Template Functions
Expect this list to grow over time, and potentially more frequently than the `sprigx` functions.
Each function includes its function signature to indicate what types of arguments/parameters it accepts,
@@ -248,19 +345,50 @@ func metaIsNil(obj any) (isNil bool)
This function fills in the gap that https://pkg.go.dev/text/template#IsTrue[`text/template.IsTrue`^] and https://pkg.go.dev/html/template#IsTrue[`html/template.IsTrue`^] (expressed in templates as `{{ if ... }}`) leaves, as those functions/expressions return false for e.g. `false` booleans AND nils.
[id="fn_meta_nop"]
==== `Nop`
[id="fn_num"]
=== Numbers/Math
[id="fn_num_f32s"]
==== `numFloat32Str`
[source,go]
.Function Signature
----
func Nop(obj ...any) (s string)
func numFloat32Str(f float32) (s string)
----
`Nop` is not actually a *template* function, but rather an exported *Go* function that one can use in
an <<override, override map>> to explicitly disable certain template functions that may be deemed "unsafe" and/or to sanitize templates from
untrusted input.
`numFloat32Str` returns a *complete* non-truncated non-right-padded string representation of a `float32`.
It will *never* error or panic, and `s` is *always* an empty string.
[id="fn_num_f64"]
==== `numFloat64`
[source,go]
.Function Signature
----
func numFloat64(val any) (f float64, err error)
----
`numFloat64` returns any string representation of a numeric value or any type of numeric value to a `float64`.
[id="fn_num_f64s"]
==== `numFloat64Str`
[source,go]
.Function Signature
----
func numFloat64Str(f float64) (s string)
----
`numFloat64Str` returns a *complete* non-truncated non-right-padded string representation of a `float64`.
[id="fn_num_fs"]
==== `numFloatStr`
[source,go]
.Function Signature
----
func numFloatStr(val any) (s string, err error)
----
`numFloatStr` wraps <<fn_num_f32s>> and <<fn_num_f64s>>.
`val` can be a string representation of any numeric value or any type of numeric value.
[id="fn_os"]
=== Operating System
@@ -818,7 +946,7 @@ renders as:
|===
[id="fn_ps"]
=== PSUtils
=== PSUtil
These are functions from https://pkg.go.dev/github.com/shirou/gopsutil/v4[`github.com/shirou/gopsutil/v4`^] packages.
[id="fn_ps_cpu"]
@@ -1386,6 +1514,173 @@ Where:
* `<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.
[id="fn_tm"]
=== Time/Dates/Timestamps
[NOTE]
====
Some of these functions duplicate Sprig functionality, but are included here for predictable API.
Care has been taken to name these functions differently from the Sprig functions where possible and sensible.
====
[id="fn_tm_date"]
==== `tmDate`
[source,go]
.Function Signature
----
func tmDate(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) (date time.Time)
----
`tmDate` directly calls https://pkg.go.dev/time#Date[`time.Date`^].
[id="fn_tm_fltmic"]
==== `tmFloatMicro`
[source,go]
.Function Signature
----
func tmFloatMicro(t time.Time) (f64 float64)
----
`tmFloatMicro` directly calls https://pkg.go.dev/r00t2.io/goutils/timex#F64Microseconds[`(r00t2.io/goutils/timex).F64Microseconds`^].
[id="fn_tm_fltmill"]
==== `tmFloatMilli`
[source,go]
.Function Signature
----
func tmFloatMilli(t time.Time) (f64 float64)
----
`tmFloatMilli` directly calls https://pkg.go.dev/r00t2.io/goutils/timex#F64Milliseconds[`(r00t2.io/goutils/timex).F64Milliseconds`^].
[id="fn_tm_fltnano"]
==== `tmFloatNano`
[source,go]
.Function Signature
----
func tmFloatNano(t time.Time) (f64 float64)
----
`tmFloatNano` directly calls https://pkg.go.dev/r00t2.io/goutils/timex#F64Nanoseconds[`(r00t2.io/goutils/timex).F64Nanoseconds`^].
[id="fn_tm_flt"]
==== `tmFloat`
[source,go]
.Function Signature
----
func tmFloat(t time.Time) (f64 float64)
----
`tmFloat` directly calls https://pkg.go.dev/r00t2.io/goutils/timex#F64Seconds[`(r00t2.io/goutils/timex).F64Seconds`^].
[id="fn_tm_fmt"]
==== `tmFmt`
[source,go]
.Function Signature
----
func tmFmt(fstr string, t time.Time) (out string)
----
`tmFormat` provides a more pipeline-friendly alternative to calling e.g.
[source,gotemplate]
----
{{- $t := tmNow -}}
{{ $t.Format "<some time format string>" }}
----
[id="fn_tm_now"]
==== `tmNow`
[source,go]
.Function Signature
----
func tmNow() (now time.Time)
----
`tmNow` directly calls https://pkg.go.dev/time#Now[`time.Now`^].
[id="fn_tm_pdur8n"]
==== `tmParseDur8n`
[source,go]
.Function Signature
----
func tmParseDur8n(s string) (d time.Duration, err error)
----
`tmParseDur8n` directly calls https://pkg.go.dev/time#ParseDuration[`time.ParseDuration`^].
[id="fn_tm_pmnth"]
==== `tmParseMonth`
[source,go]
.Function Signature
----
func tmParseMonth(v any) (mon time.Month, err error)
----
`tmParseMonth` attempts to first try <<fn_tm_pmnthi>> and then tries <<fn_tm_pmnths>> if `v` is not "numeric".
[id="fn_tm_pmnthi"]
==== `tmParseMonthInt`
[source,go]
.Function Signature
----
func tmParseMonthInt(n any) (mon time.Month, err error)
----
`tmParseMonthInt` parses a number representation of month `n` to a https://pkg.go.dev/time#Month[`time.Month`^].
`n` may be any numeric type or a string representation of a number (or a custom type derived from those).
A negative integer (or float, etc.) will be converted to a positive one (e.g. `-6` -> `6` -> `time.June`).
Floats are rounded to the nearest integer.
The integer should map directly to the https://pkg.go.dev/time#example-Month[`time.Month` constants^] in the `time` module:
* `1`: `time.January`
* `2`: `time.February`
* `3`: `time.March`
* `4`: `time.April`
* `5`: `time.May`
* `6`: `time.June`
* `7`: `time.July`
* `8`: `time.August`
* `9`: `time.September`
* `10`: `time.October`
* `11`: `time.November`
* `12`: `time.December`
If `n` resolves to `0`, `mon` will be the current month (as determined by https://pkg.go.dev/time#Now[`time.Now`^]).
If `n` resolves to > `12`, `err` will be `sprigx.ErrBadMonth` (though be sure to use https://pkg.go.dev/errors#Is[`errors.Is`^]; it will be wrapped by link:https://pkg.go.dev/text/template#ExecError[`(text/template).ExecError`]/link:https://pkg.go.dev/html/template#ExecError[`(html/template).ExecError`].
[id="fn_tm_pmnths"]
==== `tmParseMonthStr`
[source,go]
.Function Signature
----
func tmParseMonthStr(s string) (mon time.Month, err error)
----
`tmParseMonthStr` parses a string representation `s` of a month to a https://pkg.go.dev/time#Month[`time.Month`^].
It normalizes `s` to lowercase and only uses the first 3 characters (the minimum length needed to determine month name
uniqueness - "June" vs. "July", "March" vs. "May").
An empty (or whitespace-only) string will use the current month (as determined by https://pkg.go.dev/time#Now[`time.Now`^]).`
[id="fn_tm_ptm"]
==== `tmParseTime`
[source,go]
.Function Signature
----
func tmParseTime(layout, value string) (t time.Time, err error)
----
`tmParseTime` directly calls https://pkg.go.dev/time#Parse[`time.Parse`^].
Be sure that `layout` is a properly parseable https://pkg.go.dev/time#Layout[layout format^].
[id="fn_sys"]
=== System/Platform/Architecture