Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82c69ec542
|
||
|
|
07e0e587fa
|
@@ -24,14 +24,16 @@ for f in $(find . -type f -iname "README.adoc"); do
|
|||||||
newf="${pfx}.md"
|
newf="${pfx}.md"
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
asciidoctor -a ROOTDIR="${orig}/" -b docbook -o - "${f}" | pandoc -f docbook -t markdown_strict -o "${newf}"
|
#asciidoctor -a ROOTDIR="${orig}/" -b docbook -o - "${f}" | pandoc -f docbook -t markdown_strict -o "${newf}"
|
||||||
|
#asciidoctor -a ROOTDIR="${orig}/" -b html -o - "${f}" | pandoc -f html -t markdown_strict -o "${newf}"
|
||||||
|
asciidoctor -a ROOTDIR="${orig}/" -b html -o - "${f}" | pandoc -f html -t gfm -o "${newf}"
|
||||||
if [ $? -eq 0 ];
|
if [ $? -eq 0 ];
|
||||||
then
|
then
|
||||||
echo "Generated ${newf} from ${f}"
|
echo "Generated ${newf} from ${f}"
|
||||||
git add "${newf}"
|
git add "${newf}"
|
||||||
else
|
else
|
||||||
echo "Failed to generate ${newf} from ${f}"
|
echo "Failed to generate ${newf} from ${f}"
|
||||||
git rm "${newf}"
|
git rm "${newf}" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
set -e
|
set -e
|
||||||
fi
|
fi
|
||||||
|
|||||||
19
chkplat.sh
Executable file
19
chkplat.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# go tool dist list for all valid GOOS/GOARCH targets.
|
||||||
|
|
||||||
|
for tgt in $(go tool dist list);
|
||||||
|
do
|
||||||
|
o="$(echo ${tgt} | cut -f1 -d '/')"
|
||||||
|
a="$(echo ${tgt} | cut -f2 -d '/')"
|
||||||
|
out="$(env GOOS=${o} GOARCH=${a} go build ./... 2>&1)"
|
||||||
|
ret=${?}
|
||||||
|
if [ $ret -ne 0 ];
|
||||||
|
then
|
||||||
|
echo "OS: ${o}"
|
||||||
|
echo "ARCH: ${a}"
|
||||||
|
echo "${out}"
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
done
|
||||||
2
go.mod
2
go.mod
@@ -10,7 +10,7 @@ require (
|
|||||||
github.com/shirou/gopsutil/v4 v4.25.12
|
github.com/shirou/gopsutil/v4 v4.25.12
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/sys v0.40.0
|
golang.org/x/sys v0.40.0
|
||||||
r00t2.io/sysutils v1.16.0
|
r00t2.io/sysutils v1.16.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -69,3 +69,5 @@ golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
|||||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
r00t2.io/sysutils v1.16.1 h1:GM9fcsIeTKyHEx6IzrFAtycX3FRy7UEWl4SDDHjkEP0=
|
||||||
|
r00t2.io/sysutils v1.16.1/go.mod h1:Fg7gu0DU63iSaX/jSRE4w4oa+zhHOthFGrS0D9+j+oo=
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !(windows || plan9 || wasip1 || js || ios)
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
// +build !windows,!plan9,!wasip1,!js,!ios
|
|
||||||
|
|
||||||
// I mean maybe it works for plan9 and ios, I don't know.
|
// I mean maybe it works for plan9 and ios, I don't know.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
|
||||||
|
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
|
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
|
||||||
// +build !windows,!plan9,!wasip1,!js,!ios,!linux
|
|
||||||
|
|
||||||
// Linux is excluded because it has its own.
|
// Linux is excluded because it has its own.
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Last rendered {localdatetime}
|
|||||||
|
|
||||||
[id="wat"]
|
[id="wat"]
|
||||||
== What is SprigX?
|
== 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.
|
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.
|
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`:
|
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"]
|
[id="fn"]
|
||||||
== Functions
|
== Template Functions
|
||||||
Expect this list to grow over time, and potentially more frequently than the `sprigx` 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,
|
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.
|
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"]
|
[id="fn_num"]
|
||||||
==== `Nop`
|
=== Numbers/Math
|
||||||
|
|
||||||
|
[id="fn_num_f32s"]
|
||||||
|
==== `numFloat32Str`
|
||||||
[source,go]
|
[source,go]
|
||||||
.Function Signature
|
.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
|
`numFloat32Str` returns a *complete* non-truncated non-right-padded string representation of a `float32`.
|
||||||
an <<override, override map>> to explicitly disable certain template 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="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"]
|
[id="fn_os"]
|
||||||
=== Operating System
|
=== Operating System
|
||||||
@@ -818,7 +946,7 @@ renders as:
|
|||||||
|===
|
|===
|
||||||
|
|
||||||
[id="fn_ps"]
|
[id="fn_ps"]
|
||||||
=== PSUtils
|
=== PSUtil
|
||||||
These are functions from https://pkg.go.dev/github.com/shirou/gopsutil/v4[`github.com/shirou/gopsutil/v4`^] packages.
|
These are functions from https://pkg.go.dev/github.com/shirou/gopsutil/v4[`github.com/shirou/gopsutil/v4`^] packages.
|
||||||
|
|
||||||
[id="fn_ps_cpu"]
|
[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.
|
* `<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.
|
* `<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"]
|
[id="fn_sys"]
|
||||||
=== System/Platform/Architecture
|
=== System/Platform/Architecture
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
5303
tplx/sprigx/README.md
Normal file
5303
tplx/sprigx/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import (
|
|||||||
`path`
|
`path`
|
||||||
`path/filepath`
|
`path/filepath`
|
||||||
`runtime`
|
`runtime`
|
||||||
|
`time`
|
||||||
|
|
||||||
`github.com/davecgh/go-spew/spew`
|
`github.com/davecgh/go-spew/spew`
|
||||||
`github.com/shirou/gopsutil/v4/cpu`
|
`github.com/shirou/gopsutil/v4/cpu`
|
||||||
@@ -16,6 +17,7 @@ import (
|
|||||||
psnet `github.com/shirou/gopsutil/v4/net`
|
psnet `github.com/shirou/gopsutil/v4/net`
|
||||||
`github.com/shirou/gopsutil/v4/process`
|
`github.com/shirou/gopsutil/v4/process`
|
||||||
`github.com/shirou/gopsutil/v4/sensors`
|
`github.com/shirou/gopsutil/v4/sensors`
|
||||||
|
`r00t2.io/goutils/timex`
|
||||||
`r00t2.io/sysutils`
|
`r00t2.io/sysutils`
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +30,13 @@ var (
|
|||||||
"Meta"/Template-Helpers
|
"Meta"/Template-Helpers
|
||||||
*/
|
*/
|
||||||
"metaIsNil": metaIsNil,
|
"metaIsNil": metaIsNil,
|
||||||
|
/*
|
||||||
|
Numbers/Math
|
||||||
|
*/
|
||||||
|
"numFloat32Str": numFloat32Str,
|
||||||
|
"numFloat64": numFloat64,
|
||||||
|
"numFloat64Str": numFloat64Str,
|
||||||
|
"numFloatStr": numFloatStr,
|
||||||
/*
|
/*
|
||||||
OS
|
OS
|
||||||
*/
|
*/
|
||||||
@@ -119,7 +128,21 @@ var (
|
|||||||
"sysNumCpu": runtime.NumCPU,
|
"sysNumCpu": runtime.NumCPU,
|
||||||
"sysOsName": sysOsNm,
|
"sysOsName": sysOsNm,
|
||||||
"sysRuntime": sysRuntime,
|
"sysRuntime": sysRuntime,
|
||||||
|
/*
|
||||||
|
Time/Dates/Timestamps
|
||||||
|
*/
|
||||||
|
"tmDate": time.Date,
|
||||||
|
"tmFmt": tmFmt,
|
||||||
|
"tmFloatMicro": timex.F64Microseconds,
|
||||||
|
"tmFloatMilli": timex.F64Milliseconds,
|
||||||
|
"tmFloatNano": timex.F64Nanoseconds,
|
||||||
|
"tmFloat": timex.F64Seconds,
|
||||||
|
"tmNow": time.Now,
|
||||||
|
"tmParseDur8n": time.ParseDuration,
|
||||||
|
"tmParseMonth": tmParseMonth,
|
||||||
|
"tmParseMonthInt": tmParseMonthInt,
|
||||||
|
"tmParseMonthStr": tmParseMonthStr,
|
||||||
|
"tmParseTime": time.Parse,
|
||||||
}
|
}
|
||||||
|
|
||||||
// htmlMap holds functions usable/intended for use in only an [html/template.FuncMap].
|
// htmlMap holds functions usable/intended for use in only an [html/template.FuncMap].
|
||||||
|
|||||||
11
tplx/sprigx/errs.go
Normal file
11
tplx/sprigx/errs.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package sprigx
|
||||||
|
|
||||||
|
import (
|
||||||
|
`errors`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBadMonth error = errors.New("could not determine/parse month")
|
||||||
|
ErrBadType error = errors.New("an invalid/unknown type was passed")
|
||||||
|
ErrNilVal error = errors.New("a nil value was passed")
|
||||||
|
)
|
||||||
@@ -1,14 +1,116 @@
|
|||||||
package sprigx
|
package sprigx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
`errors`
|
||||||
htpl "html/template"
|
htpl "html/template"
|
||||||
|
`math`
|
||||||
|
`reflect`
|
||||||
|
`strconv`
|
||||||
ttpl "text/template"
|
ttpl "text/template"
|
||||||
|
|
||||||
|
`github.com/Masterminds/sprig/v3`
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Many of these functions are modeled after sprig's.
|
Many of these functions are modeled after sprig's.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
CombinedFuncMap returns a generic function map (like [FuncMap]) combined with
|
||||||
|
[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 [CombinedHtmlFuncMap] or [CombinedTxtFuncMap] instead,
|
||||||
|
as they wrap this with the appropriate type.
|
||||||
|
*/
|
||||||
|
func CombinedFuncMap(preferSprigX bool) (fmap map[string]any) {
|
||||||
|
|
||||||
|
var fn any
|
||||||
|
var fnNm string
|
||||||
|
var sprigMap map[string]interface{} = sprig.GenericFuncMap()
|
||||||
|
var sprigxMap map[string]any = FuncMap()
|
||||||
|
|
||||||
|
if preferSprigX {
|
||||||
|
fmap = sprigMap
|
||||||
|
for fnNm, fn = range sprigxMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmap = sprigxMap
|
||||||
|
for fnNm, fn = range sprigMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CombinedHtmlFuncMap returns an [htpl.FuncMap] (like [HtmlFuncMap]) combined with
|
||||||
|
[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.
|
||||||
|
*/
|
||||||
|
func CombinedHtmlFuncMap(preferSprigX bool) (fmap htpl.FuncMap) {
|
||||||
|
|
||||||
|
var fn any
|
||||||
|
var fnNm string
|
||||||
|
var sprigMap htpl.FuncMap = sprig.HtmlFuncMap()
|
||||||
|
var sprigxMap htpl.FuncMap = HtmlFuncMap()
|
||||||
|
|
||||||
|
if preferSprigX {
|
||||||
|
fmap = sprigMap
|
||||||
|
for fnNm, fn = range sprigxMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmap = sprigxMap
|
||||||
|
for fnNm, fn = range sprigMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CombinedTxtFuncMap returns a [ttpl.FuncMap] (like [TxtFuncMap]) combined with
|
||||||
|
[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.
|
||||||
|
*/
|
||||||
|
func CombinedTxtFuncMap(preferSprigX bool) (fmap ttpl.FuncMap) {
|
||||||
|
|
||||||
|
var fn any
|
||||||
|
var fnNm string
|
||||||
|
var sprigMap ttpl.FuncMap = sprig.TxtFuncMap()
|
||||||
|
var sprigxMap ttpl.FuncMap = TxtFuncMap()
|
||||||
|
|
||||||
|
if preferSprigX {
|
||||||
|
fmap = sprigMap
|
||||||
|
for fnNm, fn = range sprigxMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmap = sprigxMap
|
||||||
|
for fnNm, fn = range sprigMap {
|
||||||
|
fmap[fnNm] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FuncMap returns a generic function map.
|
FuncMap returns a generic function map.
|
||||||
|
|
||||||
@@ -57,6 +159,11 @@ func HtmlFuncMap() (fmap htpl.FuncMap) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nop explicitly performs a NO-OP and returns an empty string, allowing one to override "unsafe" functions.
|
||||||
|
func Nop(obj ...any) (s string) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// TxtFuncMap returns a [text/template.FuncMap].
|
// TxtFuncMap returns a [text/template.FuncMap].
|
||||||
func TxtFuncMap() (fmap ttpl.FuncMap) {
|
func TxtFuncMap() (fmap ttpl.FuncMap) {
|
||||||
|
|
||||||
@@ -79,3 +186,171 @@ func TxtFuncMap() (fmap ttpl.FuncMap) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
toFloat64 uses reflection to resolve any string or numeric type (even custom types) to a float64.
|
||||||
|
|
||||||
|
It wraps toString for string types but will fall back to checking numeric types.
|
||||||
|
|
||||||
|
If err != nil, then NaN (if true) indicates that:
|
||||||
|
|
||||||
|
* val is a string (or pointer to a string), but
|
||||||
|
* is not a valid numeric string
|
||||||
|
|
||||||
|
(you can do this from the caller as well by calling `errors.Is(err, strconv.ErrSyntax)`).
|
||||||
|
err will always be non-nil if NaN is true.
|
||||||
|
|
||||||
|
err will be ErrNilVal if val is nil.
|
||||||
|
*/
|
||||||
|
func toFloat64(val any) (f float64, NaN bool, err error) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var k reflect.Kind
|
||||||
|
var rv reflect.Value
|
||||||
|
|
||||||
|
// toString will return ErrNilVal if nil.
|
||||||
|
if s, err = toString(val); err != nil {
|
||||||
|
if errors.Is(err, ErrBadType) {
|
||||||
|
// This is OK, it's (hopefully) a number type.
|
||||||
|
err = nil
|
||||||
|
} else {
|
||||||
|
// *probably* ErrNilVal.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We can go ahead and parse this directly since it's already deref'd if a ptr.
|
||||||
|
if f, err = strconv.ParseFloat(s, 64); err != nil {
|
||||||
|
NaN = errors.Is(err, strconv.ErrSyntax)
|
||||||
|
}
|
||||||
|
// We can return regardless here; it's up to the caller to check NaN/err.
|
||||||
|
// If they're false/nil, f is parsed already!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = reflect.ValueOf(val)
|
||||||
|
k = rv.Kind()
|
||||||
|
|
||||||
|
if k == reflect.Ptr {
|
||||||
|
if rv.IsNil() {
|
||||||
|
// *technically* this should be handled above, but best be safe.
|
||||||
|
err = ErrNilVal
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rv = rv.Elem()
|
||||||
|
k = rv.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
f = float64(rv.Int())
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
f = float64(rv.Uint())
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
f = rv.Float()
|
||||||
|
default:
|
||||||
|
// No need to check for string types since we do that near the beginning.
|
||||||
|
err = ErrBadType
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
toInt wraps toFloat64, rounds it to the nearest integer,
|
||||||
|
and converts to an int.
|
||||||
|
|
||||||
|
NaN, err have the same meaning as in toFloat64.
|
||||||
|
|
||||||
|
This function will panic if float64(val)'s f return exceeds
|
||||||
|
math.MaxInt on your platform.
|
||||||
|
*/
|
||||||
|
func toInt(val any) (i int, NaN bool, err error) {
|
||||||
|
|
||||||
|
var f float64
|
||||||
|
|
||||||
|
if f, NaN, err = toFloat64(val); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i = int(math.Round(f))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
toPosFloat64 wraps toFloat64 and ensures that it is a positive float64.
|
||||||
|
|
||||||
|
NaN, err have the same meaning as in toFloat64.
|
||||||
|
*/
|
||||||
|
func toPosFloat64(val any) (f float64, NaN bool, err error) {
|
||||||
|
|
||||||
|
if f, NaN, err = toFloat64(val); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f = math.Abs(f)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
toPosInt wraps toPosFloat64, rounds it to the nearest integer,
|
||||||
|
and converts to an int.
|
||||||
|
|
||||||
|
NaN, err have the same meaning as in toPosFloat64 (and thus toFloat64).
|
||||||
|
|
||||||
|
This function will panic if float64(val)'s f return exceeds
|
||||||
|
math.MaxInt on your platform.
|
||||||
|
*/
|
||||||
|
func toPosInt(val any) (i int, NaN bool, err error) {
|
||||||
|
|
||||||
|
var f float64
|
||||||
|
|
||||||
|
if f, NaN, err = toPosFloat64(val); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i = int(math.Round(f))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
toString uses reflection to resolve any string value (even custom types and ptrs)
|
||||||
|
to a concrete string.
|
||||||
|
|
||||||
|
err will be ErrBadType if val is not a string type/string-derived type.
|
||||||
|
err will be ErrNilVal if val is nil.
|
||||||
|
*/
|
||||||
|
func toString(val any) (s string, err error) {
|
||||||
|
|
||||||
|
var rv reflect.Value
|
||||||
|
var k reflect.Kind
|
||||||
|
|
||||||
|
if val == nil {
|
||||||
|
err = ErrNilVal
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = reflect.ValueOf(val)
|
||||||
|
k = rv.Kind()
|
||||||
|
|
||||||
|
if k == reflect.Ptr {
|
||||||
|
if rv.IsNil() {
|
||||||
|
// *technically* this should be handled above, but best be safe.
|
||||||
|
err = ErrNilVal
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rv = rv.Elem()
|
||||||
|
k = rv.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
if k == reflect.String {
|
||||||
|
s = rv.String()
|
||||||
|
} else {
|
||||||
|
err = ErrBadType
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package sprigx
|
package sprigx
|
||||||
|
|
||||||
// Nop explicitly performs a NO-OP and returns an empty string, allowing one to override "unsafe" functions.
|
|
||||||
func Nop(obj ...any) (s string) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// metaIsNil returns true if obj is explicitly nil.
|
// metaIsNil returns true if obj is explicitly nil.
|
||||||
func metaIsNil(obj any) (isNil bool) {
|
func metaIsNil(obj any) (isNil bool) {
|
||||||
|
|
||||||
|
|||||||
51
tplx/sprigx/funcs_tpl_nums.go
Normal file
51
tplx/sprigx/funcs_tpl_nums.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package sprigx
|
||||||
|
|
||||||
|
import (
|
||||||
|
`math/big`
|
||||||
|
)
|
||||||
|
|
||||||
|
// numFloat64 returns any string representation of a numeric value or any type of numeric value to a float64.
|
||||||
|
func numFloat64(val any) (f float64, err error) {
|
||||||
|
|
||||||
|
if f, _, err = toFloat64(val); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
numFloatStr wraps numFloat32Str and numFloat64Str.
|
||||||
|
|
||||||
|
val can be a string representation of any numeric value or any type of numeric value.
|
||||||
|
*/
|
||||||
|
func numFloatStr(val any) (s string, err error) {
|
||||||
|
|
||||||
|
var f float64
|
||||||
|
|
||||||
|
if f, _, err = toFloat64(val); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = numFloat64Str(f)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// numFloat32Str returns float32 f as a complete string representation with no truncation (or right-padding).
|
||||||
|
func numFloat32Str(f float32) (s string) {
|
||||||
|
|
||||||
|
s = numFloat64Str(float64(f))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// numFloat64Str returns float64 f as a complete string representation with no truncation (or right-padding).
|
||||||
|
func numFloat64Str(f float64) (s string) {
|
||||||
|
|
||||||
|
var bf *big.Float
|
||||||
|
|
||||||
|
bf = big.NewFloat(f)
|
||||||
|
s = bf.String()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -7,16 +7,29 @@ import (
|
|||||||
`strings`
|
`strings`
|
||||||
)
|
)
|
||||||
|
|
||||||
// osGroupById returns os/user.LookupGroupId. Can accept either an integer or a string.
|
/*
|
||||||
func osGroupById[T string | int](gid T) (g *user.Group, err error) {
|
osGroupById returns os/user.LookupGroupId.
|
||||||
|
|
||||||
|
Can accept either a string (`"1000"`) or any
|
||||||
|
numeric type (`1000`, `-1000`, `1000.0`, `MyCustomType(1000)`, etc.)
|
||||||
|
*/
|
||||||
|
func osGroupById(gid any) (g *user.Group, err error) {
|
||||||
|
|
||||||
|
var i int
|
||||||
|
var NaN bool
|
||||||
var gidStr string
|
var gidStr string
|
||||||
|
|
||||||
switch t := any(gid).(type) {
|
if i, NaN, err = toPosInt(gid); err != nil {
|
||||||
case string:
|
if NaN {
|
||||||
gidStr = t
|
err = nil
|
||||||
case int:
|
if gidStr, err = toString(gid); err != nil {
|
||||||
gidStr = strconv.Itoa(t)
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gidStr = strconv.Itoa(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
g, err = user.LookupGroupId(gidStr)
|
g, err = user.LookupGroupId(gidStr)
|
||||||
@@ -55,16 +68,29 @@ func osHost() (hostNm string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// osUserById returns an os/user.LookupId. Can accept either an integer or a string.
|
/*
|
||||||
func osUserById[T string | int](uid T) (u *user.User, err error) {
|
osUserById returns an os/user.LookupId.
|
||||||
|
|
||||||
|
Can accept either a string (`"1000"`) or any
|
||||||
|
numeric type (`1000`, `-1000`, `1000.0`, `MyCustomType(1000)`, etc.)
|
||||||
|
*/
|
||||||
|
func osUserById(uid any) (u *user.User, err error) {
|
||||||
|
|
||||||
|
var i int
|
||||||
|
var NaN bool
|
||||||
var uidStr string
|
var uidStr string
|
||||||
|
|
||||||
switch t := any(uid).(type) {
|
if i, NaN, err = toPosInt(uid); err != nil {
|
||||||
case string:
|
if NaN {
|
||||||
uidStr = t
|
err = nil
|
||||||
case int:
|
if uidStr, err = toString(uid); err != nil {
|
||||||
uidStr = strconv.Itoa(t)
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uidStr = strconv.Itoa(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err = user.LookupId(uidStr)
|
u, err = user.LookupId(uidStr)
|
||||||
|
|||||||
139
tplx/sprigx/funcs_tpl_time.go
Normal file
139
tplx/sprigx/funcs_tpl_time.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package sprigx
|
||||||
|
|
||||||
|
import (
|
||||||
|
`errors`
|
||||||
|
`strconv`
|
||||||
|
`strings`
|
||||||
|
`time`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
tmFmt formats time t using format string fstr.
|
||||||
|
|
||||||
|
While one certainly can do the same via e.g.
|
||||||
|
|
||||||
|
{{- $t := tmNow -}}
|
||||||
|
{{ $t.Format $fstr }}
|
||||||
|
|
||||||
|
This takes a time.Time as the second (and last) parameter,
|
||||||
|
allowing it to work in pipelines.
|
||||||
|
*/
|
||||||
|
func tmFmt(fstr string, t time.Time) (out string) {
|
||||||
|
|
||||||
|
out = t.Format(fstr)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
tmParseMonth attempts to first try tmParseMonthInt
|
||||||
|
and then tries tmParseMonthStr if v is not "numeric".
|
||||||
|
*/
|
||||||
|
func tmParseMonth(v any) (mon time.Month, err error) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
|
||||||
|
if mon, err = tmParseMonthInt(v); err != nil {
|
||||||
|
if errors.Is(err, strconv.ErrSyntax) {
|
||||||
|
// NaN
|
||||||
|
err = nil
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it gets here, it's a non-numeric string.
|
||||||
|
if s, err = toString(v); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if mon, err = tmParseMonthStr(s); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
tmParseMonthInt parses a number representation of month n to a 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 month constants in the time module:
|
||||||
|
|
||||||
|
* 1: January
|
||||||
|
* 2: February
|
||||||
|
* 3: March
|
||||||
|
* 4: April
|
||||||
|
* 5: May
|
||||||
|
* 6: June
|
||||||
|
* 7: July
|
||||||
|
* 8: August
|
||||||
|
* 9: September
|
||||||
|
* 10: October
|
||||||
|
* 11: November
|
||||||
|
* 12: December
|
||||||
|
|
||||||
|
If n resolves to 0, mon will be the current month (as determined by time.Now).
|
||||||
|
|
||||||
|
If n resolves to > 12, err will be ErrBadMonth.
|
||||||
|
*/
|
||||||
|
func tmParseMonthInt(n any) (mon time.Month, err error) {
|
||||||
|
|
||||||
|
var i int
|
||||||
|
|
||||||
|
if i, _, err = toPosInt(n); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
mon = time.Now().Month()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 12 {
|
||||||
|
err = ErrBadMonth
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mon = time.Month(i)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
tmParseMonthStr parses a string representation of month s to a 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 time.Now).
|
||||||
|
*/
|
||||||
|
func tmParseMonthStr(s string) (mon time.Month, err error) {
|
||||||
|
|
||||||
|
var i int
|
||||||
|
var m time.Month
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
mon = time.Now().Month()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s = strings.ToLower(strings.TrimSpace(s))[0:3]
|
||||||
|
|
||||||
|
for i = range 12 {
|
||||||
|
m = time.Month(i + 1)
|
||||||
|
if strings.ToLower(m.String())[0:3] == s {
|
||||||
|
mon = m
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ErrBadMonth
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user