* IDState cleaned up. Should work on all *NIXes now.
* Can now get IDState of arbitrary PID.
* Shuffled some env stuff around.
This commit is contained in:
brent saner
2025-11-07 23:11:47 -05:00
parent 675a10addd
commit 803be548cf
16 changed files with 434 additions and 296 deletions

View File

@@ -1,10 +1,6 @@
package envs
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
@@ -14,7 +10,6 @@ import (
"r00t2.io/goutils/structutils"
"r00t2.io/sysutils/errs"
"r00t2.io/sysutils/internal"
"r00t2.io/sysutils/paths"
)
/*
@@ -34,7 +29,7 @@ func DefEnv(key, fallback string) (value string) {
return
}
// DefEnvBlank is like DefEnv but will ADDITIONALLY/ALSO apply fallback if key is *defined/exists but is an empty string*.
// DefEnvBlank is like [DefEnv] but will ADDITIONALLY/ALSO apply fallback if key is *defined/exists but is an empty string*.
func DefEnvBlank(key, fallback string) (value string) {
value = DefEnv(key, fallback)
@@ -45,7 +40,7 @@ func DefEnvBlank(key, fallback string) (value string) {
return
}
// GetEnvErr returns the value of key if it exists. If it does not exist, err will be an EnvErrNoVal.
// GetEnvErr returns the value of key if it exists. If it does not exist, err will be an [EnvErrNoVal].
func GetEnvErr(key string) (value string, err error) {
var exists bool
@@ -61,13 +56,13 @@ func GetEnvErr(key string) (value string, err error) {
}
/*
GetEnvErrNoBlank behaves exactly like GetEnvErr with the
GetEnvErrNoBlank behaves exactly like [GetEnvErr] with the
additional stipulation that the value must not be empty.
An error for a value that is non-empty but whitespace only (e.g. VARNM="\t")
can be returned if ignoreWhitespace == true.
(If it is, an EnvErrNoVal will also be returned.)
(If it is, an [EnvErrNoVal] will also be returned.)
*/
func GetEnvErrNoBlank(key string, ignoreWhitespace bool) (value string, err error) {
@@ -98,7 +93,7 @@ func GetEnvMap() (envVars map[string]string) {
var envList []string = os.Environ()
envVars = envListToMap(envList)
envVars = internal.EnvListToMap(envList)
return
}
@@ -108,20 +103,20 @@ GetEnvMapNative returns a map of all environment variables, but attempts to "nat
All values are interfaces. It is up to the caller to typeswitch them to proper types.
Note that the PATH/Path environment variable (for *Nix and Windows, respectively) will be
a []string (as per GetPathEnv). No other env vars, even if they contain os.PathListSeparator,
a []string (as per [GetPathEnv]). No other env vars, even if they contain [os.PathListSeparator],
will be transformed to a slice or the like.
If an error occurs during parsing the path env var, it will be rendered as a string.
All number types will attempt to be their 64-bit version (i.e. int64, uint64, float64, etc.).
If a type cannot be determined for a value, its string form will be used
(as it would be found in GetEnvMap).
(as it would be found in [GetEnvMap]).
*/
func GetEnvMapNative() (envMap map[string]interface{}) {
var stringMap map[string]string = GetEnvMap()
envMap = nativizeEnvMap(stringMap)
envMap = internal.NativizeEnvMap(stringMap)
return
}
@@ -144,7 +139,7 @@ If val is "" and ok is true, this means that one of the specified variable names
set but is set to an empty value. If ok is false, none of the specified variables
are set.
It is a thin wrapper around GetFirstWithRef.
It is a thin wrapper around [GetFirstWithRef].
*/
func GetFirst(varNames []string) (val string, ok bool) {
@@ -154,7 +149,7 @@ func GetFirst(varNames []string) (val string, ok bool) {
}
/*
GetFirstWithRef behaves exactly like GetFirst, but with an additional returned value, idx,
GetFirstWithRef behaves exactly like [GetFirst], but with an additional returned value, idx,
which specifies the index in varNames in which a set variable was found. e.g. if:
GetFirstWithRef([]string{"FOO", "FOOBAR", "FOOBAZ"})
@@ -182,16 +177,10 @@ func GetFirstWithRef(varNames []string) (val string, ok bool, idx int) {
// GetPathEnv returns a slice of the PATH variable's items.
func GetPathEnv() (pathList []string, err error) {
var pathVar string = internal.GetPathEnvName()
pathList = make([]string, 0)
for _, p := range strings.Split(os.Getenv(pathVar), string(os.PathListSeparator)) {
if err = paths.RealPath(&p); err != nil {
return
}
pathList = append(pathList, p)
if pathList, err = internal.GetPathEnv(); err != nil {
return
}
return
}
@@ -201,60 +190,34 @@ It gets the environment variables of a given process' PID.
*/
func GetPidEnvMap(pid uint32) (envMap map[string]string, err error) {
var envBytes []byte
var envList []string
var envArr [][]byte
var procPath string
var exists bool
envMap = make(map[string]string)
procPath = fmt.Sprintf("/proc/%v/environ", pid)
if exists, err = paths.RealPathExists(&procPath); err != nil {
if envMap, err = internal.GetPidEnvMap(pid); err != nil {
return
}
if !exists {
err = errors.New(fmt.Sprintf("information for pid %v does not exist", pid))
return
}
if envBytes, err = ioutil.ReadFile(procPath); err != nil {
return
}
envArr = bytes.Split(envBytes, []byte{0x0})
envList = make([]string, len(envArr))
for idx, b := range envArr {
envList[idx] = string(b)
}
envMap = envListToMap(envList)
return
}
/*
GetPidEnvMapNative, like GetEnvMapNative, returns a map of all environment variables, but attempts to "nativize" them.
GetPidEnvMapNative returns a map of all environment variables (like [GetEnvMapNative]), but attempts to "nativize" them.
All values are interfaces. It is up to the caller to typeswitch them to proper types.
See the documentation for GetEnvMapNative for details.
See the documentation for [GetEnvMapNative] for details.
*/
func GetPidEnvMapNative(pid uint32) (envMap map[string]interface{}, err error) {
var stringMap map[string]string
if stringMap, err = GetPidEnvMap(pid); err != nil {
if stringMap, err = internal.GetPidEnvMap(pid); err != nil {
return
}
envMap = nativizeEnvMap(stringMap)
envMap = internal.NativizeEnvMap(stringMap)
return
}
/*
HasEnv is much like os.LookupEnv, but only returns a boolean for
HasEnv is much like [os.LookupEnv], but only returns a boolean indicating
if the environment variable key exists or not.
This is useful anywhere you may need to set a boolean in a func call
@@ -280,7 +243,7 @@ and performs variable substitution on strings from environment variables.
It supports both UNIX/Linux/POSIX syntax formats (e.g. $VARNAME, ${VARNAME}) and,
if on Windows, it *additionally* supports the EXPAND_SZ format (e.g. %VARNAME%).
For structs, the tag name used can be changed by setting the StructTagInterpolate
For structs, the tag name used can be changed by setting the [StructTagInterpolate]
variable in this submodule; the default is `envsub`.
If the tag value is "-", the field will be skipped.
For map fields within structs etc., the default is to apply interpolation to both keys and values.
@@ -347,9 +310,9 @@ from environment variables.
It supports both UNIX/Linux/POSIX syntax formats (e.g. $VARNAME, ${VARNAME}) and,
if on Windows, it *additionally* supports the EXPAND_SZ format (e.g. %VARNAME%).
If s is nil, nothing will be done and err will be ErrNilPtr.
If s is nil, nothing will be done and err will be [errs.ErrNilPtr].
This is a standalone function that is much more performant than Interpolate
This is a standalone function that is much more performant than [Interpolate]
at the cost of rigidity.
*/
func InterpolateString(s *string) (err error) {
@@ -369,7 +332,7 @@ func InterpolateString(s *string) (err error) {
return
}
// interpolateMap is used by Interpolate for maps. v should be a reflect.Value of a map.
// interpolateMap is used by [Interpolate] for maps. v should be a [reflect.Value] of a map.
func interpolateMap(v reflect.Value) (err error) {
var kVal reflect.Value
@@ -467,7 +430,7 @@ func interpolateMap(v reflect.Value) (err error) {
return
}
// interpolateSlice is used by Interpolate for slices and arrays. v should be a reflect.Value of a slice/array.
// interpolateSlice is used by [Interpolate] for slices and arrays. v should be a [reflect.Value] of a slice/array.
func interpolateSlice(v reflect.Value) (err error) {
var wg sync.WaitGroup
@@ -558,7 +521,7 @@ func interpolateStringReflect(v reflect.Value) (err error) {
return
}
// interpolateStruct is used by Interpolate for structs. v should be a reflect.Value of a struct.
// interpolateStruct is used by [Interpolate] for structs. v should be a [reflect.Value] of a struct.
func interpolateStruct(v reflect.Value) (err error) {
var field reflect.StructField