Files
go_goutils/tplx/sprigx/README.adoc
brent saner 1eea0c2672 v1.16.7
ADDED:
* uuidx
FIXED:
* sprigx docs consistency
2026-02-11 10:21:29 -05:00

2078 lines
50 KiB
Plaintext

= SprigX
Brent Saner <bts@square-r00t.net>
Last rendered {localdatetime}
:doctype: book
:docinfo: shared
:data-uri:
:imagesdir: images
:sectlinks:
:sectnums:
:sectnumlevels: 7
:toc: preamble
:toc2: left
:idprefix:
:toclevels: 7
:source-highlighter: rouge
:docinfo: shared
// BEGIN variable attributes
:sprig_ver: 3
:psutil_ver: 4
:mod_me: r00t2.io/goutils
:pkg_me: tplx/sprigx
:src_root: https://git.r00t2.io
:godoc_root: https://pkg.go.dev
:sprig_web: https://masterminds.github.io/sprig
:mod_sprig: github.com/Masterminds/sprig/v{sprig_ver}
:mod_psutil: github.com/shirou/gopsutil/v{psutil_ver}
:import_sprig: {mod_sprig}
:src_base: {src_root}/r00t2/go_goutils/src/branch/master
:src_dir: {src_base}/{pkg_me}
:import_me: {mod_me}/{pkg_me}
:godoc_me: {godoc_root}/{import_me}
:godoc_sprig: {godoc_root}/{import_sprig}
// END variable attributes
[id="wat"]
== What is SprigX?
SprigX is a suite of extensions to {sprig_web}/[the `sprig` library^] ({godoc_sprig}[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 ({godoc_me})
or the directory landing page ({src_dir}), it may not render correctly.
Be sure to view it at properly via {src_dir}/README.adoc[the AsciiDoc rendering^]
or by downloading and viewing the {src_dir}/README.html[HTML version^] and/or {src_dir}/README.pdf[PDF version^].
====
[id="use"]
== How do I Use SprigX?
The same way you would `sprig`!
[%collapsible]
.Like this.
====
[source,go,subs="attributes"]
----
package main
import (
htmlTplLib "html/template"
txtTplLib "text/template"
"{import_me}"
)
var (
txtTpl *txtTplLib.Template = txtTplLib.
New("").
Funcs(
sprigx.TxtFuncMap(),
)
htmlTpl *htmlTplLib.Template = htmlTplLib.
New("").
Funcs(
sprigx.HtmlFuncMap(),
)
)
----
====
They can even be combined/used together.
[%collapsible]
.Like this.
====
[source,go,subs="attributes"]
----
package main
import (
"text/template"
"{import_sprig}"
"{import_me}"
)
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(),
)
*/
----
====
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`:
this will use `foo` from `sprigx`
[%collapsible]
.(show)
====
[source,go,subs="attributes"]
----
package main
import (
"text/template"
"{import_sprig}"
"{import_me}"
)
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`
[%collapsible]
.(show)
====
[source,go,subs="attributes"]
----
package main
import (
"text/template"
"{import_sprig}"
"{import_me}"
)
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 [[override]]overridden.
[%collapsible]
.(show)
====
This would override a function `foo` and `foo2` in `sprigx` from `foo` and `foo2` from `sprig`, but leave all other `sprig` functions untouched.
[source,go,subs="attributes"]
----
package main
import (
"text/template"
"{import_sprig}"
"{import_me}"
)
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"],
},
),
)
)
----
====
[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
{godoc_sprig}#GenericFuncMap[`{import_sprig}.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 template.FuncMap)
----
This function returns an {godoc_root}/html/template#FuncMap[`html/template.FuncMap`] function map (like <<lib_hfmap>>) combined with
{godoc_sprig}#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 template.FuncMap)
----
This function returns a {godoc_root}/text/template#FuncMap[`text/template.FuncMap`] function map (like <<lib_tfmap>>) combined with
{godoc_sprig}#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 template.FuncMap)
----
This function returns a SprigX {godoc_root}/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 template.FuncMap)
----
This function returns a SprigX {godoc_root}/text/template#FuncMap[`text/template.FuncMap`^].
[id="fn"]
== 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 arguments/parameters it accepts, their type(s),
what it returns, and the returned value(s) type(s).
Because Go template functions can only return either:
* a single value of any type, or
* a value of any type and an `error` (in that order)
you can easily determine whether a function can return an error or not by simply referring to the Function Signature.
[id="fn_dbg"]
=== Debugging
[id="fn_dbg_dump"]
==== `dump`
[source,go]
.Function Signature
----
func dump(a ...interface{}) (out string)
----
The `dump` function directly calls {godoc_root}/davecgh/go-spew/spew#Sdump[`github.com/davecgh/go-spew/spew.Sdump`^]
for whatever object(s) is/are passed to it.
[id="fn_meta"]
=== "Meta"/Template Helpers
[id="fn_meta_isnil"]
==== `metaIsNil`
[source,go]
.Function Signature
----
func metaIsNil(obj any) (isNil bool)
----
`metaIsNil` returns `true` if `obj` is explicitly nil, otherwise it returns false.
This function fills in the gap that {godoc_root}/text/template#IsTrue[`text/template.IsTrue`^] and {godoc_root}/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_net_all"]
=== Networking
These template functions use capabilities from:
* <<fn_net>>
* <<fn_netip>>
* <<fn_netipx>>
The function prefix is used to indicate which module/package a function is added from.
[id="fn_net"]
==== `net`
These template functions contain capabilities from {godoc_root}/net[`net`^].
[id="fn_net_cidrmask"]
===== `netCidrMask`
[source,go]
.Function Signature
----
func netCidrMask(ones, bits int) (mask net.IPMask)
----
`netCidrMask` directly calls {godoc_root}/net#CIDRMask[`net.CIDRMask`^].
[id="fn_net_cidra"]
===== `netExtractAddr`
[source,go]
.Function Signature
----
func netExtractAddr(s string) (addr net.IP, err error)
----
`netExtractAddr` wraps {godoc_root}/net#ParseCIDR[`net.ParseCIDR`^] and returns the {godoc_root}/net#IP[`net.IP`^] component.
[id="fn_net_hph"]
===== `netExtractHost`
[source,go]
.Function Signature
----
func netExtractHost(hostPort string) (host string, err error)
----
`netExtractHost` wraps {godoc_root}/net#SplitHostPort[`net.SplitHostPort`^] and returns the host component (as a string).
[id="fn_net_cidrn"]
===== `netExtractIpnet`
[source,go]
.Function Signature
----
func netExtractIpnet(s string) (ipNet *net.IPNet, err error)
----
`netExtractIpnet` wraps {godoc_root}/net#ParseCIDR[`net.ParseCIDR`^] and returns the {godoc_root}/net#IPNet[`net.IPNet`^] component.
[id="fn_net_hpp"]
===== `netExtractPort`
[source,go]
.Function Signature
----
func netExtractPort(hostPort string) (port uint16, err error)
----
`netExtractPort` wraps {godoc_root}/net#SplitHostPort[`net.SplitHostPort`^] and returns the port component (as a uint16).
[id='fn_net_ifaces']
===== `netIfaces`
[source,go]
.Function Signature
----
func netIfaces() (ifaces []net.Interface, err error)
----
`netIfaces` directly calls {godoc_root}/net#Interfaces[`net.Interfaces`^].
[id="fn_net_ip4mask"]
===== `netIp4Mask`
[source,go]
.Function Signature
----
func netIp4Mask(a, b, c, d any) (mask net.IPMask, err error)
----
`netIp4Mask` wraps {godoc_root}/net#IPv4Mask[`net.IPv4Mask`^].
It is wrapped so that `a`, `b`, `c`, and `d` may be a string:
[source,gotemplate]
----
{{- $mask := netIp4Mask "198" "51" "100" "10" -}}
----
or integers/other numeric:
[source,gotemplate]
----
{{- $mask := netIp4Mask 198 51 100 10 -}}
----
or bytes:
[source,gotemplate]
----
{{- $mask := netIp4Mask 0xc6 0x33 0x64 0x0a -}}
----
or even a mix:
[source,gotemplate]
----
{{- $mask := netIp4Mask "198" 51 "100" 0x0a -}}
----
[id="fn_net_jhp"]
===== `netJoinHostPort`
[source,go]
.Function Signature
----
func netJoinHostPort(host, port string) (out string)
----
`netJoinHostPort` directly calls {godoc_root}/net#JoinHostPort[`net.JoinHostPort`^].
[id="fn_net_parseip"]
===== `netParseIP`
[source,go]
.Function Signature
----
func netParseIP(s string) (ip net.IP)
----
`netParseIP` directly calls {godoc_root}/net#ParseIP[`net.ParseIP`^].
[id="fn_netip"]
==== `net/netip`
These template functions contain capabilities from {godoc_root}/net/netip[`net/netip`^].
[id="fn_netip_addrport"]
===== `netipAddrPort`
[source,go]
.Function Signature
----
func netipAddrPort(ip netip.Addr, port uint16) (addrPort netip.AddrPort)
----
`netipAddrPort` directly calls {godoc_root}/net/netip#AddrPortFrom[`net/netip.AddrPortFrom`^].
[id="fn_netip_parseaddr"]
===== `netipParseAddr`
[source,go]
.Function Signature
----
func netipParseAddr(s string) (addr netip.Addr, err error)
----
`netipParseAddr` directly calls {godoc_root}/net/netip#ParseAddr[`net/netip.ParseAddr`^].
[id="fn_netip_pap"]
===== `netipParseAddrPort`
[source,go]
.Function Signature
----
func netipParseAddrPort(s string) (addrPort netip.AddrPort, err error)
----
`netipParseAddrPort` directly calls {godoc_root}/net/netip#ParseAddrPort[`net/netip.ParseAddrPort`^].
[id="fn_netip_parsepfx"]
===== `netipParsePrefix`
[source,go]
.Function Signature
----
func netipParsePrefix(s string) (pfx netip.Prefix, err error)
----
`netipParsePrefix` directly calls {godoc_root}/net/netip#ParsePrefix[`net/netip.ParsePrefix`^].
[id="fn_netip_pfx"]
===== `netipPrefix`
[source,go]
.Function Signature
----
func netipPrefix(ip netip.Addr, bits int) (pfx netip.Prefix)
----
`netipPrefix` directly calls {godoc_root}/net/netip#PrefixFrom[`net/netip.PrefixFrom`^].
[id="fn_netipx"]
==== `go4.org/netipx`
These template functions contain capabilities from {godoc_root}/go4.org/netipx[`go4.org/netipx`^].
[id="fn_netipx_addripnet"]
===== `netipxAddrIpNet`
[source,go]
.Function Signature
----
func netipxAddrIpNet(addr netip.Addr) (ipNet *net.IPNet)
----
`netipxAddrIpNet` directly calls {godoc_root}/go4.org/netipx#AddrIPNet[`go4.org/netipx.AddrIPNet`^].
[id="fn_netipx_cmppfx"]
===== `netipxCmpPfx`
[source,go]
.Function Signature
----
func netipxCmpPfx(a, b netip.Prefix) (cmp int)
----
`netipxCmpPfx` directly calls {godoc_root}/go4.org/netipx#ComparePrefix[`go4.org/netipx.ComparePrefix`^].
[id="fn_netipx_fromstdaddr"]
===== `netipxFromStdAddr`
[source,go]
.Function Signature
----
func netipxFromStdAddr(ip net.IP, port int, zone string) (addrPort netip.AddrPort, err error)
----
`netipxFromStdAddr` wraps {godoc_root}/go4.org/netipx#FromStdAddr[`go4.org/netipx.FromStdAddr`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false.
[id="fn_netipx_fromip"]
===== `netipxFromIp`
[source,go]
.Function Signature
----
func netipxFromIp(ip net.IP) (addr netip.Addr, err error)
----
`netipxFromIp` wraps {godoc_root}/go4.org/netipx#FromStdIP[`go4.org/netipx.FromStdIP`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false.
[id="fn_netipx_fromipnet"]
===== `netipxFromIpNet`
[source,go]
.Function Signature
----
func netipxFromIpNet(ipNet *net.IPNet) (pfx netip.Prefix, err error)
----
`netipxFromIpNet` wraps {godoc_root}/go4.org/netipx#FromStdIPNet[`go4.org/netipx.FromStdIPNet`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false.
[id="fn_netipx_parserange"]
===== `netipxParseRange`
[source,go]
.Function Signature
----
func netipxParseRange(s string) (ipRange netipx.IPRange, err error)
----
`netipxRange` directly calls {godoc_root}/go4.org/netipx#ParseIPRange[`go4.org/netipx.ParseIPRange`^].
[id="fn_netipx_pfxaddr"]
===== `netipxPfxAddr`
[source,go]
.Function Signature
----
func netipxPfxAddr(s string) (addr netip.Addr, err error)
----
`netipxPfxAddr` directly calls {godoc_root}/go4.org/netipx#ParsePrefixOrAddr[`go4.org/netipx.ParsePrefixOrAddr`^].
[id="fn_netipx_pfxipnet"]
===== `netipxPfxIpNet`
[source,go]
.Function Signature
----
func netipxPfxIpNet(pfx netip.Prefix) (ipNet *net.IPNet)
----
`netipxPfxIpNet` directly calls {godoc_root}/go4.org/netipx#PrefixIPNet[`go4.org/netipx.PrefixIPNet`^].
[id="fn_netipx_pfxlast"]
===== `netipxPfxLast`
[source,go]
.Function Signature
----
func netipxPfxLast(pfx netip.Prefix) (addr netip.Addr)
----
`netipxPfxLast` directly calls {godoc_root}/go4.org/netipx#PrefixLastIP[`go4.org/netipx.PrefixLastIP`^].
[id="fn_netipx_pfxrange"]
===== `netipxPfxRange`
[source,go]
.Function Signature
----
func netipxPfxRange(pfx netip.Prefix) (ipRange netipx.IPRange)
----
`netipxPfxRange` directly calls {godoc_root}/go4.org/netipx#RangeOfPrefix[`go4.org/netipx.RangeOfPrefix`^].
[id="fn_netipx_range"]
===== `netipxRange`
[source,go]
.Function Signature
----
func netipxRange(from, to netip.Addr) (ipRange netipx.IPRange)
----
`netipxRange` directly calls {godoc_root}/go4.org/netipx#IPRangeFrom[`go4.org/netipx.IPRangeFrom`^].
[id="fn_num"]
=== Numbers/Math
[id="fn_num_f32s"]
==== `numFloat32Str`
[source,go]
.Function Signature
----
func numFloat32Str(f float32) (s string)
----
`numFloat32Str` returns a *complete* non-truncated non-right-padded string representation of a `float32`.
[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
[id="fn_os_fqdn"]
==== `osFQDN`
[source,go]
.Function Signature
----
func osFQDN() (fqdn string, err error)
----
`osFQDN` currently just directly calls {godoc_root}/os#Hostname[`os.Hostname`^].
As such, it comes with the same caveats -- namely that it isn't guaranteed to be
an FQDN, it will be precisely/exactly whatever the kernel/OS hostname is set as.
In the future, it may be extended to support a more diligent effort to determine
an actual FQDN, and return an error if it is unable to be derived.
To (relatively) predictably get the "short hostname", use <<fn_os_hst>>.
To directly/predictably use {godoc_root}/os#Hostname[`os.Hostname`^], use <<fn_os_hstnm>>.
[id="fn_os_grpid"]
==== `osGroupById`
[source,go]
.Function Signature
----
func osGroupById[T string | int](gid T) (g *user.Group, err error)
----
`osGroupById` returns an {godoc_root}/os/user#Group[`os/user.Group`^] from a given group ID/GID.
It more or less behaves exactly like {godoc_root}/os/user#LookupGroupId[`os/user.LookupGroupId`^],
except it will accept either a `string` *or* an `int` as the GID.
[id="fn_os_grpnm"]
==== `osGroupByName`
[source,go]
.Function Signature
----
func osGroupByName(grpNm string) (g *user.Group, err error)
----
`osGroupByName` returns an {godoc_root}/os/user#Group[`os/user.Group`^] from a given group name.
It behaves exactly like {godoc_root}/os/user#LookupGroup[`os/user.LookupGroup`^].
[id="fn_os_hst"]
==== `osHost`
[source,go]
.Function Signature
----
func osHost() (out string, err error)
----
`osHost` returns the "short hostname" by calling {godoc_root}/os#Hostname[`os.Hostname`^]
and returning the first "host label" (as RFCs refer to it). This is commonly/colloquially called the "hostname" or "hostname without the domain part".
e.g.:
[source,gotemplate]
----
{{- $fqdn := osFQDN -}}
{{- $h := osHost -}}
{{- $cmp := index ($fqdn | splitList ".") 0 -}}
osHost {{ $h }} should be equal to first label of FQDN {{ $cmp }}.
----
[TIP]
====
The `splitList` function shown above is from the {sprig_web}/string_slice.html[`sprig` string slice functions^].
====
To (try to) get the FQDN, use <<fn_os_fqdn>>.
To directly use {godoc_root}/os#Hostname[`os.Hostname`^], use <<fn_os_hstnm>>.
[id="fn_os_hstnm"]
==== `osHostname`
[source,go]
.Function Signature
----
func osHostname() (out string, err error)
----
`osHostname` directly calls {godoc_root}/os#Hostname[`os.Hostname`^].
[id="fn_os_idst"]
==== `osIdState`
[source,go]
.Function Signature
----
func osIdState() (idst sysutils.IDState)
----
`osIdState` returns the current runtime process' {godoc_root}/r00t2.io/sysutils#IDState[`r00t2.io/sysutils.IDState`^].
It directly calls {godoc_root}/r00t2.io/sysutils#GetIDState[`r00t2.io/sysutils.GetIDState`^].
[WARNING]
====
This is more or less useless on Windows; it returns only a dummy struct for cross-platform compatibility.
====
[id="fn_os_usr"]
==== `osUser`
[source,go]
.Function Signature
----
func osUser() (u *user.User, err error)
----
`osUser` returns the current runtime process' {godoc_root}/os/user#User[`os/user.User`^].
It directly calls {godoc_root}/os/user#Current[`os/user.Current`^].
[id="fn_os_usrid"]
==== `osUserById`
[source,go]
.Function Signature
----
func osUserById[T string | int](uid T) (u *user.User, err error)
----
`osUserById` returns an {godoc_root}/os/user#User[`os/user.User`^] from a given user ID/UID.
It more or less behaves exactly like {godoc_root}/os/user#LookupId[`os/user.LookupId`^],
except it will accept either a `string` *or* an `int` as the UID.
[id="fn_os_usrnm"]
==== `osUserByName`
[source,go]
.Function Signature
----
func osUserByName(userNm string) (u *user.User, err error)
----
`osUserByName` returns an {godoc_root}/os/user#User[`os/user.User`^] from a given username.
It directly calls {godoc_root}/os/user#Lookup[`os/user.Lookup`^].
[id="fn_path"]
=== Paths
[id="fn_path_gnrc"]
==== Generic
These operate similar to {godoc_root}/path[the `path` stdlib library^] and use a fixed `/` path separator.
[id="fn_path_gnrc_pj"]
===== `pathJoin`
[source,go]
.Function Signature
----
func pathJoin(elem ...string) (out string)
----
`pathJoin` directly calls {godoc_root}/path#Join[`path.Join`^].
[WARNING]
====
If you are joining paths in a pipeline, you almost assuredly want <<fn_path_gnrc_ppj>> or <<fn_path_gnrc_pspj>> instead
unless you are explicitly *appending* a pipeline result to a path.
====
[source,gotemplate]
----
{{- pathJoin "a" "b" "c" }}
{{- pathJoin "/" "a" "b" "c" }}
{{- pathJoin "/a/b" "c" }}
----
renders as:
[source,text]
----
a/b/c
/a/b/c
/a/b/c
----
[id="fn_path_gnrc_ppj"]
===== `pathPipeJoin`
[source,go]
.Function Signature
----
func pathPipeJoin(elems ...string) (out string)
----
`pathPipeJoin` operates like <<fn_path_gnrc_pj>> 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.
[source,gotemplate]
----
{{- $myBase := "/a" -}}
{{- pathPipeJoin "b" "c" "a" }}
{{- pathPipeJoin "a" "b" "c" "/" }}
{{- $myBase | pathPipeJoin "b" "c" }}
----
renders as:
[source,text]
----
a/b/c
/a/b/c
/a/b/c
----
[id="fn_path_gnrc_psj"]
===== `pathSliceJoin`
[source,go]
.Function Signature
----
func pathSliceJoin(sl []string) (out string)
----
`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_web}/string_slice.html[`sprig` string slice functions^].
====
[source,gotemplate]
----
{{- $myList := "a,b,c" | splitList "," -}}
{{- $myList | pathSliceJoin }}
{{- ("a,b,c" | splitList ",") | pathSliceJoin }}
{{- ("/,a,b,c" | splitList ",") | pathSliceJoin }}
----
renders as:
[source,text]
----
a/b/c
a/b/c
/a/b/c
----
[id="fn_path_gnrc_pspj"]
===== `pathSlicePipeJoin`
[source,go]
.Function Signature
----
func pathSlicePipeJoin(sl []string, root string) (out string)
----
`pathSlicePipeJoin` operates like <<fn_path_gnrc_ppj>> in that it is suitable for pipeline use in which the root/base path is passed in
from the pipeline, but it is like <<fn_path_gnrc_psj>> 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_web}/string_slice.html[`sprig` string slice functions^].
====
[source,gotemplate]
----
{{- $myBase := "/a" -}}
{{- $myList := "b,c,d" | splitList "." -}}
{{- pathSlicePipeJoin $myList $myBase }}
{{- $myBase | pathSlicePipeJoin $myList }}
----
renders as:
[source,text]
----
/a/b/c
/a/b/c
----
[id="fn_path_gnrc_psubj"]
===== `pathSubJoin`
[source,go]
.Function Signature
----
func pathSubJoin(root string, elems ...string) (out string)
----
`pathSubJoin` operates like <<fn_path_gnrc_pj>> but it expects an explicit root/base path.
The pipeline-friendly equivalent of this is <<fn_path_gnrc_ppj>>.
[source,gotemplate]
----
{{- pathSubJoin "/a/b" "c" }}
{{- pathSubJoin "/" "a" "b" "c" }}
{{- "c" | pathSubJoin "/" "a" "b" }}
----
renders as:
[source,text]
----
/a/b/c
/a/b/c
/a/b/c
----
[id="fn_path_os"]
==== OS/Platform-Tailored
These operate similar to {godoc_root}/path/filepath[the `path/filepath` stdlib library^], and use the OS-specific {godoc_root}/os#PathSeparator[`os.PathSeparator`^].
[WARNING]
====
Take special note of the oddness around specifying Windows paths and drive letters in e.g. <<fn_path_os_pj>>!
It is recommended to make use of <<fn_sys_os>> to conditionally format path bases/roots if needed.
====
[id="fn_path_os_pj"]
===== `osPathJoin`
[source,go]
.Function Signature
----
func osPathJoin(elem ...string) (out string)
----
`osPathJoin` directly calls {godoc_root}/path/filepath#Join[`path/filepath.Join`^].
[WARNING]
====
If you are joining paths in a pipeline, you almost assuredly want <<fn_path_os_ppj>> or <<fn_path_os_pspj>> instead unless you are
explicitly *appending* a pipeline result to a path.
====
[source,gotemplate]
----
{{- osPathJoin "a" "b" "c" }}
{{- osPathJoin "/" "a" "b" "c" }}
{{- osPathJoin "C:\\" "a" "b" "c" }}
{{- osPathJoin "C:" "a" "b" "c" }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
a\b\c
\a\b\c
\a\b\c
C:\a\b\c
C:a\b\c
----
| Others (e.g. Linux, macOS) | [source,text]
----
a/b/c
/a/b/c
C:\/a/b/c
C:/a/b/c
----
|===
[id="fn_path_os_ppj"]
===== `osPathPipeJoin`
[source,go]
.Function Signature
----
func osPathPipeJoin(elems ...string) (out string)
----
`osPathPipeJoin` operates like <<fn_path_gnrc_ppj>> (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 argument to the next pipe function.
[source,gotemplate]
----
{{- $myBase := "/a" -}}
{{- osPathPipeJoin "b" "c" "a" }}
{{- osPathPipeJoin "a" "b" "c" "/" }}
{{- $myBase | osPathPipeJoin "b" "c" }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
a\b\c
\a\b\c
\a\b\c
----
| Others (e.g. Linux, macOS) | [source,text]
----
a/b/c
/a/b/c
/a/b/c
----
|===
[id="fn_path_ossep"]
===== `osPathSep`
[source,go]
.Function Signature
----
func osPathSep() (out string)
----
`osPathSep` returns the {godoc_root}/os#PathSeparator[`os.PathSeparator`^] for this OS.
[source,gotemplate]
----
{{- osPathSep }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
\
----
| Others (e.g. Linux, macOS) | [source,text]
----
/
----
|===
[id="fn_path_os_psj"]
===== `osPathSliceJoin`
[source,go]
.Function Signature
----
func osPathSliceJoin(sl []string) (out string)
----
`osPathSliceJoin` operates like <<fn_path_gnrc_psj>> but with OS-specific path separators.
[TIP]
====
The `splitList` function shown below is from the {sprig_web}/string_slice.html[`sprig` string slice functions^].
====
[source,gotemplate]
----
{{- $myList := "a,b,c" | splitList "," -}}
{{- $myList | osPathSliceJoin }}
{{- ("a,b,c" | splitList ",") | osPathSliceJoin }}
{{- ("/,a,b,c" | splitList ",") | osPathSliceJoin }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
a\b\c
a\b\c
\a\b\c
----
| Others (e.g. Linux, macOS) | [source,text]
----
a/b/c
a/b/c
/a/b/c
----
|===
[id="fn_path_os_pspj"]
===== `osPathSlicePipeJoin`
[source,go]
.Function Signature
----
func osPathSlicePipeJoin(sl []string, root string) (out string)
----
`osPathSlicePipeJoin` operates like <<fn_path_gnrc_pspj>> but with OS-specific separators.
[TIP]
====
The `splitList` function shown below is from the {sprig_web}/string_slice.html[`sprig` string slice functions^].
====
[source,gotemplate]
----
{{- $myBase := "/a" -}}
{{- $myList := "b,c,d" | splitList "." -}}
{{- osPathSlicePipeJoin $myList $myBase }}
{{- $myBase | osPathSlicePipeJoin $myList }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
\a\b\c\d
\a\b\c\d
----
| Others (e.g. Linux, macOS) | [source,text]
----
/a/b/c/d
/a/b/c/d
----
|===
[id="fn_path_os_psubj"]
===== `osPathSubJoin`
[source,go]
.Function Signature
----
func osPathSubJoin(root string, elems ...string) (out string)
----
`osPathSubJoin` operates like <<fn_path_gnrc_psubj>> but with OS-specific separators.
The pipeline-friendly equivalent of this is <<fn_path_os_ppj>>.
[source,gotemplate]
----
{{- osPathSubJoin "/a/b" "c" }}
{{- osPathSubJoin "/" "a" "b" "c" }}
{{- "c" | osPathSubJoin "/" "a" "b" }}
----
renders as:
[cols="^.^2,.^4a",options="header"]
|===
| OS ^| Result
| Windows | [source,text]
----
\a\b\c
\a\b\c
\a\b\c
----
| Others (e.g. Linux, macOS) | [source,text]
----
/a/b/c
/a/b/c
/a/b/c
----
|===
[id="fn_ps"]
=== PSUtil
These are functions from {godoc_root}/{mod_psutil}[`{mod_psutil}`^] packages.
[id="fn_ps_cpu"]
==== CPU/Processor
[id="fn_ps_cpu_cnts"]
===== `psCpuCnts`
[source,go]
.Function Signature
----
func psCpuCnts(logical bool) (numCpu int, err error)
----
`psCpuCnts` directly calls {godoc_root}/{mod_psutil}/cpu#Counts[`{mod_psutil}/cpu.Counts`^].
[id="fn_ps_cpu_info"]
===== `psCpuInfo`
[source,go]
.Function Signature
----
func psCpuInfo() (cpuInfo []cpu.Info, err error)
----
`psCpuInfo` directly calls {godoc_root}/{mod_psutil}/cpu#Info[`{mod_psutil}/cpu.Info`^].
[id="fn_ps_cpu_pct"]
===== `psCpuPct`
[source,go]
.Function Signature
----
func psCpuPct(interval time.Duration, percpu bool) (pcts []float64, err error)
----
`psCpuPct` directly calls {godoc_root}/{mod_psutil}/cpu#Percent[`{mod_psutil}/cpu.Percent`^].
[id="fn_ps_cpu_tms"]
===== `psCpuTimes`
[source,go]
.Function Signature
----
func psCpuTimes(percpu bool) (cpuTimes []cpu.TimesStat, err error)
----
`psCpuTimes` directly calls {godoc_root}/{mod_psutil}/cpu#Times[`{mod_psutil}/cpu.Times`^].
[id="fn_ps_dsk"]
==== Disk
[id="fn_ps_dsk_iocnts"]
===== `psDiskIoCnts`
[source,go]
.Function Signature
----
func psDiskIoCnts(names ...string) (stats map[string]disk.IOCountersStat, err error)
----
`psDiskIoCnts` directly calls {godoc_root}/{mod_psutil}/disk#IOCounters[`{mod_psutil}/disk.IOCounters`^].
[id="fn_ps_dsk_lbl"]
===== `psDiskLabel`
[source,go]
.Function Signature
----
func psDiskLabel(name string) (label string, err error)
----
`psDiskLabel` directly calls {godoc_root}/{mod_psutil}/disk#Label[`{mod_psutil}/disk.Label`^].
[id="fn_ps_dsk_parts"]
===== `psDiskParts`
[source,go]
.Function Signature
----
func psDiskParts(all bool) (parts []disk.PartitionStat, err error)
----
`psDiskParts` directly calls {godoc_root}/{mod_psutil}/disk#Partitions[`{mod_psutil}/disk.Partitions`^].
[id="fn_ps_dsk_srl"]
===== `psDiskSerial`
[source,go]
.Function Signature
----
func psDiskSerial(name string) (serial string, err error)
----
`psDiskSerial` directly calls {godoc_root}/{mod_psutil}/disk#SerialNumber[`{mod_psutil}/disk.SerialNumber`^].
[id="fn_ps_dsk_usg"]
===== `psDiskUsage`
[source,go]
.Function Signature
----
func psDiskUsage(path string) (usage *disk.UsageStat, err error)
----
`psDiskUsage` directly calls {godoc_root}/{mod_psutil}/disk#Usage[`{mod_psutil}/disk.Usage`^].
[id="fn_ps_hst"]
==== Host
[id="fn_ps_hst_boot"]
===== `psHostBoot`
[source,go]
.Function Signature
----
func psHostBoot() (bootEpoch uint64, err error)
----
`psHostBoot` directly calls {godoc_root}/{mod_psutil}/host#BootTime[`{mod_psutil}/host.BootTime`^].
[id="fn_ps_hst_id"]
===== `psHostId`
[source,go]
.Function Signature
----
func psHostId() (hostId string, err error)
----
`psHostId` directly calls {godoc_root}/{mod_psutil}/host#HostID[`{mod_psutil}/host.HostID`^].
[id="fn_ps_hst_info"]
===== `psHostInfo`
[source,go]
.Function Signature
----
func psHostInfo() (info *host.InfoStat, err error)
----
`psHostInfo` directly calls {godoc_root}/{mod_psutil}/host#Info[`{mod_psutil}/host.Info`^].
[id="fn_ps_hst_krnarch"]
===== `psHostKernArch`
[source,go]
.Function Signature
----
func psHostKernArch() (arch string, err error)
----
`psHostKernArch` directly calls {godoc_root}/{mod_psutil}/host#KernelArch[`{mod_psutil}/host.KernelArch`^].
[id="fn_ps_hst_krnver"]
===== `psHostKernVer`
[source,go]
.Function Signature
----
func psHostKernVer() (ver string, err error)
----
`psHostKernVer` directly calls {godoc_root}/{mod_psutil}/host#KernelVersion[`{mod_psutil}/host.KernelVersion`^].
[id="fn_ps_hst_plat"]
===== `psHostPlatInfo`
[source,go]
.Function Signature
----
func psHostPlatInfo() (platInfo [3]string, err error)
----
`psHostPlatInfo` wraps {godoc_root}/{mod_psutil}/host#PlatformInformation[`{mod_psutil}/host.PlatformInformation`^].
It is necessary to wrap because the function normally returns `(string, string, string, error)` but a template function may only return either a single value (of any type) or a single value of any type and an error, so the three `string` returns are consolidated into an ordered `[3]string`.
[id="fn_ps_hst_uptm"]
===== `psHostPlatUptime`
[source,go]
.Function Signature
----
func psHostPlatUptime() (uptimeSecs uint64, err error)
----
`psHostPlatUptime` directly calls {godoc_root}/{mod_psutil}/host#Uptime[`{mod_psutil}/host.Uptime`^].
[id="fn_ps_hst_usrs"]
===== `psHostUsers`
[source,go]
.Function Signature
----
func psHostUsers() (users []host.UserStat, err error)
----
`psHostUsers` directly calls {godoc_root}/{mod_psutil}/host#Users[`{mod_psutil}/host.Users`^].
[id="fn_ps_hst_virt"]
===== `psHostPlatVirt`
[source,go]
.Function Signature
----
func psHostVirt() (virtInfo [2]string, err error)
----
`psHostPlatVirt` wraps {godoc_root}/{mod_psutil}/host#Virtualization[`{mod_psutil}/host.Virtualization`^].
It is necessary to wrap because the function normally returns `(string, string, error)` but a template function may only return either a single value (of any type) or a single value of any type and an error, so the two `string` returns are consolidated into an ordered `[2]string`.
[id="fn_ps_ld"]
==== Load
[id="fn_ps_ld_avg"]
===== `psLoadAvg`
[source,go]
.Function Signature
----
func psLoadAvg() (avg *load.AvgStat, err error)
----
`psLoadAvg` directly calls {godoc_root}/{mod_psutil}/load#Avg[`{mod_psutil}/load.Avg`^].
[id="fn_ps_ld_misc"]
===== `psLoadMisc`
[source,go]
.Function Signature
----
func psLoadMisc() (misc *load.MiscStat, err error)
----
`psLoadMisc` directly calls {godoc_root}/{mod_psutil}/load#Misc[`{mod_psutil}/load.Misc`^].
[id="fn_ps_mem"]
==== Memory
[id="fn_ps_mem_exvmem"]
===== `psMemExVMem`
[source,go]
.Function Signature
----
func psMemExVMem() (exVMem *mem.ExVirtualMemory, err error)
----
[WARNING]
====
This function is available on Windows and Linux platforms *only*.
====
[WARNING]
====
This function returns very different types depending on platform.
* Linux: {godoc_root}/{mod_psutil}/mem?GOOS=linux#ExVirtualMemory[`mem.ExVirtualMemory`^]
* Windows: {godoc_root}/{mod_psutil}/mem?GOOS=windows#ExVirtualMemory[`mem.ExVirtualMemory`^]
====
This function wraps link:{godoc_root}/{mod_psutil}/mem?GOOS=linux#NewExLinux[`{mod_psutil}/mem.NewExLinux`^].link:{godoc_root}/{mod_psutil}/mem?GOOS=linux#ExLinux.VirtualMemory[`VirtualMemory`^] on Linux and
link:{godoc_root}/{mod_psutil}/mem?GOOS=windows#NewExWindows[`{mod_psutil}/mem.NewExWindows`^].link:{godoc_root}/{mod_psutil}/mem?GOOS=windows#ExWindows.VirtualMemory[`VirtualMemory`^] on Windows.
[id="fn_ps_mem_swap"]
===== `psMemSwap`
[source,go]
.Function Signature
----
func psMemSwap() (swap *mem.SwapMemoryStat, err error)
----
`psMemSwap` directly calls {godoc_root}/{mod_psutil}/mem#SwapMemory[`{mod_psutil}/mem.SwapMemory`^].
[id="fn_ps_mem_swapdevs"]
===== `psMemSwapDevs`
[source,go]
.Function Signature
----
func psMemSwapDevs() (swapDevs []*mem.SwapDevice, err error)
----
`psMemSwapDevs` directly calls {godoc_root}/{mod_psutil}/mem#SwapDevices[`{mod_psutil}/mem.SwapDevices`^].
[id="fn_ps_mem_vmem"]
===== `psMemVMem`
[source,go]
.Function Signature
----
func psMemVMem() (vmem *mem.VirtualMemoryStat, err error)
----
`psMemVMem` directly calls {godoc_root}/{mod_psutil}/mem#VirtualMemory[`{mod_psutil}/mem.VirtualMemory`^].
[id="fn_ps_net"]
==== Network
[id="fn_ps_net_conns"]
===== `psNetConns`
[source,go]
.Function Signature
----
func psNetConns(kind string) (conns []net.ConnectionStat, err error)
----
`psNetConns` directly calls {godoc_root}/{mod_psutil}/net#Connections[`{mod_psutil}/net.Connections`^].
[id="fn_ps_net_connsmax"]
===== `psNetConnsMax`
[source,go]
.Function Signature
----
func psNetConnsMax(kind string, maxConn int) (conns []net.ConnectionStat, err error)
----
`psNetConnsMax` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsMax[`{mod_psutil}/net.ConnectionsMax`^].
[id="fn_ps_net_connspid"]
===== `psNetConnsPid`
[source,go]
.Function Signature
----
func psNetConnsPid(kind string, pid int32) (conns []net.ConnectionStat, err error)
----
`psNetConnsPid` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsPid[`{mod_psutil}/net.ConnectionsPid`^].
[id="fn_ps_net_connspidmax"]
===== `psNetConnsPidMax`
[source,go]
.Function Signature
----
func psNetConnsPidMax(kind string, pid int32, maxConn int) (conns []net.ConnectionStat, err error)
----
`psNetConnsPidMax` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsPidMax[`{mod_psutil}/net.ConnectionsPidMax`^].
[id="fn_ps_net_ct"]
===== `psNetCTStats`
[source,go]
.Function Signature
----
func psNetCTStats(percCpu bool) (ctStats []net.ConntrackStat, err error)
----
`psNetCTStats` directly calls {godoc_root}/{mod_psutil}/net#ConntrackStats[`{mod_psutil}/net.ConntrackStats`^].
[id="fn_ps_net_ctlist"]
===== `psNetCTStatList`
[source,go]
.Function Signature
----
func psNetCTStatList() (ctStats *net.ConntrackStatList, err error)
----
`psNetCTStatList` directly calls {godoc_root}/{mod_psutil}/net#ConntrackStatList[`{mod_psutil}/net.ConntrackStatList`^].
[id="fn_ps_net_fltcnt"]
===== `psNetFilterCnts`
[source,go]
.Function Signature
----
func psNetFilterCnts() (filterCnts []net.FilterStat, err error)
----
`psNetFilterCnts` directly calls {godoc_root}/{mod_psutil}/net#FilterCounters[`{mod_psutil}/net.FilterCounters`^].
[id="fn_ps_net_iocnts"]
===== `psNetIoCnts`
[source,go]
.Function Signature
----
func psNetIoCnts(perNIC bool) (ioCnts []net.IOCountersStat, err error)
----
`psNetIoCnts` directly calls {godoc_root}/{mod_psutil}/net#IOCounters[`{mod_psutil}/net.IOCounters`^].
[id="fn_ps_net_iocntsfl"]
===== `psNetIoCntsFile`
[source,go]
.Function Signature
----
func psNetIoCntsFile(perNIC bool, filepath string) (ioCnts []net.IOCountersStat, err error)
----
`psNetIoCntsFile` directly calls {godoc_root}/{mod_psutil}/net#IOCountersByFile[`{mod_psutil}/net.IOCountersByFile`^].
[id="fn_ps_net_ifaces"]
===== `psNetIfaces`
[source,go]
.Function Signature
----
func psNetIfaces() (ioCnts []net.InterfaceStatList, err error)
----
`psNetIfaces` directly calls {godoc_root}/{mod_psutil}/net#Interfaces[`{mod_psutil}/net.Interfaces`^].
[id="fn_ps_net_pids"]
===== `psNetPids`
[source,go]
.Function Signature
----
func psNetPids() (pids []int32, err error)
----
`psNetPids` directly calls {godoc_root}/{mod_psutil}/net#Pids[`{mod_psutil}/net.Pids`^].
[id="fn_ps_net_protocnts"]
===== `psNetProtoCnt`
[source,go]
.Function Signature
----
func psNetProtoCnt(protos []string) (protoCnts []net.ProtoCountersStat, err error)
----
[WARNING]
====
This only works properly on Linux currently per upstream.
====
`psNetProtoCnt` directly calls {godoc_root}/{mod_psutil}/net#ProtoCounters[`{mod_psutil}/net.ProtoCounters`^].
[id="fn_ps_net_rev"]
===== `psNetRev`
[source,go]
.Function Signature
----
func psNetRev(b []byte) (out []byte)
----
[WARNING]
====
This function only exists on Linux.
====
`psNetRev` directly calls {godoc_root}/{mod_psutil}/net?GOOS=linux#Reverse[`{mod_psutil}/net.Reverse`^].
[id="fn_ps_proc"]
==== Processes
[id="fn_ps_procs_procs"]
===== `psProcs`
[source,go]
.Function Signature
----
func psProcs(pid int32) (procs []*process.Process, err error)
----
`psProcs` directly calls {godoc_root}/{mod_psutil}/process#Processes[`{mod_psutil}/proc.Processes`^].
[id="fn_ps_proc_new"]
===== `psProcNew`
[source,go]
.Function Signature
----
func psProcNew(pid int32) (proc *process.Process, err error)
----
`psProcNew` directly calls {godoc_root}/{mod_psutil}/process#NewProcess[`{mod_psutil}/proc.NewProcess`^].
[id="fn_ps_proc_pids"]
===== `psProcPids`
[source,go]
.Function Signature
----
func psProcPids() (pids []int32, err error)
----
`psProcPids` directly calls {godoc_root}/{mod_psutil}/process#Pids[`{mod_psutil}/proc.Pids`^].
[id="fn_ps_proc_pidxst"]
===== `psProcPidExists`
[source,go]
.Function Signature
----
func psProcPidExists(pid int32) (exists bool, err error)
----
`psProcPidExists` directly calls {godoc_root}/{mod_psutil}/process#PidExists[`{mod_psutil}/proc.PidExists`^].
[id="fn_ps_sns"]
==== Sensors/Thermals
[id="fn_ps_sns_extemp"]
===== `psSensorExTemp`
[source,go]
.Function Signature
----
func psSensorExTemp() (temps []sensors.ExTemperature, err error)
----
[WARNING]
====
This function only exists on Linux.
====
`psSensorExTemp` wraps link:{godoc_root}/{mod_psutil}/sensors?GOOS=linux#NewExLinux[`{mod_psutil}/sensors.NewExLinux`^].link:{godoc_root}/{mod_psutil}/sensors?GOOS=linux#TemperatureWithContext[`{mod_psutil}/sensors.TemperatureWithContext`^].
[id="fn_ps_sns_temps"]
===== `psSensorTemps`
[source,go]
.Function Signature
----
func psSensorTemps() (temps []sensors.TemperatureStat, err error)
----
`psSensorTemps` directly calls {godoc_root}/{mod_psutil}/sensors#SensorsTemperatures[`{mod_psutil}/sensors.SensorsTemperatures`^].
[id="fn_ps_winsvc"]
==== Windows Services
[WARNING]
====
All of these functions are only available on Windows.
====
[id="fn_ps_winsvc_list"]
===== `psWinsvcList`
[source,go]
.Function Signature
----
func psWinsvcList() (svcs []winservices.Service, err error)
----
[WARNING]
====
This function is only available on Windows.
====
`psWinsvcList` directly calls {godoc_root}/{mod_psutil}/winservices?GOOS=windows#ListServices[`{mod_psutil}/winservices.ListServices`^].
[id="fn_ps_winsvc_new"]
===== `psWinsvcNew`
[source,go]
.Function Signature
----
func psWinsvcNew(svcName string) (svc *winservices.Service, err error)
----
[WARNING]
====
This function is only available on Windows.
====
`psWinsvcNew` directly calls {godoc_root}/{mod_psutil}/winservices?GOOS=windows#NewService[`{mod_psutil}/winservices.NewService`^].
[id="fn_str"]
=== Strings
[id="fn_str_extindent"]
==== `extIndent`
[source,go]
.Function Signature
----
func extIndent(
levels int,
skipFirst, skipEmpty, skipWhitespace bool,
indentString, input string,
) (out string)
----
`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 doublespace text!
====
It has quite a few arguments, however:
[cols="^.^1m,^.^1m,.^4a",options="header"]
|===
| Argument ^| Type | Description
| levels | int | 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 | bool | If true, skip indenting the first line. This is particularly handy if you like to visually align your function calls in your templates.
| skipEmpty | bool | If true, do not add an indent to *empty* lines (where an "empty line" means "only has a linebreak").
| skipWhitespace | bool | If true, do not add an indent to lines that *only* consist of whitespace (spaces, tabs, etc.) and a linebreak.
| indentString | string | The string to use as the "indent character". This can be any string, such as `"<SP>"` (https://asciiref.dev/#c32[`0x20`^]), `"\t"`, `"."`, `"\|"`, `"=="` etc.
| input | string | The text to be indented. Because it is the last argument, `extIndent` works with pipelined text as well.
|===
[id="fn_sys"]
=== System/Platform/Architecture
[id="fn_sys_arch"]
==== `sysArch`
[source,go]
.Function Signature
----
func sysArch() (out string)
----
Returns the {godoc_root}/runtime#GOARCH[`runtime.GOARCH`^] constant.
[id="fn_sys_numcpu"]
==== `sysNumCpu`
[source,go]
.Function Signature
----
func sysNumCpu() (cnt int)
----
`sysNumCpu` directly calls {godoc_root}/runtime#NumCPU[`runtime.NumCPU`^].
[id="fn_sys_os"]
==== `sysOsName`
[source,go]
.Function Signature
----
func sysOsNm() (out string)
----
Returns the {godoc_root}/runtime#GOOS[`runtime.GOOS`^] constant.
[id="fn_sys_rntm"]
==== `sysRuntime`
[source,go]
.Function Signature
----
func sysRuntime() (out map[string]string)
----
This function returns a `map[string]string` of various information from the {godoc_root}/runtime[`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_web}/conversion.html[Sprig conversion functions^] if necessary.
====
.`sysRuntime` Values
[cols="^.^3m,^.^3",options="header"]
|===
| Key | Value Type
| compiler | {godoc_root}/runtime#Compiler[string^]
| arch | {godoc_root}/runtime#GOARCH[string^]
| os | {godoc_root}/runtime#GOOS[string^]
| maxprocs | {godoc_root}/runtime#GOMAXPROCS[int^] footnote:[For safety concerns, `sprigx` does not allow *setting* `GOMAXPROCS`, this value only contains the *current* `GOMAXPROCS` value.]
| cpu_cnt | {godoc_root}/runtime#NumCPU[int^]
| num_cgo | {godoc_root}/runtime#NumCgoCall[int^]
| num_go | {godoc_root}/runtime#NumGoroutine[int^]
| go_ver | {godoc_root}/runtime#Version[string^]
|===
As a convenience, some of these values also have their own dedicated functions as well:
* <<fn_sys_arch>>
* <<fn_sys_numcpu>>
* <<fn_sys_os>>
[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 {godoc_root}/time#Date[`time.Date`^].
[id="fn_tm_fltmic"]
==== `tmFloatMicro`
[source,go]
.Function Signature
----
func tmFloatMicro(t time.Time) (f64 float64)
----
`tmFloatMicro` directly calls {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/time#Now[`time.Now`^]).
If `n` resolves to > `12`, `err` will be `sprigx.ErrBadMonth` (though be sure to use {godoc_root}/errors#Is[`errors.Is`^]; it will be wrapped by link:{godoc_root}/text/template#ExecError[`(text/template).ExecError`]/link:{godoc_root}/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 {godoc_root}/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 {godoc_root}/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 {godoc_root}/time#Parse[`time.Parse`^].
Be sure that `layout` is a properly parseable {godoc_root}/time#Layout[layout format^].