2 Commits

Author SHA1 Message Date
8254fd21a3 features: envs.GetFirst{,WithRef}, paths.GetFirst{,WithRef} 2022-09-15 01:56:08 -04:00
2bf9323203 fixing false undefined error 2022-08-26 02:41:13 -04:00
3 changed files with 163 additions and 26 deletions

12
TODO
View File

@@ -2,12 +2,24 @@
-- incorporate with https://github.com/tredoe/osutil ? -- incorporate with https://github.com/tredoe/osutil ?
-- cli flag to dump flat hashes too -- cli flag to dump flat hashes too
--- https://github.com/hlandau/passlib --- https://github.com/hlandau/passlib
-- incoprporated separately; https://git.r00t2.io/r00t2/PWGen (import r00t2.io/pwgen)
- unit tests - unit tests
- constants/vars for errors - 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) - 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) - 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 -- https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/naming-conventions-for-computer-domain-site-ou

View File

@@ -61,6 +61,59 @@ func GetEnvMapNative() (envMap map[string]interface{}) {
return 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. GetPidEnvMap will only work on *NIX-like systems with procfs.
It gets the environment variables of a given process' PID. It gets the environment variables of a given process' PID.

View File

@@ -20,19 +20,18 @@ package paths
import ( import (
"errors" "errors"
`fmt` "fmt"
`io/fs` "io/fs"
"os" "os"
"os/user" "os/user"
"path/filepath" "path/filepath"
`strings` "strings"
// "syscall" // "syscall"
) )
/* /*
ExpandHome will take a tilde(~)-prefixed path and resolve it to the actual path in-place. ExpandHome will take a tilde(~)-prefixed path and resolve it to the actual path in-place.
"Nested" user paths (~someuser/somechroot/~someotheruser) are not supported as home directories are expected to be absolute paths. "Nested" user paths (~someuser/somechroot/~someotheruser) are not supported as home directories are expected to be absolute paths.
*/ */
func ExpandHome(path *string) (err error) { func ExpandHome(path *string) (err error) {
@@ -84,9 +83,80 @@ func ExpandHome(path *string) (err error) {
} }
/* /*
MakeDirIfNotExist will create a directory at a given path if it doesn't exist. GetFirst is the file equivalent of envs.GetFirst.
See also the documentation for RealPath. 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) { func MakeDirIfNotExist(path string) (err error) {
@@ -113,6 +183,8 @@ func MakeDirIfNotExist(path string) (err error) {
if !stat.Mode().IsDir() { if !stat.Mode().IsDir() {
err = errors.New(fmt.Sprintf("path %v exists but is not a directory", locPath)) err = errors.New(fmt.Sprintf("path %v exists but is not a directory", locPath))
return return
} else {
return
} }
// This should probably never happen. Probably. // This should probably never happen. Probably.
@@ -121,12 +193,12 @@ func MakeDirIfNotExist(path string) (err error) {
} }
/* /*
RealPath will transform a given path into the very best guess for an absolute path in-place. RealPath will transform a given path into the very best guess for an absolute path in-place.
It is recommended to check err (if not nil) for an invalid path error. If this is true, the It is recommended to check err (if not nil) for an invalid path error. If this is true, the
path syntax/string itself is not supported on the runtime OS. This can be done via: path syntax/string itself is not supported on the runtime OS. This can be done via:
if errors.Is(err, fs.ErrInvalid) {...} if errors.Is(err, fs.ErrInvalid) {...}
*/ */
func RealPath(path *string) (err error) { func RealPath(path *string) (err error) {
@@ -142,20 +214,20 @@ func RealPath(path *string) (err error) {
} }
/* /*
RealPathExists is like RealPath, but will also return a boolean as to whether the path RealPathExists is like RealPath, but will also return a boolean as to whether the path
actually exists or not. actually exists or not.
Note that err *may* be os.ErrPermission/fs.ErrPermission, in which case the exists value Note that err *may* be os.ErrPermission/fs.ErrPermission, in which case the exists value
cannot be trusted as a permission error occurred when trying to stat the path - if the cannot be trusted as a permission error occurred when trying to stat the path - if the
calling user/process does not have read permission on e.g. a parent directory, then calling user/process does not have read permission on e.g. a parent directory, then
exists may be false but the path may actually exist. This condition can be checked via exists may be false but the path may actually exist. This condition can be checked via
via: via:
if errors.Is(err, fs.ErrPermission) {...} if errors.Is(err, fs.ErrPermission) {...}
See also the documentation for RealPath. See also the documentation for RealPath.
In those cases, it may be preferable to use RealPathExistsStat and checking stat for nil. In those cases, it may be preferable to use RealPathExistsStat and checking stat for nil.
*/ */
func RealPathExists(path *string) (exists bool, err error) { func RealPathExists(path *string) (exists bool, err error) {
@@ -176,11 +248,11 @@ func RealPathExists(path *string) (exists bool, err error) {
} }
/* /*
RealPathExistsStat is like RealPathExists except it will also return the os.FileInfo RealPathExistsStat is like RealPathExists except it will also return the os.FileInfo
for the path (assuming it exists). for the path (assuming it exists).
If stat is nil, it is highly recommended to check err via the methods suggested If stat is nil, it is highly recommended to check err via the methods suggested
in the documentation for RealPath and RealPathExists. in the documentation for RealPath and RealPathExists.
*/ */
func RealPathExistsStat(path *string) (exists bool, stat os.FileInfo, err error) { func RealPathExistsStat(path *string) (exists bool, stat os.FileInfo, err error) {