Skip to content

Commit

Permalink
Merge pull request #20 from LandonTClipp/updates
Browse files Browse the repository at this point in the history
Adding query specifications
  • Loading branch information
LandonTClipp authored Sep 7, 2020
2 parents b275ba2 + 9dc0016 commit 1e22e38
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 29 deletions.
15 changes: 6 additions & 9 deletions path.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,13 +456,13 @@ func (p *Path) IsFile() (bool, error) {
if err != nil {
return false, err
}
return IsFile(fileInfo)
return IsFile(fileInfo), nil
}

// IsFile returns whether or not the file described by the given
// os.FileInfo is a regular file.
func IsFile(fileInfo os.FileInfo) (bool, error) {
return fileInfo.Mode().IsRegular(), nil
func IsFile(fileInfo os.FileInfo) bool {
return fileInfo.Mode().IsRegular()
}

// IsSymlink returns true if the given path is a symlink.
Expand All @@ -472,16 +472,13 @@ func (p *Path) IsSymlink() (bool, error) {
if err != nil {
return false, err
}
return IsSymlink(fileInfo)
return IsSymlink(fileInfo), nil
}

// IsSymlink returns true if the file described by the given
// os.FileInfo describes a symlink.
func IsSymlink(fileInfo os.FileInfo) (bool, error) {
if fileInfo.Mode()&os.ModeSymlink != 0 {
return true, nil
}
return false, nil
func IsSymlink(fileInfo os.FileInfo) bool {
return fileInfo.Mode()&os.ModeSymlink != 0
}

// Path returns the string representation of the path
Expand Down
112 changes: 93 additions & 19 deletions walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ type WalkOpts struct {
// to True. Here be dragons!
FollowSymlinks bool

// MinimumFileSize specifies the minimum size of a file for visitation.
// If negative, there is no minimum size.
MinimumFileSize int64

// MaximumFileSize specifies the maximum size of a file for visitation.
// If negative, there is no maximum size.
MaximumFileSize int64

// VisitFiles specifies that we should visit regular files during
// the walk.
VisitFiles bool

// VisitDirs specifies that we should visit directories during the walk.
VisitDirs bool

// VisitSymlinks specifies that we should visit symlinks during the walk.
VisitSymlinks bool

// VisitFirst specifies that, in the algorithms where it is appropriate,
// a node's contents should be visited first, before recursing down. If false,
// a node's subdirectories will be recursed first before visiting any of its
Expand All @@ -36,12 +54,33 @@ type WalkOpts struct {
// walking a directory.
func DefaultWalkOpts() *WalkOpts {
return &WalkOpts{
Depth: -1,
Algorithm: AlgorithmBasic,
FollowSymlinks: false,
Depth: -1,
Algorithm: AlgorithmBasic,
FollowSymlinks: false,
MinimumFileSize: -1,
MaximumFileSize: -1,
VisitFiles: true,
VisitDirs: true,
VisitSymlinks: true,
}
}

// MeetsMinimumSize returns whether size is at least the minimum specified.
func (w *WalkOpts) MeetsMinimumSize(size int64) bool {
if w.MinimumFileSize < 0 {
return true
}
return size >= w.MinimumFileSize
}

// MeetsMaximumSize returns whether size is less than or equal to the maximum specified.
func (w *WalkOpts) MeetsMaximumSize(size int64) bool {
if w.MaximumFileSize < 0 {
return true
}
return size <= w.MaximumFileSize
}

// Algorithm represents the walk algorithm that will be performed.
type Algorithm int

Expand Down Expand Up @@ -100,7 +139,7 @@ func (w *Walk) walkDFS(walkFn WalkFunc, root *Path, currentDepth int) error {
return nil
}

var nonDirectories []*dfsObjectInfo
var children []*dfsObjectInfo

if err := w.iterateImmediateChildren(root, func(child *Path, info os.FileInfo, encounteredErr error) error {
// Since we are doing depth-first, we have to first recurse through all the directories,
Expand All @@ -109,26 +148,32 @@ func (w *Walk) walkDFS(walkFn WalkFunc, root *Path, currentDepth int) error {
if err := w.walkDFS(walkFn, child, currentDepth+1); err != nil {
return err
}
if err := walkFn(child, info, encounteredErr); err != nil {
return err
}
} else {
nonDirectories = append(nonDirectories, &dfsObjectInfo{
path: child,
info: info,
err: encounteredErr,
})
}

children = append(children, &dfsObjectInfo{
path: child,
info: info,
err: encounteredErr,
})

return nil
}); err != nil {
return err
}

// Iterate over all non-directory objects
for _, nonDir := range nonDirectories {
if err := walkFn(nonDir.path, nonDir.info, nonDir.err); err != nil {
// Iterate over all children after all subdirs have been recursed
for _, child := range children {
passesQuery, err := w.passesQuerySpecification(child.info)
if err != nil {
return err
}

if passesQuery {
if err := walkFn(child.path, child.info, child.err); err != nil {
return err
}
}

}
return nil
}
Expand All @@ -150,11 +195,10 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
}
if w.Opts.FollowSymlinks {
info, err = child.Stat()
isSymlink, err := IsSymlink(info)
if err != nil {
return err
}
if isSymlink {
if IsSymlink(info) {
child, err = child.ResolveAll()
if err != nil {
return err
Expand All @@ -179,6 +223,28 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
return nil
}

// passesQuerySpecification returns whether or not the object described by
// the os.FileInfo passes all of the query specifications listed in
// the walk options.
func (w *Walk) passesQuerySpecification(info os.FileInfo) (bool, error) {
if IsFile(info) {
if !w.Opts.VisitFiles {
return false, nil
}

if !w.Opts.MeetsMinimumSize(info.Size()) ||
!w.Opts.MeetsMaximumSize(info.Size()) {
return false, nil
}
} else if IsDir(info) && !w.Opts.VisitDirs {
return false, nil
} else if IsSymlink(info) && !w.Opts.VisitSymlinks {
return false, nil
}

return true, nil
}

func (w *Walk) walkBasic(walkFn WalkFunc, root *Path, currentDepth int) error {
if w.maxDepthReached(currentDepth) {
return nil
Expand All @@ -191,9 +257,17 @@ func (w *Walk) walkBasic(walkFn WalkFunc, root *Path, currentDepth int) error {
}
}

if err := walkFn(child, info, encounteredErr); err != nil {
passesQuery, err := w.passesQuerySpecification(info)
if err != nil {
return err
}

if passesQuery {
if err := walkFn(child, info, encounteredErr); err != nil {
return err
}
}

return nil
})

Expand Down
11 changes: 10 additions & 1 deletion walk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,16 @@ func TestDefaultWalkOpts(t *testing.T) {
name string
want *WalkOpts
}{
{"assert defaults", &WalkOpts{-1, AlgorithmBasic, false}},
{"assert defaults", &WalkOpts{
Depth: -1,
Algorithm: AlgorithmBasic,
FollowSymlinks: false,
MinimumFileSize: -1,
MaximumFileSize: -1,
VisitFiles: true,
VisitDirs: true,
VisitSymlinks: true,
}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit 1e22e38

Please sign in to comment.