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
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) {