2024-11-12 06:32:04 -05:00
|
|
|
package paths
|
|
|
|
|
|
|
|
import (
|
2024-11-18 17:36:14 -05:00
|
|
|
`context`
|
|
|
|
`io/fs`
|
|
|
|
`regexp`
|
|
|
|
`sync`
|
|
|
|
`time`
|
|
|
|
|
|
|
|
`github.com/djherbis/times`
|
|
|
|
`golang.org/x/sync/semaphore`
|
2024-11-12 06:32:04 -05:00
|
|
|
`r00t2.io/goutils/bitmask`
|
|
|
|
)
|
|
|
|
|
2024-11-18 17:36:14 -05:00
|
|
|
// FsSearchCriteria contains filter criteria for SearchFsPaths* functions.
|
|
|
|
type FsSearchCriteria struct {
|
|
|
|
// Root indicates the root to search.
|
|
|
|
Root string `json:"root" toml:"RootPath" yaml:"Root Path" xml:"root,attr" validate:"dir"`
|
|
|
|
// NoMatch, if true, will not return matches. If NoMatch and NoMismatch are both true, no results will be returned.
|
|
|
|
NoMatch bool `json:"no_match" toml:"NoMatch" yaml:"No Matches" xml:"noMatch,attr"`
|
|
|
|
// NoMismatch, if true, will not return mismatches. If NoMatch and NoMismatch are both true, no results will be returned.
|
|
|
|
NoMismatch bool `json:"no_miss" toml:"NoMismatch" yaml:"No Mismatches" xml:"noMiss,attr"`
|
|
|
|
/*
|
|
|
|
TargetType defines what types of filesystem objects should be matched.
|
|
|
|
It can consist of one or more (io/)fs.FileMode types OR'd together
|
|
|
|
(ensure they are part of (io/)fs.ModeType).
|
|
|
|
(You can use 0 to match regular files explicitly, and/or NoFiles = true to exclude them.)
|
|
|
|
*/
|
|
|
|
TargetType fs.FileMode `json:"type_tgt" toml:"TargetType" yaml:"Target Type" xml:"typeTgt,attr"`
|
|
|
|
// NoFiles excludes files from TargetType-matching (as there isn't a way to explicitly exclude files otherwise if a non-zero mode is given).
|
|
|
|
NoFiles bool `json:"no_file" toml:"ExcludeFiles" yaml:"Exclude Files" xml:"noFile,attr"`
|
|
|
|
// FollowSymlinks, if true and a path being tested is a symlink, will use metadata (age, etc.) of the symlink itself rather than the link target.
|
|
|
|
FollowSymlinks bool `json:"follow_sym" toml:"FollowSymlinks" yaml:"Follow Symlinks" xml:"followSym,attr"`
|
|
|
|
// BasePtrn, if specified, will apply to the *base name (that is, quux.txt rather than /foo/bar/baz/quux.txt). See also PathPtrn.
|
|
|
|
BasePtrn *regexp.Regexp `json:"ptrn_base,omitempty" toml:"BaseNamePattern,omitempty" yaml:"Base Name Pattern,omitempty" xml:"ptrnBase,attr,omitempty"`
|
|
|
|
// PathPtrn, if specified, will apply to the *full path* (e.g. /foo/bar/baz/quux.txt, not just quux.txt). See also BasePtrn.
|
|
|
|
PathPtrn *regexp.Regexp `json:"ptrn_path,omitempty" toml:"PathPattern,omitempty" yaml:"Path Pattern,omitempty" xml:"ptrnPath,attr,omitempty"`
|
|
|
|
/*
|
|
|
|
Age, if specified, indicates the comparison of Now againt the AgeType of filesystem objects.
|
|
|
|
Use OlderThan to indicate if it should be older or newer.
|
|
|
|
*/
|
|
|
|
Age *time.Duration `json:"age,omitempty" toml:"Age,omitempty" yaml:"Age,omitempty" xml:"age,attr,omitempty"`
|
|
|
|
/*
|
|
|
|
AgeType can be one (or more, OR'd together) of the Time* constants in this package (TimeAny, TimeAccessed, TimeCreated,
|
|
|
|
TimeChanged, TimeModified) to indicate what timestamp(s) to use for comparing Age.
|
|
|
|
|
|
|
|
The zero-value is TimeAny.
|
|
|
|
|
|
|
|
The first matching timestamp will pass all time comparisons.
|
|
|
|
Be mindful of timestamp type support/limitations per OS/filesystem of Root.
|
|
|
|
|
|
|
|
Completely unused if Age is nil.
|
|
|
|
*/
|
|
|
|
AgeType pathTimeType `json:"type_age" toml:"AgeType" yaml:"Age Type" xml:"typeAge,attr"`
|
|
|
|
/*
|
|
|
|
OlderThan, if true (and Age is not nil), indicates that matching filesystem objects should have their
|
|
|
|
AgeType older than Now. If false, their AgeType should be *newer* than Now.
|
|
|
|
|
|
|
|
Completely unused if Age is nil.
|
|
|
|
*/
|
|
|
|
OlderThan bool `json:"older" toml:"OlderThan" yaml:"Older Than" xml:"older,attr"`
|
|
|
|
/*
|
|
|
|
Now expresses a time to compare to Age via AgeType and OlderThan.
|
|
|
|
Note that it may be any valid time, not necessarily "now".
|
|
|
|
If Age is specified but Now is nil, it will be populated with time.Now() when the search is invoked.
|
|
|
|
|
|
|
|
Completely unused if Age is nil.
|
|
|
|
*/
|
|
|
|
Now *time.Time `json:"now,omitempty" toml:"Now,omitempty" yaml:"Now,omitempty" xml:"now,attr,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// FsSearchCriteriaAsync extends FsSearchCriteria for use in an asynchronous (goroutine) manner.
|
|
|
|
type FsSearchCriteriaAsync struct {
|
|
|
|
FsSearchCriteria
|
|
|
|
/*
|
|
|
|
WG should be a non-nil pointer to a sync.WaitGroup.
|
|
|
|
This is used to manage searching completion to the caller.
|
|
|
|
|
|
|
|
.Done() will be called once within the search function, but no .Add() will be called;
|
|
|
|
.Add() should be done by the caller beforehand.
|
|
|
|
*/
|
|
|
|
WG *sync.WaitGroup
|
|
|
|
// ResChan must be a non-nil channel for (positive) match results to be sent to.
|
|
|
|
ResChan chan *FsSearchResult
|
|
|
|
// MismatchChan, if not nil, will have negative matches/"misses" sent to it.
|
|
|
|
MismatchChan chan *FsSearchResult
|
|
|
|
/*
|
|
|
|
ErrChan should be a non-nil error channel for any unexpected errors encountered.
|
|
|
|
|
|
|
|
If nil, a panic will be raised.
|
|
|
|
*/
|
|
|
|
ErrChan chan error
|
|
|
|
/*
|
|
|
|
Semaphore is completely optional, but if non-nil
|
|
|
|
it will be used to limit concurrent filesystem
|
|
|
|
object processing.
|
|
|
|
|
|
|
|
It is generally a Very Good Idea(TM) to use this,
|
|
|
|
as the default is to dispatch all processing concurrently.
|
|
|
|
This can lead to some heavy I/O and CPU wait.
|
|
|
|
|
|
|
|
(See https://pkg.go.dev/golang.org/x/sync/semaphore for details.)
|
|
|
|
*/
|
|
|
|
Semaphore *semaphore.Weighted
|
|
|
|
/*
|
|
|
|
SemaphoreCtx is the context.Context to use for Semaphore.
|
|
|
|
If nil (but Sempaphore is not), one will be created locally/internally.
|
|
|
|
*/
|
|
|
|
SemaphoreCtx context.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
// FsSearchResult contains a match/miss result for FsSearchCriteria and FsSearchCriteriaAsync.
|
|
|
|
type FsSearchResult struct {
|
|
|
|
/*
|
|
|
|
Path is the path to the object on the filesystem.
|
|
|
|
It may or may not exist at the time of return,
|
|
|
|
but will not be an empty string.
|
|
|
|
*/
|
|
|
|
Path string `json:"path" toml:"Path" yaml:"Path" xml:"path,attr"`
|
|
|
|
// DirEntry is the fs.DirEntry for the Path; note that .Name() is the base name only. TODO: serialization?
|
|
|
|
DirEntry fs.DirEntry `json:"-" toml:"-" yaml:"-" xml:"-"`
|
|
|
|
// FileInfo is the fs.FileInfo for the Path; note that .Name() is the base name only. TODO: serialization?
|
|
|
|
FileInfo fs.FileInfo `json:"-" toml:"-" yaml:"-" xml:"-"`
|
|
|
|
// Criteria is the evaluated criteria specified that this FsSearchResult matched.
|
|
|
|
Criteria *FsSearchCriteria `json:"criteria" toml:"Criteria" yaml:"Criteria" xml:"criteria"`
|
|
|
|
// Times holds the mtime, ctime, etc. of the filesystem object (where supported). TODO: serialization?
|
|
|
|
Times times.Timespec `json:"-" toml:"-" yaml:"-" xml:"-"`
|
|
|
|
// MissReason contains the reason the result is a miss (MissNoMiss if a match); see the Miss* constants.
|
|
|
|
MissReason missReason `json:"miss_reason" toml:"MissReason" yaml:"Miss Reason" xml:"miss,attr"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type missReason string
|
|
|
|
|
2024-11-12 06:32:04 -05:00
|
|
|
type pathMode bitmask.MaskBit
|
|
|
|
|
|
|
|
type pathTimeType bitmask.MaskBit
|