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 }