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

View File

@@ -21,23 +21,25 @@ package paths
import (
"errors"
`fmt`
`io/fs`
"os"
"os/user"
"path/filepath"
`runtime`
// "strconv"
"strings"
`strings`
// "syscall"
)
/*
ExpandHome will take a tilde(~)-prefixed path and resolve it to the actual path in-place.
Note that it only works for current user; the syntax ~someotheruser/foo/bar is currently unsupported.
"Nested" user paths (~someuser/somechroot/~someotheruser) are not supported as home directories are expected to be absolute paths.
*/
func ExpandHome(path *string) (err error) {
var usr *user.User
var unameSplit []string
var uname string
var u *user.User
// Props to this guy.
// https://stackoverflow.com/a/43578461/733214
@@ -51,40 +53,41 @@ func ExpandHome(path *string) (err error) {
// E(ffective)UID (e.g. chown'd user for SUID)
/*
uid := strconv.Itoa(syscall.Geteuid())
usr, err := user.LookupId(euid)
u, err := user.LookupId(euid)
*/
// (Real)UID (invoking user)
if usr, err = user.Current(); err != nil {
return err
}
*path = filepath.Join(usr.HomeDir, (*path)[1:])
return
}
// GetPathEnv returns a slice of the PATH variable's items.
func GetPathEnv() (paths []string, err error) {
var pathVar string = "PATH"
var sep string = ":"
paths = make([]string, 0)
if runtime.GOOS == "windows" {
pathVar = "Path"
sep = ";"
}
for _, p := range strings.Split(os.Getenv(pathVar), sep) {
if err = RealPath(&p); err != nil {
/*
if u, err = user.Current(); err != nil {
return
}
paths = append(paths, p)
*/
// K but do it smarter.
unameSplit = strings.SplitAfterN(*path, string(os.PathSeparator), 2)
if len(unameSplit) != 2 {
unameSplit = append(unameSplit, "")
}
uname = strings.TrimPrefix(unameSplit[0], "~")
if uname == "" {
if u, err = user.Current(); err != nil {
return
}
} else {
if u, err = user.Lookup(uname); err != nil {
return
}
}
*path = filepath.Join(u.HomeDir, unameSplit[1])
return
}
// MakeDirIfNotExist will create a directory at a given path if it doesn't exist.
/*
MakeDirIfNotExist will create a directory at a given path if it doesn't exist.
See also the documentation for RealPath.
*/
func MakeDirIfNotExist(path string) (err error) {
var stat os.FileInfo
@@ -117,7 +120,14 @@ func MakeDirIfNotExist(path string) (err error) {
return
}
// 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
path syntax/string itself is not supported on the runtime OS. This can be done via:
if errors.Is(err, fs.ErrInvalid) {...}
*/
func RealPath(path *string) (err error) {
if err = ExpandHome(path); err != nil {
@@ -135,18 +145,28 @@ func RealPath(path *string) (err error) {
RealPathExists is like RealPath, but will also return a boolean as to whether the path
actually exists or not.
It's hacky, but the "exists" bool along with err is a sort of proto-state-machine.
If err != nil and bool is true, the error occurred during path absolution.
If err != nil and bool is false, the path does not exist.
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
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
via:
if errors.Is(err, fs.ErrPermission) {...}
See also the documentation for RealPath.
In those cases, it may be preferable to use RealPathExistsStat and checking stat for nil.
*/
func RealPathExists(path *string) (exists bool, err error) {
if err = RealPath(path); err != nil {
exists = true
return
}
if _, err = os.Stat(*path); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
err = nil
}
return
}
@@ -155,12 +175,16 @@ func RealPathExists(path *string) (exists bool, err error) {
return
}
// RealPathExistsStat is like RealPathExists except it will also return the os.FileInfo for the path (assuming it exists).
/*
RealPathExistsStat is like RealPathExists except it will also return the os.FileInfo
for the path (assuming it exists).
If stat is nil, it is highly recommended to check err via the methods suggested
in the documentation for RealPath and RealPathExists.
*/
func RealPathExistsStat(path *string) (exists bool, stat os.FileInfo, err error) {
// See the comments for RealPathExists for details on this.
if err = RealPath(path); err != nil {
exists = true
if exists, err = RealPathExists(path); err != nil {
return
}
@@ -168,7 +192,5 @@ func RealPathExistsStat(path *string) (exists bool, stat os.FileInfo, err error)
return
}
exists = true
return
}