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