4 Commits

Author SHA1 Message Date
brent saner
67c7faf449 v1.16.6
FIXED:
* tplx/sprigx float to string non-truncating was... truncating. it no
  longer is.
2026-01-30 20:21:34 -05:00
brent saner
82c69ec542 v1.16.5
FIXED:
* Misaligned `Nop` in README.adoc
2026-01-30 06:49:22 -05:00
brent saner
07e0e587fa v1.16.4
ADDED:
* math, time functions to tplx/sprigx
FIXED:
* logging not initializing properly on some BSDs
2026-01-30 06:35:23 -05:00
brent saner
1bd6e1256c v1.16.3
ADDED:
* Much more functions to tplx/sprigx
2026-01-29 19:02:21 -05:00
25 changed files with 9341 additions and 1226 deletions

View File

@@ -22,9 +22,20 @@ for f in $(find . -type f -iname "README.adoc"); do
if command -v pandoc &> /dev/null; if command -v pandoc &> /dev/null;
then then
newf="${pfx}.md" newf="${pfx}.md"
asciidoctor -a ROOTDIR="${orig}/" -b docbook -o - "${f}" | pandoc -f docbook -t markdown_strict -o "${newf}"
echo "Generated ${newf} from ${f}" set +e
git add "${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 ];
then
echo "Generated ${newf} from ${f}"
git add "${newf}"
else
echo "Failed to generate ${newf} from ${f}"
git rm "${newf}" 2>/dev/null
fi
set -e
fi fi
cd ${orig} cd ${orig}
done done

19
chkplat.sh Executable file
View 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

22
go.mod
View File

@@ -4,24 +4,32 @@ go 1.25
require ( require (
github.com/Masterminds/sprig/v3 v3.3.0 github.com/Masterminds/sprig/v3 v3.3.0
github.com/coreos/go-systemd/v22 v22.6.0 github.com/coreos/go-systemd/v22 v22.7.0
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
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.39.0 golang.org/x/sys v0.40.0
r00t2.io/sysutils v1.15.1 r00t2.io/sysutils v1.16.2
) )
require ( require (
dario.cat/mergo v1.0.1 // indirect dario.cat/mergo v1.0.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/djherbis/times v1.6.0 // indirect github.com/djherbis/times v1.6.0 // indirect
github.com/ebitengine/purego v0.9.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cast v1.10.0 // indirect
golang.org/x/crypto v0.26.0 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/sync v0.19.0 // indirect golang.org/x/sync v0.19.0 // indirect
) )

57
go.sum
View File

@@ -1,21 +1,26 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
@@ -24,33 +29,43 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY=
github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.15.1 h1:0EVZZAxTFqQN6jjfjqUKkXye0LMshUA5MO7l3Wd6wH8=
r00t2.io/sysutils v1.15.1/go.mod h1:T0iOnaZaSG5NE1hbXTqojRZc0ia/u8TB73lV7zhMz58=

View File

@@ -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.

View File

