diff --git a/paths/funcs.go b/paths/funcs.go index 049f99d..1e588e7 100644 --- a/paths/funcs.go +++ b/paths/funcs.go @@ -19,22 +19,23 @@ package paths import ( - `context` + "context" "errors" "fmt" "io/fs" "os" "os/user" + "path" "path/filepath" - `sort` + "sort" "strings" - `sync` - `time` + "sync" + "time" // "syscall" - `github.com/djherbis/times` - `r00t2.io/goutils/bitmask` + "github.com/djherbis/times" + "r00t2.io/goutils/bitmask" ) /* @@ -91,21 +92,21 @@ func ExpandHome(path *string) (err error) { } /* - GetFirst is the file equivalent of envs.GetFirst. +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). +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. +If no path exists, ok will be false. - As always, results are not guaranteed due to permissions, etc. - potentially returning an inaccurate result. +As always, results are not guaranteed due to permissions, etc. +potentially returning an inaccurate result. - This is a thin wrapper around GetFirstWithRef. +This is a thin wrapper around GetFirstWithRef. */ func GetFirst(paths []string) (content []byte, isDir, ok bool) { @@ -115,13 +116,13 @@ func GetFirst(paths []string) (content []byte, isDir, ok bool) { } /* - GetFirstWithRef is the file equivalent of envs.GetFirstWithRef. +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. +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. +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) { @@ -221,6 +222,68 @@ func RealPath(path *string) (err error) { return } +/* +RealPathJoin combines RealPath with (path).Join. + +If dst is nil, then rootPath will be updated with the new value. +You probably don't want that. +*/ +func RealPathJoin(rootPath, dst *string, subPaths ...string) (err error) { + + var newPath string + var realDst *string + + if err = RealPath(rootPath); err != nil { + return + } + + if dst == nil { + realDst = rootPath + } else { + realDst = dst + } + + newPath = path.Join(append([]string{*rootPath}, subPaths...)...) + if err = RealPath(&newPath); err != nil { + return + } + + *realDst = newPath + + return +} + +/* +RealPathJoinSys combines RealPath with (path/filepath).Join. + +If dst is nil, then path will be updated with the new value. +You probably don't want that. +*/ +func RealPathJoinSys(path, dst *string, subPaths ...string) (err error) { + + var newPath string + var realDst *string + + if err = RealPath(path); err != nil { + return + } + + if dst == nil { + realDst = path + } else { + realDst = dst + } + + newPath = filepath.Join(append([]string{*path}, subPaths...)...) + if err = RealPath(&newPath); err != nil { + return + } + + *realDst = newPath + + return +} + /* RealPathExists is like RealPath, but will also return a boolean as to whether the path actually exists or not. @@ -327,14 +390,14 @@ func SearchFsPaths(matcher FsSearchCriteria) (found, miss []*FsSearchResult, err } /* - SearchFsPathsAsync is exactly like SearchFsPaths, but dispatches off concurrent - workers for the filtering logic instead of performing iteratively/recursively. - It may, in some cases, be *slightly more* performant and *slightly less* in others. - Note that unlike SearchFsPaths, the results written to the - FsSearchCriteriaAsync.ResChan are not guaranteed to be in any predictable order. +SearchFsPathsAsync is exactly like SearchFsPaths, but dispatches off concurrent +workers for the filtering logic instead of performing iteratively/recursively. +It may, in some cases, be *slightly more* performant and *slightly less* in others. +Note that unlike SearchFsPaths, the results written to the +FsSearchCriteriaAsync.ResChan are not guaranteed to be in any predictable order. - All channels are expected to have already been initialized by the caller. - They will not be closed by this function. +All channels are expected to have already been initialized by the caller. +They will not be closed by this function. */ func SearchFsPathsAsync(matcher FsSearchCriteriaAsync) { @@ -436,11 +499,11 @@ func SearchFsPathsAsync(matcher FsSearchCriteriaAsync) { } /* - filterTimes checks a times.Timespec of a file using: - * an age specified by the caller - * an ageType bitmask for types of times to compare - * an olderThan bool (if false, the file must be younger than) - * an optional "now" timestamp for the age derivation. +filterTimes checks a times.Timespec of a file using: + - an age specified by the caller + - an ageType bitmask for types of times to compare + - an olderThan bool (if false, the file must be younger than) + - an optional "now" timestamp for the age derivation. */ func filterTimes(tspec times.Timespec, age *time.Duration, ageType *pathTimeType, olderThan bool, now *time.Time) (include bool) {