diff --git a/TODO b/TODO index eeca37f..79da0ee 100644 --- a/TODO +++ b/TODO @@ -2,12 +2,24 @@ -- incorporate with https://github.com/tredoe/osutil ? -- cli flag to dump flat hashes too --- https://github.com/hlandau/passlib +-- incoprporated separately; https://git.r00t2.io/r00t2/PWGen (import r00t2.io/pwgen) - unit tests - constants/vars for errors - func and struct to return segregated system-level env vars vs. user env vars (mostly usable on windows) (see envs/.TODO.go.UNFINISHED) +-- https://www3.ntu.edu.sg/home/ehchua/programming/howto/Environment_Variables.html +-- windows: +--- https://docs.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables +--- https://pureinfotech.com/list-environment-variables-windows-10/ +--- https://gist.github.com/RebeccaWhit3/5dad8627b8227142e1bea432db3f8824 +--- https://ss64.com/nt/syntax-variables.html +-- linux/XDG: +--- https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html +--- https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html +-- macOS: +--- https://ss64.com/osx/syntax-env_vars.html - validator for windows usernames, domains, etc. (for *NIX, https://unix.stackexchange.com/a/435120/284004) -- https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/naming-conventions-for-computer-domain-site-ou diff --git a/envs/funcs.go b/envs/funcs.go index 3bc32de..8bdeb58 100644 --- a/envs/funcs.go +++ b/envs/funcs.go @@ -61,6 +61,59 @@ func GetEnvMapNative() (envMap map[string]interface{}) { return } +/* + GetFirst gets the first instance if populated/set occurrence of varNames. + + For example, if you have three potential env vars, FOO, FOOBAR, FOOBARBAZ, + and want to follow the logic flow of: + + 1.) Check if FOO is set. If not, + 2.) Check if FOOBAR is set. If not, + 3.) Check if FOOBARBAZ is set. + + Then this would be specified as: + + GetFirst([]string{"FOO", "FOOBAR", "FOOBARBAZ"}) + + If val is "" and ok is true, this means that one of the specified variable names IS + 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. +*/ +func GetFirst(varNames []string) (val string, ok bool) { + + val, ok, _ = GetFirstWithRef(varNames) + + return +} + +/* + 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"}) + + is called and FOO is not set but FOOBAR is, idx will be 1. + + If ok is false, idx will always be -1 and should be ignored. +*/ +func GetFirstWithRef(varNames []string) (val string, ok bool, idx int) { + + idx = -1 + + for i, vn := range varNames { + if HasEnv(vn) { + ok = true + idx = i + val = os.Getenv(vn) + return + } + } + + return +} + /* GetPidEnvMap will only work on *NIX-like systems with procfs. It gets the environment variables of a given process' PID. diff --git a/paths/funcs.go b/paths/funcs.go index 57f4444..3857cf9 100644 --- a/paths/funcs.go +++ b/paths/funcs.go @@ -82,10 +82,81 @@ func ExpandHome(path *string) (err error) { return } +/* + GetFirst is the file equivalent of envs.GetFirst. + + It iterates through paths, normalizing them along the way + (so abstracted paths such as ~/foo/bar.txt and relative paths + such as bar/baz.txt will still work), and returns the content + of the first found existing file. If the first found path + is a directory, content will be nil but isDir will be true + (as will ok). + + If no path exists, ok will be false. + + As always, results are not guaranteed due to permissions, etc. + potentially returning an inaccurate result. + + This is a thin wrapper around GetFirstWithRef. +*/ +func GetFirst(paths []string) (content []byte, isDir, ok bool) { + + content, isDir, ok, _ = GetFirstWithRef(paths) + + return +} + +/* + GetFirstWithRef is the file equivalent of envs.GetFirstWithRef. + + It behaves exactly like GetFirst, but with an additional returned value, idx, + which specifies the index in paths in which a path was found. + + As always, results are not guaranteed due to permissions, etc. + potentially returning an inaccurate result. +*/ +func GetFirstWithRef(paths []string) (content []byte, isDir, ok bool, idx int) { + + var locPaths []string + var exists bool + var stat os.FileInfo + var err error + + idx = -1 + // We have to be a little less cavalier about this. + if paths == nil { + return + } + locPaths = make([]string, len(paths)) + locPaths = paths[:] // Create an explicit copy so we don't modify paths. + for i, p := range locPaths { + if exists, stat, err = RealPathExistsStat(&p); err != nil { + err = nil + continue + } + if !exists { + continue + } + isDir = stat.IsDir() + if !isDir { + if content, err = os.ReadFile(p); err != nil { + continue + } + } + ok = true + idx = i + return + } + + return +} + /* MakeDirIfNotExist will create a directory at a given path if it doesn't exist. See also the documentation for RealPath. + +This is a bit more sane option than os.MkdirAll as it will normalize paths a little better. */ func MakeDirIfNotExist(path string) (err error) {