@@ -1,3 +1,5 @@
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
package logging package logging
var ( var (

View File

@@ -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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,57 @@
package sprigx package sprigx
import ( import (
"path" `os`
"path/filepath" `os/user`
`path`
`path/filepath`
`runtime`
`time`
`github.com/davecgh/go-spew/spew`
`github.com/shirou/gopsutil/v4/cpu`
`github.com/shirou/gopsutil/v4/disk`
`github.com/shirou/gopsutil/v4/host`
`github.com/shirou/gopsutil/v4/load`
`github.com/shirou/gopsutil/v4/mem`
psnet `github.com/shirou/gopsutil/v4/net`
`github.com/shirou/gopsutil/v4/process`
`github.com/shirou/gopsutil/v4/sensors`
`r00t2.io/goutils/timex`
`r00t2.io/sysutils`
) )
var ( var (
// genericMap holds functions usable/intended for use in either an [html/template.FuncMap] or [text/template.FuncMap]. // genericMap holds functions usable/intended for use in either an [html/template.FuncMap] or [text/template.FuncMap].
genericMap map[string]any = map[string]any{ genericMap map[string]any = map[string]any{
// Debugging // Debugging
"dump": dump, "dump": spew.Sdump,
// Strings /*
"extIndent": extIndent, // PR in: https://github.com/Masterminds/sprig/pull/468 "Meta"/Template-Helpers
// OS/System */
"sysArch": sysArch, "metaIsNil": metaIsNil,
"sysNumCpu": sysNumCpu, /*
"sysOsName": sysOsNm, Numbers/Math
"sysRuntime": sysRuntime, */
"numFloat32Str": numFloat32Str,
"numFloat64": numFloat64,
"numFloat64Str": numFloat64Str,
"numFloatStr": numFloatStr,
/*
OS
*/
"osFQDN": osFQDN,
"osGroupById": osGroupById,
"osGroupByName": user.LookupGroup,
"osHost": osHost,
"osHostname": os.Hostname,
"osIdState": sysutils.GetIDState,
"osUser": user.Current,
"osUserById": osUserById,
"osUserByName": user.Lookup,
/*
Paths
*/
// Paths: Generic // Paths: Generic
"pathJoin": path.Join, "pathJoin": path.Join,
"pathPipeJoin": pathPipeJoin, "pathPipeJoin": pathPipeJoin,
@@ -30,6 +65,84 @@ var (
"osPathSliceJoin": osPathSliceJoin, "osPathSliceJoin": osPathSliceJoin,
"osPathSlicePipeJoin": osPathSlicePipeJoin, "osPathSlicePipeJoin": osPathSlicePipeJoin,
"osPathSubJoin": osPathSubJoin, "osPathSubJoin": osPathSubJoin,
/*
PSUtil
(https://pkg.go.dev/github.com/shirou/gopsutil/v4)
*/
// .../cpu
"psCpuCnts": cpu.Counts,
"psCpuInfo": cpu.Info,
"psCpuPct": cpu.Percent,
"psCpuTimes": cpu.Times,
// .../disk
"psDiskIoCnts": disk.IOCounters,
"psDiskLabel": disk.Label,
"psDiskParts": disk.Partitions,
"psDiskSerial": disk.SerialNumber,
"psDiskUsage": disk.Usage,
// .../host
"psHostBoot": host.BootTime,
"psHostId": host.HostID,
"psHostInfo": host.Info,
"psHostKernArch": host.KernelArch,
"psHostKernVer": host.KernelVersion,
"psHostPlatInfo": psHostPlatInfo,
"psHostUptime": host.Uptime,
"psHostUsers": host.Users,
"psHostVirt": psHostVirt,
// .../load
"psLoadAvg": load.Avg,
"psLoadMisc": load.Misc,
// .../mem
"psMemSwap": mem.SwapMemory,
"psMemSwapDevs": mem.SwapDevices,
"psMemVMem": mem.VirtualMemory,
// .../net
"psNetConns": psnet.Connections,
"psNetConnsMax": psnet.ConnectionsMax,
"psNetConnsPid": psnet.ConnectionsPid,
"psNetConnsPidMax": psnet.ConnectionsPidMax,
"psNetCTStats": psnet.ConntrackStats,
"psNetCTStatList": psnet.NewConntrackStatList,
"psNetFilterCnts": psnet.FilterCounters,
"psNetIoCnts": psnet.IOCounters,
"psNetIoCntsFile": psnet.IOCountersByFile,
"psNetIfaces": psnet.Interfaces,
"psNetPids": psnet.Pids,
"psNetProtoCnt": psnet.ProtoCounters,
// .../process
"psProcs": process.Processes,
"psProcNew": process.NewProcess,
"psProcPids": process.Pids,
"psProcPidExists": process.PidExists,
// .../sensors
"psSensorTemps": sensors.SensorsTemperatures,
/*
Strings
*/
"extIndent": extIndent, // PR in: https://github.com/Masterminds/sprig/pull/468
/*
System/Platform
*/
"sysArch": sysArch,
"sysNumCpu": runtime.NumCPU,
"sysOsName": sysOsNm,
"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].

View File

@@ -0,0 +1,9 @@
//go:build darwin
package sprigx
var (
osGenericMap map[string]any = map[string]any{}
osHtmlMap map[string]any = map[string]any{}
osTxtMap map[string]any = map[string]any{}
)

View File

@@ -0,0 +1,25 @@
//go:build linux
package sprigx
import (
`github.com/shirou/gopsutil/v4/mem`
psnet `github.com/shirou/gopsutil/v4/net`
)
var (
osGenericMap map[string]any = map[string]any{
/*
PSUtil
(https://pkg.go.dev/github.com/shirou/gopsutil/v4)
*/
// .../mem
"psMemExVMem": mem.NewExLinux().VirtualMemory,
// .../net
"psNetRev": psnet.Reverse,
// .../sensors
"psSensorExTemp": psSensorExTemp,
}
osHtmlMap map[string]any = map[string]any{}
osTxtMap map[string]any = map[string]any{}
)

View File

@@ -0,0 +1,9 @@
//go:build !(linux || windows || darwin)
package sprigx
var (
osGenericMap map[string]any = map[string]any{}
osHtmlMap map[string]any = map[string]any{}
osTxtMap map[string]any = map[string]any{}
)

View File

@@ -0,0 +1,24 @@
//go:build windows
package sprigx
import (
`github.com/shirou/gopsutil/v4/mem`
`github.com/shirou/gopsutil/v4/winservices`
)
var (
osGenericMap map[string]any = map[string]any{
/*
PSUtil
(https://pkg.go.dev/github.com/shirou/gopsutil/v4)
*/
// .../mem
"psMemExVMem": mem.NewExWindows().VirtualMemory,
// .../winservices
"psWinsvcList": winservices.ListServices,
"psWinsvcNew": winservices.NewService,
}
osHtmlMap map[string]any = map[string]any{}
osTxtMap map[string]any = map[string]any{}
)

11
tplx/sprigx/errs.go Normal file
View 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")
)

View File

@@ -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.
@@ -25,6 +127,11 @@ func FuncMap() (fmap map[string]any) {
for fn, f = range genericMap { for fn, f = range genericMap {
fmap[fn] = f fmap[fn] = f
} }
if osGenericMap != nil && len(osGenericMap) > 0 {
for fn, f = range osGenericMap {
fmap[fn] = f
}
}
return return
} }
@@ -43,6 +150,17 @@ func HtmlFuncMap() (fmap htpl.FuncMap) {
} }
} }
if osHtmlMap != nil && len(osHtmlMap) > 0 {
for fn, f = range osHtmlMap {
fmap[fn] = f
}
}
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 return
} }
@@ -60,5 +178,179 @@ func TxtFuncMap() (fmap ttpl.FuncMap) {
} }
} }
if osTxtMap != nil && len(osTxtMap) > 0 {
for fn, f = range osTxtMap {
fmap[fn] = f
}
}
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 return
} }

