ADDED:
* paths.RealPathJoin() and paths.RealPathJoinSys()
This commit is contained in:
brent saner 2025-07-09 16:24:41 -04:00
parent 772324247a
commit 82f58d4fbf
Signed by: bts
GPG Key ID: 8C004C2F93481F6B

View File

@ -19,22 +19,23 @@
package paths package paths
import ( import (
`context` "context"
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
"os/user" "os/user"
"path"
"path/filepath" "path/filepath"
`sort` "sort"
"strings" "strings"
`sync` "sync"
`time` "time"
// "syscall" // "syscall"
`github.com/djherbis/times` "github.com/djherbis/times"
`r00t2.io/goutils/bitmask` "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 It iterates through paths, normalizing them along the way
(so abstracted paths such as ~/foo/bar.txt and relative paths (so abstracted paths such as ~/foo/bar.txt and relative paths
such as bar/baz.txt will still work), and returns the content such as bar/baz.txt will still work), and returns the content
of the first found existing file. If the first found path of the first found existing file. If the first found path
is a directory, content will be nil but isDir will be true is a directory, content will be nil but isDir will be true
(as will ok). (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. As always, results are not guaranteed due to permissions, etc.
potentially returning an inaccurate result. 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) { 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, It behaves exactly like GetFirst, but with an additional returned value, idx,
which specifies the index in paths in which a path was found. which specifies the index in paths in which a path was found.
As always, results are not guaranteed due to permissions, etc. As always, results are not guaranteed due to permissions, etc.
potentially returning an inaccurate result. potentially returning an inaccurate result.
*/ */
func GetFirstWithRef(paths []string) (content []byte, isDir, ok bool, idx int) { func GetFirstWithRef(paths []string) (content []byte, isDir, ok bool, idx int) {
@ -221,6 +222,68 @@ func RealPath(path *string) (err error) {
return 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 RealPathExists is like RealPath, but will also return a boolean as to whether the path
actually exists or not. 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 SearchFsPathsAsync is exactly like SearchFsPaths, but dispatches off concurrent
workers for the filtering logic instead of performing iteratively/recursively. workers for the filtering logic instead of performing iteratively/recursively.
It may, in some cases, be *slightly more* performant and *slightly less* in others. It may, in some cases, be *slightly more* performant and *slightly less* in others.
Note that unlike SearchFsPaths, the results written to the Note that unlike SearchFsPaths, the results written to the
FsSearchCriteriaAsync.ResChan are not guaranteed to be in any predictable order. FsSearchCriteriaAsync.ResChan are not guaranteed to be in any predictable order.
All channels are expected to have already been initialized by the caller. All channels are expected to have already been initialized by the caller.
They will not be closed by this function. They will not be closed by this function.
*/ */
func SearchFsPathsAsync(matcher FsSearchCriteriaAsync) { func SearchFsPathsAsync(matcher FsSearchCriteriaAsync) {
@ -436,11 +499,11 @@ func SearchFsPathsAsync(matcher FsSearchCriteriaAsync) {
} }
/* /*
filterTimes checks a times.Timespec of a file using: filterTimes checks a times.Timespec of a file using:
* an age specified by the caller - an age specified by the caller
* an ageType bitmask for types of times to compare - an ageType bitmask for types of times to compare
* an olderThan bool (if false, the file must be younger than) - an olderThan bool (if false, the file must be younger than)
* an optional "now" timestamp for the age derivation. - 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) { func filterTimes(tspec times.Timespec, age *time.Duration, ageType *pathTimeType, olderThan bool, now *time.Time) (include bool) {