1 package org.codehaus.plexus.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.File;
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Stack;
24
25
26
27
28
29
30 public class DirectoryWalker {
31
32
33
34 class DirStackEntry {
35
36
37
38 public int count;
39
40
41
42
43 public File dir;
44
45
46
47
48 public int index;
49
50
51
52
53 public double percentageOffset;
54
55
56
57
58 public double percentageSize;
59
60
61
62
63
64
65
66 public DirStackEntry(File d, int length) {
67 dir = d;
68 count = length;
69 }
70
71
72
73
74
75
76 public double getNextPercentageOffset() {
77 return percentageOffset + (index * (percentageSize / count));
78 }
79
80
81
82
83
84
85 public double getNextPercentageSize() {
86 return (percentageSize / count);
87 }
88
89
90
91
92
93
94 public int getPercentage() {
95 double percentageWithinDir = (double) index / (double) count;
96 return (int) Math.floor(percentageOffset + (percentageWithinDir * percentageSize));
97 }
98
99 @Override
100 public String toString() {
101 return "DirStackEntry[" + "dir=" + dir.getAbsolutePath() + ",count=" + count + ",index=" + index
102 + ",percentageOffset=" + percentageOffset + ",percentageSize=" + percentageSize + ",percentage()="
103 + getPercentage() + ",getNextPercentageOffset()=" + getNextPercentageOffset()
104 + ",getNextPercentageSize()=" + getNextPercentageSize() + "]";
105 }
106 }
107
108 private File baseDir;
109
110 private int baseDirOffset;
111
112 private Stack<DirectoryWalker.DirStackEntry> dirStack;
113
114 private List<String> excludes;
115
116 private List<String> includes;
117
118 private boolean isCaseSensitive = true;
119
120 private List<DirectoryWalkListener> listeners;
121
122 private boolean debugEnabled = false;
123
124 public DirectoryWalker() {
125 includes = new ArrayList<String>();
126 excludes = new ArrayList<String>();
127 listeners = new ArrayList<DirectoryWalkListener>();
128 }
129
130 public void addDirectoryWalkListener(DirectoryWalkListener listener) {
131 listeners.add(listener);
132 }
133
134 public void addExclude(String exclude) {
135 excludes.add(fixPattern(exclude));
136 }
137
138 public void addInclude(String include) {
139 includes.add(fixPattern(include));
140 }
141
142
143
144
145 public void addSCMExcludes() {
146 String scmexcludes[] = AbstractScanner.DEFAULTEXCLUDES;
147 for (String scmexclude : scmexcludes) {
148 addExclude(scmexclude);
149 }
150 }
151
152 private void fireStep(File file) {
153 DirStackEntry dsEntry = dirStack.peek();
154 int percentage = dsEntry.getPercentage();
155 for (Object listener1 : listeners) {
156 DirectoryWalkListener listener = (DirectoryWalkListener) listener1;
157 listener.directoryWalkStep(percentage, file);
158 }
159 }
160
161 private void fireWalkFinished() {
162 for (DirectoryWalkListener listener1 : listeners) {
163 listener1.directoryWalkFinished();
164 }
165 }
166
167 private void fireWalkStarting() {
168 for (DirectoryWalkListener listener1 : listeners) {
169 listener1.directoryWalkStarting(baseDir);
170 }
171 }
172
173 private void fireDebugMessage(String message) {
174 for (DirectoryWalkListener listener1 : listeners) {
175 listener1.debug(message);
176 }
177 }
178
179 private String fixPattern(String pattern) {
180 String cleanPattern = pattern;
181
182 if (File.separatorChar != '/') {
183 cleanPattern = cleanPattern.replace('/', File.separatorChar);
184 }
185
186 if (File.separatorChar != '\\') {
187 cleanPattern = cleanPattern.replace('\\', File.separatorChar);
188 }
189
190 return cleanPattern;
191 }
192
193 public void setDebugMode(boolean debugEnabled) {
194 this.debugEnabled = debugEnabled;
195 }
196
197
198
199
200 public File getBaseDir() {
201 return baseDir;
202 }
203
204
205
206
207 public List<String> getExcludes() {
208 return excludes;
209 }
210
211
212
213
214 public List<String> getIncludes() {
215 return includes;
216 }
217
218 private boolean isExcluded(String name) {
219 return isMatch(excludes, name);
220 }
221
222 private boolean isIncluded(String name) {
223 return isMatch(includes, name);
224 }
225
226 private boolean isMatch(List<String> patterns, String name) {
227 for (String pattern1 : patterns) {
228 if (SelectorUtils.matchPath(pattern1, name, isCaseSensitive)) {
229 return true;
230 }
231 }
232
233 return false;
234 }
235
236 private String relativeToBaseDir(File file) {
237 return file.getAbsolutePath().substring(baseDirOffset + 1);
238 }
239
240
241
242
243
244
245 public void removeDirectoryWalkListener(DirectoryWalkListener listener) {
246 listeners.remove(listener);
247 }
248
249
250
251
252 public void scan() {
253 if (baseDir == null) {
254 throw new IllegalStateException("Scan Failure. BaseDir not specified.");
255 }
256
257 if (!baseDir.exists()) {
258 throw new IllegalStateException("Scan Failure. BaseDir does not exist.");
259 }
260
261 if (!baseDir.isDirectory()) {
262 throw new IllegalStateException("Scan Failure. BaseDir is not a directory.");
263 }
264
265 if (includes.isEmpty()) {
266
267 addInclude("**");
268 }
269
270 if (debugEnabled) {
271 Iterator<String> it;
272 StringBuilder dbg = new StringBuilder();
273 dbg.append("DirectoryWalker Scan");
274 dbg.append("\n Base Dir: ").append(baseDir.getAbsolutePath());
275 dbg.append("\n Includes: ");
276 it = includes.iterator();
277 while (it.hasNext()) {
278 String include = it.next();
279 dbg.append("\n - \"").append(include).append("\"");
280 }
281 dbg.append("\n Excludes: ");
282 it = excludes.iterator();
283 while (it.hasNext()) {
284 String exclude = it.next();
285 dbg.append("\n - \"").append(exclude).append("\"");
286 }
287 fireDebugMessage(dbg.toString());
288 }
289
290 fireWalkStarting();
291 dirStack = new Stack<DirStackEntry>();
292 scanDir(baseDir);
293 fireWalkFinished();
294 }
295
296 private void scanDir(File dir) {
297 File[] files = dir.listFiles();
298
299 if (files == null) {
300 return;
301 }
302
303 DirectoryWalker.DirStackEntry curStackEntry = new DirectoryWalker.DirStackEntry(dir, files.length);
304 if (dirStack.isEmpty()) {
305 curStackEntry.percentageOffset = 0;
306 curStackEntry.percentageSize = 100;
307 } else {
308 DirectoryWalker.DirStackEntry previousStackEntry = dirStack.peek();
309 curStackEntry.percentageOffset = previousStackEntry.getNextPercentageOffset();
310 curStackEntry.percentageSize = previousStackEntry.getNextPercentageSize();
311 }
312
313 dirStack.push(curStackEntry);
314
315 for (int idx = 0; idx < files.length; idx++) {
316 curStackEntry.index = idx;
317 String name = relativeToBaseDir(files[idx]);
318
319 if (isExcluded(name)) {
320 fireDebugMessage(name + " is excluded.");
321 continue;
322 }
323
324 if (files[idx].isDirectory()) {
325 scanDir(files[idx]);
326 } else {
327 if (isIncluded(name)) {
328 fireStep(files[idx]);
329 }
330 }
331 }
332
333 dirStack.pop();
334 }
335
336
337
338
339 public void setBaseDir(File baseDir) {
340 this.baseDir = baseDir;
341 baseDirOffset = baseDir.getAbsolutePath().length();
342 }
343
344
345
346
347 public void setExcludes(List<String> entries) {
348 excludes.clear();
349 if (entries != null) {
350 for (String entry : entries) {
351 excludes.add(fixPattern(entry));
352 }
353 }
354 }
355
356
357
358
359 public void setIncludes(List<String> entries) {
360 includes.clear();
361 if (entries != null) {
362 for (String entry : entries) {
363 includes.add(fixPattern(entry));
364 }
365 }
366 }
367 }