View File

@@ -1,17 +0,0 @@
package sprigx
import (
`github.com/davecgh/go-spew/spew`
)
/*
dump calls [spew.Sdump] on obj.
[spew.Sdump]: https://pkg.go.dev/github.com/davecgh/go-spew/spew
*/
func dump(obj any) (out string) {
out = spew.Sdump(obj)
return
}

View File

@@ -0,0 +1,9 @@
package sprigx
// metaIsNil returns true if obj is explicitly nil.
func metaIsNil(obj any) (isNil bool) {
isNil = obj == nil
return
}

View 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.Text('f', -1)
return
}

View File

@@ -1,13 +1,99 @@
package sprigx package sprigx
import ( import (
"os" `os`
`os/user`
`strconv`
`strings`
) )
// osHostname returns os.Hostname() /*
func osHostname() (out string, err error) { osGroupById returns os/user.LookupGroupId.
out, err = os.Hostname() 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
if i, NaN, err = toPosInt(gid); err != nil {
if NaN {
err = nil
if gidStr, err = toString(gid); err != nil {
return
}
} else {
return
}
} else {
gidStr = strconv.Itoa(i)
}
g, err = user.LookupGroupId(gidStr)
return
}
/*
osFQDN (tries to) return the FQDN of this host.
Currently it just calls os.Hostname() but may be extended to "try harder" in the future.
*/
func osFQDN() (fqdn string, err error) {
fqdn, err = os.Hostname()
return
}
/*
osHost returns the system's "host shortname".
Currently it just calls os.Hostname() and takes the first
"host label" (as RFCs refer to it), but it may be extended
in the future.
*/
func osHost() (hostNm string, err error) {
hostNm, err = os.Hostname()
if hostNm == "" {
return
}
hostNm = strings.Split(hostNm, ".")[0]
return
}
/*
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
if i, NaN, err = toPosInt(uid); err != nil {
if NaN {
err = nil
if uidStr, err = toString(uid); err != nil {
return
}
} else {
return
}
} else {
uidStr = strconv.Itoa(i)
}
u, err = user.LookupId(uidStr)
return return
} }

View File

@@ -0,0 +1,43 @@
package sprigx
import (
`github.com/shirou/gopsutil/v4/host`
)
/*
psHostPlatInfo returns a "squashed" github.com/shirou/gopsutil/v4/host.PlatformInformation;
normally it returns a (string, string, string, error)
but you can only have a (any) or (any, error) return in Golang templates.
*/
func psHostPlatInfo() (platInfo [3]string, err error) {
var s1 string
var s2 string
var s3 string
if s1, s2, s3, err = host.PlatformInformation(); err != nil {
return
}
platInfo = [3]string{s1, s2, s3}
return
}
/*
psHostVirt returns a "squared" github.com/shirou/gopsutil/v4/host.Virtualization;
normally it returns a (string, string, error) but Go templates etc.
*/
func psHostVirt() (virtInfo [2]string, err error) {
var s1 string
var s2 string
if s1, s2, err = host.Virtualization(); err != nil {
return
}
virtInfo = [2]string{s1, s2}
return
}

