what a rabbithole. lots of goodies now.

This commit is contained in:
2021-12-18 04:23:35 -05:00
parent 11b0744e5c
commit 8f582d37f1
24 changed files with 399 additions and 326 deletions

60
envs/.TODO.go.UNFINISHED Normal file
View File

@@ -0,0 +1,60 @@
package envs
/*
EnvMapper contains the environment variables as grouped by their basic type.
If a variable's type cannot be determined, it's placed in Strings.
If a variable's type is a list, it will be an []interface{} as each item may be a different variable type.
It essentially is the same as EnvMap except with the types split out for convenience.
*/
type EnvMapper struct {
Booleans map[string]bool `json:"bools"`
Numbers map[string]int `json:"nums"`
Strings map[string]string `json:"strings"`
Lists map[string][]interface{} `json:"lists"`
}
// GetEnvMapper returns a pointer to a populated EnvMapper.
func GetEnvMapper() (e *EnvMapper, err error) {
var em map[string]interface{}
var env EnvMapper
env = EnvMapper{
Booleans: nil,
Numbers: nil,
Strings: nil,
Lists: nil,
}
for k, v := range em {
switch t := v.(type) {
case bool:
if env.Booleans == nil {
env.Booleans = make(map[string]bool, 0)
}
env.Booleans[k] = t
continue
case int:
if env.Numbers == nil {
env.Numbers = make(map[string]int, 0)
}
env.Numbers[k] = t
continue
case []interface{}:
if env.Lists == nil {
env.Lists = make(map[string][]interface{}, 0)
}
env.Lists[k] = t
case string: // the "default" since everything could probably be typeswitched to a string otherwise.
if env.Strings == nil {
env.Strings = make(map[string]string, 0)
}
env.Strings[k] = t
}
}
*e = env
return
}

11
envs/consts.go Normal file
View File

@@ -0,0 +1,11 @@
package envs
import (
`regexp`
)
// Compiled regex patterns.
var (
reMaybeInt *regexp.Regexp = regexp.MustCompilePOSIX(`^(?P<sign>\+|-)[0-9]+$`)
reMaybeFloat *regexp.Regexp = regexp.MustCompilePOSIX(`(?P<sign>\+|-)?[0-9]+\.[0-9]+$`)
)

120
envs/funcs.go Normal file
View File

@@ -0,0 +1,120 @@
package envs
import (
`bytes`
`errors`
`fmt`
`io/ioutil`
`os`
`strings`
`r00t2.io/sysutils/internal`
`r00t2.io/sysutils/paths`
)
// 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)
}
return
}
// GetEnvMap returns a map of all environment variables. All values are strings.
func GetEnvMap() (envVars map[string]string) {
var envList []string = os.Environ()
envVars = envListToMap(envList)
return
}
/*
GetEnvMapNative returns a map of all environment variables, but attempts to "nativize" them.
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,
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).
*/
func GetEnvMapNative() (envMap map[string]interface{}) {
var stringMap map[string]string = GetEnvMap()
envMap = nativizeEnvMap(stringMap)
return
}
/*
GetPidEnvMap will only work on *NIX-like systems with procfs.
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, 0)
procPath = fmt.Sprintf("/proc/%v/environ", pid)
if exists, err = paths.RealPathExists(&procPath); 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.
All values are interfaces. It is up to the caller to typeswitch them to proper types.
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 {
return
}
envMap = nativizeEnvMap(stringMap)
return
}

85
envs/utils.go Normal file
View File

@@ -0,0 +1,85 @@
package envs
import (
`strconv`
`strings`
`r00t2.io/sysutils/internal`
)
// envListToMap splits a []string of env var keypairs to a map.
func envListToMap(envs []string) (envMap map[string]string) {
var kv []string
var k, v string
envMap = make(map[string]string, 0)
for _, ev := range envs {
kv = strings.SplitAfterN(ev, "=", 2)
// I *think* SplitAfterN does this for me, but...
if len(kv) == 1 {
kv = append(kv, "")
}
k = kv[0]
v = kv[1]
envMap[k] = v
}
return
}
// nativizeEnvMap returns a native-typed env map from a string version.
func nativizeEnvMap(stringMap map[string]string) (envMap map[string]interface{}) {
var pathVar string = internal.GetPathEnvName()
var err error
for k, v := range stringMap {
// Check for PATH/Path - we handle this uniquely.
if k == pathVar {
if envMap[k], err = GetPathEnv(); err != nil {
envMap[k] = v
err = nil
}
continue
}
// It might be...
// a float
if reMaybeFloat.MatchString(v) {
if envMap[k], err = strconv.ParseFloat(v, 64); err == nil {
continue
}
err = nil
}
// an int
if reMaybeInt.MatchString(v) {
if envMap[k], err = strconv.Atoi(v); err == nil {
continue
}
err = nil
}
// a uint
if envMap[k], err = strconv.ParseUint(v, 10, 64); err == nil {
continue
} else {
err = nil
}
// a boolean
if envMap[k], err = strconv.ParseBool(v); err == nil {
continue
} else {
err = nil
}
// ok so... guess it's a string, then.
envMap[k] = v
}
return
}