@@ -22,6 +22,24 @@ type WalkOpts struct {
22
22
// to True. Here be dragons!
23
23
FollowSymlinks bool
24
24
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
+
25
43
// VisitFirst specifies that, in the algorithms where it is appropriate,
26
44
// a node's contents should be visited first, before recursing down. If false,
27
45
// a node's subdirectories will be recursed first before visiting any of its
@@ -36,12 +54,33 @@ type WalkOpts struct {
36
54
// walking a directory.
37
55
func DefaultWalkOpts () * WalkOpts {
38
56
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 ,
42
65
}
43
66
}
44
67
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
+
45
84
// Algorithm represents the walk algorithm that will be performed.
46
85
type Algorithm int
47
86
@@ -100,7 +139,7 @@ func (w *Walk) walkDFS(walkFn WalkFunc, root *Path, currentDepth int) error {
100
139
return nil
101
140
}
102
141
103
- var nonDirectories []* dfsObjectInfo
142
+ var children []* dfsObjectInfo
104
143
105
144
if err := w .iterateImmediateChildren (root , func (child * Path , info os.FileInfo , encounteredErr error ) error {
106
145
// 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 {
109
148
if err := w .walkDFS (walkFn , child , currentDepth + 1 ); err != nil {
110
149
return err
111
150
}
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
- })
121
151
}
152
+
153
+ children = append (children , & dfsObjectInfo {
154
+ path : child ,
155
+ info : info ,
156
+ err : encounteredErr ,
157
+ })
158
+
122
159
return nil
123
160
}); err != nil {
124
161
return err
125
162
}
126
163
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 {
130
168
return err
131
169
}
170
+
171
+ if passesQuery {
172
+ if err := walkFn (child .path , child .info , child .err ); err != nil {
173
+ return err
174
+ }
175
+ }
176
+
132
177
}
133
178
return nil
134
179
}
@@ -150,11 +195,10 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
150
195
}
151
196
if w .Opts .FollowSymlinks {
152
197
info , err = child .Stat ()
153
- isSymlink , err := IsSymlink (info )
154
198
if err != nil {
155
199
return err
156
200
}
157
- if isSymlink {
201
+ if IsSymlink ( info ) {
158
202
child , err = child .ResolveAll ()
159
203
if err != nil {
160
204
return err
@@ -179,6 +223,28 @@ func (w *Walk) iterateImmediateChildren(root *Path, algorithmFunction WalkFunc)
179
223
return nil
180
224
}
181
225
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
+
182
248
func (w * Walk ) walkBasic (walkFn WalkFunc , root * Path , currentDepth int ) error {
183
249
if w .maxDepthReached (currentDepth ) {
184
250
return nil
@@ -191,9 +257,17 @@ func (w *Walk) walkBasic(walkFn WalkFunc, root *Path, currentDepth int) error {
191
257
}
192
258
}
193
259
194
- if err := walkFn (child , info , encounteredErr ); err != nil {
260
+ passesQuery , err := w .passesQuerySpecification (info )
261
+ if err != nil {
195
262
return err
196
263
}
264
+
265
+ if passesQuery {
266
+ if err := walkFn (child , info , encounteredErr ); err != nil {
267
+ return err
268
+ }
269
+ }
270
+
197
271
return nil
198
272
})
199
273
0 commit comments