Skip to content

Commit 1e22e38

Browse files
authored
Merge pull request #20 from LandonTClipp/updates
Adding query specifications
2 parents b275ba2 + 9dc0016 commit 1e22e38

File tree

3 files changed

+109
-29
lines changed

3 files changed

+109
-29
lines changed

path.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,13 @@ func (p *Path) IsFile() (bool, error) {
456456
if err != nil {
457457
return false, err
458458
}
459-
return IsFile(fileInfo)
459+
return IsFile(fileInfo), nil
460460
}
461461

462462
// IsFile returns whether or not the file described by the given
463463
// os.FileInfo is a regular file.
464-
func IsFile(fileInfo os.FileInfo) (bool, error) {
465-
return fileInfo.Mode().IsRegular(), nil
464+
func IsFile(fileInfo os.FileInfo) bool {
465+
return fileInfo.Mode().IsRegular()
466466
}
467467

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

478478
// IsSymlink returns true if the file described by the given
479479
// os.FileInfo describes a symlink.
480-
func IsSymlink(fileInfo os.FileInfo) (bool, error) {
481-
if fileInfo.Mode()&os.ModeSymlink != 0 {
482-
return true, nil
483-
}
484-
return false, nil
480+
func IsSymlink(fileInfo os.FileInfo) bool {
481+
return fileInfo.Mode()&os.ModeSymlink != 0
485482
}
486483

487484
// Path returns the string representation of the path

walk.go

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ type WalkOpts struct {
2222
// to True. Here be dragons!
2323
FollowSymlinks bool
2424

25+
// MinimumFileSize specifies the minimum size of a file for visitation.
26+
// If negative, there is no minimum size.
27+
MinimumFileSize int64
28+
29+
// MaximumFileSize specifies the maximum size of a file for visitation.
30+
// If negative, there is no maximum size.
31+
MaximumFileSize int64
32+
33+
// VisitFiles specifies that we should visit regular files during
34+
// the walk.
35+
VisitFiles bool
36+
37+
// VisitDirs specifies that we should visit directories during the walk.
38+
VisitDirs bool
39+
40+
// VisitSymlinks specifies that we should visit symlinks during the walk.
41+
VisitSymlinks bool
42+
2543
// VisitFirst specifies that, in the algorithms where it is appropriate,
2644
// a node's contents should be visited first, before recursing down. If false,
2745
// a node's subdirectories will be recursed first before visiting any of its
@@ -36,12 +54,33 @@ type WalkOpts struct {
3654
// walking a directory.
3755
func DefaultWalkOpts() *WalkOpts {
3856
return &WalkOpts{
39-
Depth: -1,
40-
Algorithm: AlgorithmBasic,
41-
FollowSymlinks: false,
57+
Depth: -1,
58+
Algorithm: AlgorithmBasic,
59+
FollowSymlinks: false,
60+
MinimumFileSize: -1,
61+
MaximumFileSize: -1,
62+
VisitFiles: true,
63+
VisitDirs: true,
64+
VisitSymlinks: true,
4265
}
4366
}
4467

68+
// MeetsMinimumSize returns whether size is at least the minimum specified.
69+
func (w *WalkOpts) MeetsMinimumSize(size int64) bool {
70+
if w.MinimumFileSize < 0 {
71+
return true
72+
}
73+
return size >= w.MinimumFileSize
74+
}
75+
76+
// MeetsMaximumSize returns whether size is less than or equal to the maximum specified.
77+
func (w *WalkOpts) MeetsMaximumSize(size int64) bool {
78+
if w.MaximumFileSize < 0 {
79+
return true
80+
}
81+
return size <= w.MaximumFileSize
82+
}
83+
4584
// Algorithm represents the walk algorithm that will be performed.
4685
type Algorithm int
4786

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

103-
var nonDirectories []*dfsObjectInfo
142+
var children []*dfsObjectInfo
104143

105144
if err := w.iterateImmediateChildren(root, func(child *Path, info os.FileInfo, encounteredErr error) error {
106145
// Since we are doing depth-first, we have to first recurse through all the directories,
@@ -109,26 +148,32 @@ func (w *Walk) walkDFS(walkFn WalkFunc, root *Path, currentDepth int) error {
109148
if err := w.walkDFS(walkFn, child, currentDepth+1); err != nil {
110149
return err
111150
}
112-
if err := walkFn(child, info, encounteredErr); err != nil {
113-
return err
114-
}
115-
} else {
116-
nonDirectories = append(nonDirectories, &dfsObjectInfo{
117-
path: child,
118-
info: info,
119-
err: encounteredErr,
120-
})
121151
}
152+
153+
children = append(children, &dfsObjectInfo{
154+
path: child,
155+
info: info,
156+
err: encounteredErr,
157+
})
158+
122159
return nil
123160
}); err != nil {
124161
return err
125162
}
126163

127-
// Iterate over all non-directory objects
128-
for _, nonDir := range nonDirectories {
129-
if err := walkFn(nonDir.path, nonDir.info, nonDir.err); err != nil {
164+
// Iterate over all children after all subdirs have been recursed
165+
for _, child := range children {
166+
passesQuery, err := w.passesQuerySpecification(child.info)
167+
if err != nil {
130168
return err
131169
}
170+
171+
if passesQuery {
172+
if err := walkFn(child.path, child.info, child.err); err != nil {
173+
return err
174+
}
175+
}
176+
132177
}
133178
return nil
134179
}
@@ -150,11 +195,10 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
150195
}
151196
if w.Opts.FollowSymlinks {
152197
info, err = child.Stat()
153-
isSymlink, err := IsSymlink(info)
154198
if err != nil {
155199
return err
156200
}
157-
if isSymlink {
201+
if IsSymlink(info) {
158202
child, err = child.ResolveAll()
159203
if err != nil {
160204
return err
@@ -179,6 +223,28 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
179223
return nil
180224
}
181225

226+
// passesQuerySpecification returns whether or not the object described by
227+
// the os.FileInfo passes all of the query specifications listed in
228+
// the walk options.
229+
func (w *Walk) passesQuerySpecification(info os.FileInfo) (bool, error) {
230+
if IsFile(info) {
231+
if !w.Opts.VisitFiles {
232+
return false, nil
233+
}
234+
235+
if !w.Opts.MeetsMinimumSize(info.Size()) ||
236+
!w.Opts.MeetsMaximumSize(info.Size()) {
237+
return false, nil
238+
}
239+
} else if IsDir(info) && !w.Opts.VisitDirs {
240+
return false, nil
241+
} else if IsSymlink(info) && !w.Opts.VisitSymlinks {
242+
return false, nil
243+
}
244+
245+
return true, nil
246+
}
247+
182248
func (w *Walk) walkBasic(walkFn WalkFunc, root *Path, currentDepth int) error {
183249
if w.maxDepthReached(currentDepth) {
184250
return nil
@@ -191,9 +257,17 @@ func (w *Walk) walkBasic(walkFn WalkFunc, root *Path, currentDepth int) error {
191257
}
192258
}
193259

194-
if err := walkFn(child, info, encounteredErr); err != nil {
260+
passesQuery, err := w.passesQuerySpecification(info)
261+
if err != nil {
195262
return err
196263
}
264+
265+
if passesQuery {
266+
if err := walkFn(child, info, encounteredErr); err != nil {
267+
return err
268+
}
269+
}
270+
197271
return nil
198272
})
199273

walk_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,16 @@ func TestDefaultWalkOpts(t *testing.T) {
121121
name string
122122
want *WalkOpts
123123
}{
124-
{"assert defaults", &WalkOpts{-1, AlgorithmBasic, false}},
124+
{"assert defaults", &WalkOpts{
125+
Depth: -1,
126+
Algorithm: AlgorithmBasic,
127+
FollowSymlinks: false,
128+
MinimumFileSize: -1,
129+
MaximumFileSize: -1,
130+
VisitFiles: true,
131+
VisitDirs: true,
132+
VisitSymlinks: true,
133+
}},
125134
}
126135
for _, tt := range tests {
127136
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)