View File

@@ -0,0 +1,15 @@
package sprigx
import (
`context`
`github.com/shirou/gopsutil/v4/sensors`
)
// psSensorExTemp wraps github.com/shirou/gopsutil/v4/sensors.NewExLinux().TemperatureWithContext() to not require a context.
func psSensorExTemp() (exTemps []sensors.ExTemperature, err error) {
exTemps, err = sensors.NewExLinux().TemperatureWithContext(context.Background())
return
}

View File

@@ -5,6 +5,22 @@ import (
`runtime` `runtime`
) )
// sysArch returns [runtime.GOARCH].
func sysArch() (out string) {
out = runtime.GOARCH
return
}
// sysOsNm returns [runtime.GOOS].
func sysOsNm() (out string) {
out = runtime.GOOS
return
}
// sysRuntime returns various information from [runtime]. // sysRuntime returns various information from [runtime].
func sysRuntime() (out map[string]string) { func sysRuntime() (out map[string]string) {
@@ -21,27 +37,3 @@ func sysRuntime() (out map[string]string) {
return return
} }
// sysArch returns [runtime.GOARCH].
func sysArch() (out string) {
out = runtime.GOARCH
return
}
// sysNumCpu returns the reuslt from [runtime.NumCPU].
func sysNumCpu() (out string) {
out = fmt.Sprintf("%d", runtime.NumCPU())
return
}
// sysOsNm returns [runtime.GOOS].
func sysOsNm() (out string) {
out = runtime.GOOS
return
}

View 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
}