source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/DirectoryScanner.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 59.1 KB
Line 
1/*
2 * Copyright 2000-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant;
19
20import java.io.File;
21import java.io.IOException;
22import java.util.Map;
23import java.util.Set;
24import java.util.Arrays;
25import java.util.Vector;
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.ArrayList;
29import java.util.Hashtable;
30import java.util.Enumeration;
31
32import org.apache.tools.ant.taskdefs.condition.Os;
33import org.apache.tools.ant.types.Resource;
34import org.apache.tools.ant.types.ResourceFactory;
35import org.apache.tools.ant.types.selectors.FileSelector;
36import org.apache.tools.ant.types.selectors.SelectorUtils;
37import org.apache.tools.ant.types.selectors.SelectorScanner;
38import org.apache.tools.ant.util.FileUtils;
39
40/**
41 * Class for scanning a directory for files/directories which match certain
42 * criteria.
43 * <p>
44 * These criteria consist of selectors and patterns which have been specified.
45 * With the selectors you can select which files you want to have included.
46 * Files which are not selected are excluded. With patterns you can include
47 * or exclude files based on their filename.
48 * <p>
49 * The idea is simple. A given directory is recursively scanned for all files
50 * and directories. Each file/directory is matched against a set of selectors,
51 * including special support for matching against filenames with include and
52 * and exclude patterns. Only files/directories which match at least one
53 * pattern of the include pattern list or other file selector, and don't match
54 * any pattern of the exclude pattern list or fail to match against a required
55 * selector will be placed in the list of files/directories found.
56 * <p>
57 * When no list of include patterns is supplied, "**" will be used, which
58 * means that everything will be matched. When no list of exclude patterns is
59 * supplied, an empty list is used, such that nothing will be excluded. When
60 * no selectors are supplied, none are applied.
61 * <p>
62 * The filename pattern matching is done as follows:
63 * The name to be matched is split up in path segments. A path segment is the
64 * name of a directory or file, which is bounded by
65 * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
66 * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
67 * "def","ghi" and "xyz.java".
68 * The same is done for the pattern against which should be matched.
69 * <p>
70 * The segments of the name and the pattern are then matched against each
71 * other. When '**' is used for a path segment in the pattern, it matches
72 * zero or more path segments of the name.
73 * <p>
74 * There is a special case regarding the use of <code>File.separator</code>s
75 * at the beginning of the pattern and the string to match:<br>
76 * When a pattern starts with a <code>File.separator</code>, the string
77 * to match must also start with a <code>File.separator</code>.
78 * When a pattern does not start with a <code>File.separator</code>, the
79 * string to match may not start with a <code>File.separator</code>.
80 * When one of these rules is not obeyed, the string will not
81 * match.
82 * <p>
83 * When a name path segment is matched against a pattern path segment, the
84 * following special characters can be used:<br>
85 * '*' matches zero or more characters<br>
86 * '?' matches one character.
87 * <p>
88 * Examples:
89 * <p>
90 * "**\*.class" matches all .class files/dirs in a directory tree.
91 * <p>
92 * "test\a??.java" matches all files/dirs which start with an 'a', then two
93 * more characters and then ".java", in a directory called test.
94 * <p>
95 * "**" matches everything in a directory tree.
96 * <p>
97 * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
98 * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
99 * <p>
100 * Case sensitivity may be turned off if necessary. By default, it is
101 * turned on.
102 * <p>
103 * Example of usage:
104 * <pre>
105 * String[] includes = {"**\\*.class"};
106 * String[] excludes = {"modules\\*\\**"};
107 * ds.setIncludes(includes);
108 * ds.setExcludes(excludes);
109 * ds.setBasedir(new File("test"));
110 * ds.setCaseSensitive(true);
111 * ds.scan();
112 *
113 * System.out.println("FILES:");
114 * String[] files = ds.getIncludedFiles();
115 * for (int i = 0; i < files.length; i++) {
116 * System.out.println(files[i]);
117 * }
118 * </pre>
119 * This will scan a directory called test for .class files, but excludes all
120 * files in all proper subdirectories of a directory called "modules"
121 *
122 */
123public class DirectoryScanner
124 implements FileScanner, SelectorScanner, ResourceFactory {
125
126 /** Is OpenVMS the operating system we're running on? */
127 private static final boolean ON_VMS = Os.isFamily("openvms");
128
129 /**
130 * Patterns which should be excluded by default.
131 *
132 * <p>Note that you can now add patterns to the list of default
133 * excludes. Added patterns will not become part of this array
134 * that has only been kept around for backwards compatibility
135 * reasons.</p>
136 *
137 * @deprecated use the {@link #getDefaultExcludes
138 * getDefaultExcludes} method instead.
139 */
140 protected static final String[] DEFAULTEXCLUDES = {
141 // Miscellaneous typical temporary files
142 "**/*~",
143 "**/#*#",
144 "**/.#*",
145 "**/%*%",
146 "**/._*",
147
148 // CVS
149 "**/CVS",
150 "**/CVS/**",
151 "**/.cvsignore",
152
153 // SCCS
154 "**/SCCS",
155 "**/SCCS/**",
156
157 // Visual SourceSafe
158 "**/vssver.scc",
159
160 // Subversion
161 "**/.svn",
162 "**/.svn/**",
163
164 // Mac
165 "**/.DS_Store"
166 };
167
168 /** Helper. */
169 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
170
171 /** iterations for case-sensitive scanning. */
172 private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
173
174 /** iterations for non-case-sensitive scanning. */
175 private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false};
176
177 /**
178 * Patterns which should be excluded by default.
179 *
180 * @see #addDefaultExcludes()
181 */
182 private static Vector defaultExcludes = new Vector();
183 static {
184 resetDefaultExcludes();
185 }
186
187 /** The base directory to be scanned. */
188 protected File basedir;
189
190 /** The patterns for the files to be included. */
191 protected String[] includes;
192
193 /** The patterns for the files to be excluded. */
194 protected String[] excludes;
195
196 /** Selectors that will filter which files are in our candidate list. */
197 protected FileSelector[] selectors = null;
198
199 /**
200 * The files which matched at least one include and no excludes
201 * and were selected.
202 */
203 protected Vector filesIncluded;
204
205 /** The files which did not match any includes or selectors. */
206 protected Vector filesNotIncluded;
207
208 /**
209 * The files which matched at least one include and at least
210 * one exclude.
211 */
212 protected Vector filesExcluded;
213
214 /**
215 * The directories which matched at least one include and no excludes
216 * and were selected.
217 */
218 protected Vector dirsIncluded;
219
220 /** The directories which were found and did not match any includes. */
221 protected Vector dirsNotIncluded;
222
223 /**
224 * The directories which matched at least one include and at least one
225 * exclude.
226 */
227 protected Vector dirsExcluded;
228
229 /**
230 * The files which matched at least one include and no excludes and
231 * which a selector discarded.
232 */
233 protected Vector filesDeselected;
234
235 /**
236 * The directories which matched at least one include and no excludes
237 * but which a selector discarded.
238 */
239 protected Vector dirsDeselected;
240
241 /** Whether or not our results were built by a slow scan. */
242 protected boolean haveSlowResults = false;
243
244 /**
245 * Whether or not the file system should be treated as a case sensitive
246 * one.
247 */
248 protected boolean isCaseSensitive = true;
249
250 /**
251 * Whether or not symbolic links should be followed.
252 *
253 * @since Ant 1.5
254 */
255 private boolean followSymlinks = true;
256
257 /** Whether or not everything tested so far has been included. */
258 protected boolean everythingIncluded = true;
259
260 /**
261 * Temporary table to speed up the various scanning methods.
262 *
263 * @since Ant 1.6
264 */
265 private Map fileListMap = new HashMap();
266
267 /**
268 * List of all scanned directories.
269 *
270 * @since Ant 1.6
271 */
272 private Set scannedDirs = new HashSet();
273
274 /**
275 * Set of all include patterns that are full file names and don't
276 * contain any wildcards.
277 *
278 * <p>If this instance is not case sensitive, the file names get
279 * turned to lower case.</p>
280 *
281 * <p>Gets lazily initialized on the first invocation of
282 * isIncluded or isExcluded and cleared at the end of the scan
283 * method (cleared in clearCaches, actually).</p>
284 *
285 * @since Ant 1.6.3
286 */
287 private Set includeNonPatterns = new HashSet();
288
289 /**
290 * Set of all include patterns that are full file names and don't
291 * contain any wildcards.
292 *
293 * <p>If this instance is not case sensitive, the file names get
294 * turned to lower case.</p>
295 *
296 * <p>Gets lazily initialized on the first invocation of
297 * isIncluded or isExcluded and cleared at the end of the scan
298 * method (cleared in clearCaches, actually).</p>
299 *
300 * @since Ant 1.6.3
301 */
302 private Set excludeNonPatterns = new HashSet();
303
304 /**
305 * Array of all include patterns that contain wildcards.
306 *
307 * <p>Gets lazily initialized on the first invocation of
308 * isIncluded or isExcluded and cleared at the end of the scan
309 * method (cleared in clearCaches, actually).</p>
310 *
311 * @since Ant 1.6.3
312 */
313 private String[] includePatterns;
314
315 /**
316 * Array of all exclude patterns that contain wildcards.
317 *
318 * <p>Gets lazily initialized on the first invocation of
319 * isIncluded or isExcluded and cleared at the end of the scan
320 * method (cleared in clearCaches, actually).</p>
321 *
322 * @since Ant 1.6.3
323 */
324 private String[] excludePatterns;
325
326 /**
327 * Have the non-pattern sets and pattern arrays for in- and
328 * excludes been initialized?
329 *
330 * @since Ant 1.6.3
331 */
332 private boolean areNonPatternSetsReady = false;
333
334 /**
335 * Scanning flag.
336 *
337 * @since Ant 1.6.3
338 */
339 private boolean scanning = false;
340
341 /**
342 * Scanning lock.
343 *
344 * @since Ant 1.6.3
345 */
346 private Object scanLock = new Object();
347
348 /**
349 * Slow scanning flag.
350 *
351 * @since Ant 1.6.3
352 */
353 private boolean slowScanning = false;
354
355 /**
356 * Slow scanning lock.
357 *
358 * @since Ant 1.6.3
359 */
360 private Object slowScanLock = new Object();
361
362 /**
363 * Exception thrown during scan.
364 *
365 * @since Ant 1.6.3
366 */
367 private IllegalStateException illegal = null;
368
369 /**
370 * Sole constructor.
371 */
372 public DirectoryScanner() {
373 }
374
375 /**
376 * Test whether or not a given path matches the start of a given
377 * pattern up to the first "**".
378 * <p>
379 * This is not a general purpose test and should only be used if you
380 * can live with false positives. For example, <code>pattern=**\a</code>
381 * and <code>str=b</code> will yield <code>true</code>.
382 *
383 * @param pattern The pattern to match against. Must not be
384 * <code>null</code>.
385 * @param str The path to match, as a String. Must not be
386 * <code>null</code>.
387 *
388 * @return whether or not a given path matches the start of a given
389 * pattern up to the first "**".
390 */
391 protected static boolean matchPatternStart(String pattern, String str) {
392 return SelectorUtils.matchPatternStart(pattern, str);
393 }
394
395 /**
396 * Test whether or not a given path matches the start of a given
397 * pattern up to the first "**".
398 * <p>
399 * This is not a general purpose test and should only be used if you
400 * can live with false positives. For example, <code>pattern=**\a</code>
401 * and <code>str=b</code> will yield <code>true</code>.
402 *
403 * @param pattern The pattern to match against. Must not be
404 * <code>null</code>.
405 * @param str The path to match, as a String. Must not be
406 * <code>null</code>.
407 * @param isCaseSensitive Whether or not matching should be performed
408 * case sensitively.
409 *
410 * @return whether or not a given path matches the start of a given
411 * pattern up to the first "**".
412 */
413 protected static boolean matchPatternStart(String pattern, String str,
414 boolean isCaseSensitive) {
415 return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
416 }
417
418 /**
419 * Test whether or not a given path matches a given pattern.
420 *
421 * @param pattern The pattern to match against. Must not be
422 * <code>null</code>.
423 * @param str The path to match, as a String. Must not be
424 * <code>null</code>.
425 *
426 * @return <code>true</code> if the pattern matches against the string,
427 * or <code>false</code> otherwise.
428 */
429 protected static boolean matchPath(String pattern, String str) {
430 return SelectorUtils.matchPath(pattern, str);
431 }
432
433 /**
434 * Test whether or not a given path matches a given pattern.
435 *
436 * @param pattern The pattern to match against. Must not be
437 * <code>null</code>.
438 * @param str The path to match, as a String. Must not be
439 * <code>null</code>.
440 * @param isCaseSensitive Whether or not matching should be performed
441 * case sensitively.
442 *
443 * @return <code>true</code> if the pattern matches against the string,
444 * or <code>false</code> otherwise.
445 */
446 protected static boolean matchPath(String pattern, String str,
447 boolean isCaseSensitive) {
448 return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
449 }
450
451 /**
452 * Test whether or not a string matches against a pattern.
453 * The pattern may contain two special characters:<br>
454 * '*' means zero or more characters<br>
455 * '?' means one and only one character
456 *
457 * @param pattern The pattern to match against.
458 * Must not be <code>null</code>.
459 * @param str The string which must be matched against the pattern.
460 * Must not be <code>null</code>.
461 *
462 * @return <code>true</code> if the string matches against the pattern,
463 * or <code>false</code> otherwise.
464 */
465 public static boolean match(String pattern, String str) {
466 return SelectorUtils.match(pattern, str);
467 }
468
469 /**
470 * Test whether or not a string matches against a pattern.
471 * The pattern may contain two special characters:<br>
472 * '*' means zero or more characters<br>
473 * '?' means one and only one character
474 *
475 * @param pattern The pattern to match against.
476 * Must not be <code>null</code>.
477 * @param str The string which must be matched against the pattern.
478 * Must not be <code>null</code>.
479 * @param isCaseSensitive Whether or not matching should be performed
480 * case sensitively.
481 *
482 *
483 * @return <code>true</code> if the string matches against the pattern,
484 * or <code>false</code> otherwise.
485 */
486 protected static boolean match(String pattern, String str,
487 boolean isCaseSensitive) {
488 return SelectorUtils.match(pattern, str, isCaseSensitive);
489 }
490
491
492 /**
493 * Get the list of patterns that should be excluded by default.
494 *
495 * @return An array of <code>String</code> based on the current
496 * contents of the <code>defaultExcludes</code>
497 * <code>Vector</code>.
498 *
499 * @since Ant 1.6
500 */
501 public static String[] getDefaultExcludes() {
502 return (String[]) defaultExcludes.toArray(new String[defaultExcludes
503 .size()]);
504 }
505
506 /**
507 * Add a pattern to the default excludes unless it is already a
508 * default exclude.
509 *
510 * @param s A string to add as an exclude pattern.
511 * @return <code>true</code> if the string was added;
512 * <code>false</code> if it already existed.
513 *
514 * @since Ant 1.6
515 */
516 public static boolean addDefaultExclude(String s) {
517 if (defaultExcludes.indexOf(s) == -1) {
518 defaultExcludes.add(s);
519 return true;
520 }
521 return false;
522 }
523
524 /**
525 * Remove a string if it is a default exclude.
526 *
527 * @param s The string to attempt to remove.
528 * @return <code>true</code> if <code>s</code> was a default
529 * exclude (and thus was removed);
530 * <code>false</code> if <code>s</code> was not
531 * in the default excludes list to begin with.
532 *
533 * @since Ant 1.6
534 */
535 public static boolean removeDefaultExclude(String s) {
536 return defaultExcludes.remove(s);
537 }
538
539 /**
540 * Go back to the hardwired default exclude patterns.
541 *
542 * @since Ant 1.6
543 */
544 public static void resetDefaultExcludes() {
545 defaultExcludes = new Vector();
546 for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
547 defaultExcludes.add(DEFAULTEXCLUDES[i]);
548 }
549 }
550
551 /**
552 * Set the base directory to be scanned. This is the directory which is
553 * scanned recursively. All '/' and '\' characters are replaced by
554 * <code>File.separatorChar</code>, so the separator used need not match
555 * <code>File.separatorChar</code>.
556 *
557 * @param basedir The base directory to scan.
558 * Must not be <code>null</code>.
559 */
560 public void setBasedir(String basedir) {
561 setBasedir(new File(basedir.replace('/', File.separatorChar).replace(
562 '\\', File.separatorChar)));
563 }
564
565 /**
566 * Set the base directory to be scanned. This is the directory which is
567 * scanned recursively.
568 *
569 * @param basedir The base directory for scanning.
570 * Should not be <code>null</code>.
571 */
572 public synchronized void setBasedir(File basedir) {
573 this.basedir = basedir;
574 }
575
576 /**
577 * Return the base directory to be scanned.
578 * This is the directory which is scanned recursively.
579 *
580 * @return the base directory to be scanned
581 */
582 public synchronized File getBasedir() {
583 return basedir;
584 }
585
586 /**
587 * Find out whether include exclude patterns are matched in a
588 * case sensitive way.
589 * @return whether or not the scanning is case sensitive.
590 * @since Ant 1.6
591 */
592 public synchronized boolean isCaseSensitive() {
593 return isCaseSensitive;
594 }
595
596 /**
597 * Set whether or not include and exclude patterns are matched
598 * in a case sensitive way.
599 *
600 * @param isCaseSensitive whether or not the file system should be
601 * regarded as a case sensitive one.
602 */
603 public synchronized void setCaseSensitive(boolean isCaseSensitive) {
604 this.isCaseSensitive = isCaseSensitive;
605 }
606
607 /**
608 * Get whether or not a DirectoryScanner follows symbolic links.
609 *
610 * @return flag indicating whether symbolic links should be followed.
611 *
612 * @since Ant 1.6
613 */
614 public synchronized boolean isFollowSymlinks() {
615 return followSymlinks;
616 }
617
618 /**
619 * Set whether or not symbolic links should be followed.
620 *
621 * @param followSymlinks whether or not symbolic links should be followed.
622 */
623 public synchronized void setFollowSymlinks(boolean followSymlinks) {
624 this.followSymlinks = followSymlinks;
625 }
626
627 /**
628 * Set the list of include patterns to use. All '/' and '\' characters
629 * are replaced by <code>File.separatorChar</code>, so the separator used
630 * need not match <code>File.separatorChar</code>.
631 * <p>
632 * When a pattern ends with a '/' or '\', "**" is appended.
633 *
634 * @param includes A list of include patterns.
635 * May be <code>null</code>, indicating that all files
636 * should be included. If a non-<code>null</code>
637 * list is given, all elements must be
638 * non-<code>null</code>.
639 */
640 public synchronized void setIncludes(String[] includes) {
641 if (includes == null) {
642 this.includes = null;
643 } else {
644 this.includes = new String[includes.length];
645 for (int i = 0; i < includes.length; i++) {
646 this.includes[i] = normalizePattern(includes[i]);
647 }
648 }
649 }
650
651 /**
652 * Set the list of exclude patterns to use. All '/' and '\' characters
653 * are replaced by <code>File.separatorChar</code>, so the separator used
654 * need not match <code>File.separatorChar</code>.
655 * <p>
656 * When a pattern ends with a '/' or '\', "**" is appended.
657 *
658 * @param excludes A list of exclude patterns.
659 * May be <code>null</code>, indicating that no files
660 * should be excluded. If a non-<code>null</code> list is
661 * given, all elements must be non-<code>null</code>.
662 */
663 public synchronized void setExcludes(String[] excludes) {
664 if (excludes == null) {
665 this.excludes = null;
666 } else {
667 this.excludes = new String[excludes.length];
668 for (int i = 0; i < excludes.length; i++) {
669 this.excludes[i] = normalizePattern(excludes[i]);
670 }
671 }
672 }
673
674 /**
675 * Add to the list of exclude patterns to use. All '/' and '\'
676 * characters are replaced by <code>File.separatorChar</code>, so
677 * the separator used need not match <code>File.separatorChar</code>.
678 * <p>
679 * When a pattern ends with a '/' or '\', "**" is appended.
680 *
681 * @param excludes A list of exclude patterns.
682 * May be <code>null</code>, in which case the
683 * exclude patterns don't get changed at all.
684 *
685 * @since Ant 1.6.3
686 */
687 public synchronized void addExcludes(String[] excludes) {
688 if (excludes != null && excludes.length > 0) {
689 if (this.excludes != null && this.excludes.length > 0) {
690 String[] tmp = new String[excludes.length
691 + this.excludes.length];
692 System.arraycopy(this.excludes, 0, tmp, 0,
693 this.excludes.length);
694 for (int i = 0; i < excludes.length; i++) {
695 tmp[this.excludes.length + i] =
696 normalizePattern(excludes[i]);
697 }
698 this.excludes = tmp;
699 } else {
700 setExcludes(excludes);
701 }
702 }
703 }
704
705 /**
706 * All '/' and '\' characters are replaced by
707 * <code>File.separatorChar</code>, so the separator used need not
708 * match <code>File.separatorChar</code>.
709 *
710 * <p> When a pattern ends with a '/' or '\', "**" is appended.
711 *
712 * @since Ant 1.6.3
713 */
714 private static String normalizePattern(String p) {
715 String pattern = p.replace('/', File.separatorChar)
716 .replace('\\', File.separatorChar);
717 if (pattern.endsWith(File.separator)) {
718 pattern += "**";
719 }
720 return pattern;
721 }
722
723 /**
724 * Set the selectors that will select the filelist.
725 *
726 * @param selectors specifies the selectors to be invoked on a scan.
727 */
728 public synchronized void setSelectors(FileSelector[] selectors) {
729 this.selectors = selectors;
730 }
731
732 /**
733 * Return whether or not the scanner has included all the files or
734 * directories it has come across so far.
735 *
736 * @return <code>true</code> if all files and directories which have
737 * been found so far have been included.
738 */
739 public synchronized boolean isEverythingIncluded() {
740 return everythingIncluded;
741 }
742
743 /**
744 * Scan the base directory for files which match at least one include
745 * pattern and don't match any exclude patterns. If there are selectors
746 * then the files must pass muster there, as well.
747 *
748 * @exception IllegalStateException if the base directory was set
749 * incorrectly (i.e. if it is <code>null</code>, doesn't exist,
750 * or isn't a directory).
751 */
752 public void scan() throws IllegalStateException {
753 synchronized (scanLock) {
754 if (scanning) {
755 while (scanning) {
756 try {
757 scanLock.wait();
758 } catch (InterruptedException e) {
759 continue;
760 }
761 }
762 if (illegal != null) {
763 throw illegal;
764 }
765 return;
766 }
767 scanning = true;
768 }
769 try {
770 synchronized (this) {
771 illegal = null;
772 clearResults();
773
774 // set in/excludes to reasonable defaults if needed:
775 boolean nullIncludes = (includes == null);
776 includes = nullIncludes ? new String[] {"**"} : includes;
777 boolean nullExcludes = (excludes == null);
778 excludes = nullExcludes ? new String[0] : excludes;
779
780 if (basedir == null) {
781 illegal = new IllegalStateException("No basedir set");
782 } else {
783 if (!basedir.exists()) {
784 illegal = new IllegalStateException("basedir " + basedir
785 + " does not exist");
786 }
787 if (!basedir.isDirectory()) {
788 illegal = new IllegalStateException("basedir " + basedir
789 + " is not a directory");
790 }
791 }
792 if (illegal != null) {
793 throw illegal;
794 }
795 if (isIncluded("")) {
796 if (!isExcluded("")) {
797 if (isSelected("", basedir)) {
798 dirsIncluded.addElement("");
799 } else {
800 dirsDeselected.addElement("");
801 }
802 } else {
803 dirsExcluded.addElement("");
804 }
805 } else {
806 dirsNotIncluded.addElement("");
807 }
808 checkIncludePatterns();
809 clearCaches();
810 includes = nullIncludes ? null : includes;
811 excludes = nullExcludes ? null : excludes;
812 }
813 } finally {
814 synchronized (scanLock) {
815 scanning = false;
816 scanLock.notifyAll();
817 }
818 }
819 }
820
821 /**
822 * This routine is actually checking all the include patterns in
823 * order to avoid scanning everything under base dir.
824 * @since Ant 1.6
825 */
826 private void checkIncludePatterns() {
827 Hashtable newroots = new Hashtable();
828 // put in the newroots vector the include patterns without
829 // wildcard tokens
830 for (int icounter = 0; icounter < includes.length; icounter++) {
831 newroots.put(SelectorUtils.rtrimWildcardTokens(
832 includes[icounter]), includes[icounter]);
833 }
834 if (newroots.containsKey("")) {
835 // we are going to scan everything anyway
836 scandir(basedir, "", true);
837 } else {
838 // only scan directories that can include matched files or
839 // directories
840 Enumeration enum2 = newroots.keys();
841
842 File canonBase = null;
843 try {
844 canonBase = basedir.getCanonicalFile();
845 } catch (IOException ex) {
846 throw new BuildException(ex);
847 }
848 while (enum2.hasMoreElements()) {
849 String currentelement = (String) enum2.nextElement();
850 String originalpattern = (String) newroots.get(currentelement);
851 File myfile = new File(basedir, currentelement);
852
853 if (myfile.exists()) {
854 // may be on a case insensitive file system. We want
855 // the results to show what's really on the disk, so
856 // we need to double check.
857 try {
858 File canonFile = myfile.getCanonicalFile();
859 String path = FILE_UTILS.removeLeadingPath(canonBase,
860 canonFile);
861 if (!path.equals(currentelement) || ON_VMS) {
862 myfile = findFile(basedir, currentelement, true);
863 if (myfile != null) {
864 currentelement =
865 FILE_UTILS.removeLeadingPath(basedir,
866 myfile);
867 }
868 }
869 } catch (IOException ex) {
870 throw new BuildException(ex);
871 }
872 }
873 if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
874 File f = findFile(basedir, currentelement, false);
875 if (f != null && f.exists()) {
876 // adapt currentelement to the case we've
877 // actually found
878 currentelement = FILE_UTILS.removeLeadingPath(basedir,
879 f);
880 myfile = f;
881 }
882 }
883 if (myfile != null && myfile.exists()) {
884 if (!followSymlinks
885 && isSymlink(basedir, currentelement)) {
886 continue;
887 }
888 if (myfile.isDirectory()) {
889 if (isIncluded(currentelement)
890 && currentelement.length() > 0) {
891 accountForIncludedDir(currentelement, myfile, true);
892 } else {
893 if (currentelement.length() > 0) {
894 if (currentelement.charAt(currentelement
895 .length() - 1)
896 != File.separatorChar) {
897 currentelement =
898 currentelement + File.separatorChar;
899 }
900 }
901 scandir(myfile, currentelement, true);
902 }
903 } else {
904 boolean included = isCaseSensitive()
905 ? originalpattern.equals(currentelement)
906 : originalpattern.equalsIgnoreCase(currentelement);
907 if (included) {
908 accountForIncludedFile(currentelement, myfile);
909 }
910 }
911 }
912 }
913 }
914 }
915
916 /**
917 * Clear the result caches for a scan.
918 */
919 protected synchronized void clearResults() {
920 filesIncluded = new Vector();
921 filesNotIncluded = new Vector();
922 filesExcluded = new Vector();
923 filesDeselected = new Vector();
924 dirsIncluded = new Vector();
925 dirsNotIncluded = new Vector();
926 dirsExcluded = new Vector();
927 dirsDeselected = new Vector();
928 everythingIncluded = (basedir != null);
929 scannedDirs.clear();
930 }
931
932 /**
933 * Top level invocation for a slow scan. A slow scan builds up a full
934 * list of excluded/included files/directories, whereas a fast scan
935 * will only have full results for included files, as it ignores
936 * directories which can't possibly hold any included files/directories.
937 * <p>
938 * Returns immediately if a slow scan has already been completed.
939 */
940 protected void slowScan() {
941 synchronized (slowScanLock) {
942 if (haveSlowResults) {
943 return;
944 }
945 if (slowScanning) {
946 while (slowScanning) {
947 try {
948 slowScanLock.wait();
949 } catch (InterruptedException e) {
950 }
951 }
952 return;
953 }
954 slowScanning = true;
955 }
956 try {
957 synchronized (this) {
958
959 // set in/excludes to reasonable defaults if needed:
960 boolean nullIncludes = (includes == null);
961 includes = nullIncludes ? new String[] {"**"} : includes;
962 boolean nullExcludes = (excludes == null);
963 excludes = nullExcludes ? new String[0] : excludes;
964
965 String[] excl = new String[dirsExcluded.size()];
966 dirsExcluded.copyInto(excl);
967
968 String[] notIncl = new String[dirsNotIncluded.size()];
969 dirsNotIncluded.copyInto(notIncl);
970
971 for (int i = 0; i < excl.length; i++) {
972 if (!couldHoldIncluded(excl[i])) {
973 scandir(new File(basedir, excl[i]),
974 excl[i] + File.separator, false);
975 }
976 }
977 for (int i = 0; i < notIncl.length; i++) {
978 if (!couldHoldIncluded(notIncl[i])) {
979 scandir(new File(basedir, notIncl[i]),
980 notIncl[i] + File.separator, false);
981 }
982 }
983 clearCaches();
984 includes = nullIncludes ? null : includes;
985 excludes = nullExcludes ? null : excludes;
986 }
987 } finally {
988 synchronized (slowScanLock) {
989 haveSlowResults = true;
990 slowScanning = false;
991 slowScanLock.notifyAll();
992 }
993 }
994 }
995
996 /**
997 * Scan the given directory for files and directories. Found files and
998 * directories are placed in their respective collections, based on the
999 * matching of includes, excludes, and the selectors. When a directory
1000 * is found, it is scanned recursively.
1001 *
1002 * @param dir The directory to scan. Must not be <code>null</code>.
1003 * @param vpath The path relative to the base directory (needed to
1004 * prevent problems with an absolute path when using
1005 * dir). Must not be <code>null</code>.
1006 * @param fast Whether or not this call is part of a fast scan.
1007 *
1008 * @see #filesIncluded
1009 * @see #filesNotIncluded
1010 * @see #filesExcluded
1011 * @see #dirsIncluded
1012 * @see #dirsNotIncluded
1013 * @see #dirsExcluded
1014 * @see #slowScan
1015 */
1016 protected void scandir(File dir, String vpath, boolean fast) {
1017 if (dir == null) {
1018 throw new BuildException("dir must not be null.");
1019 } else if (!dir.exists()) {
1020 throw new BuildException(dir + " doesn't exists.");
1021 } else if (!dir.isDirectory()) {
1022 throw new BuildException(dir + " is not a directory.");
1023 }
1024 // avoid double scanning of directories, can only happen in fast mode
1025 if (fast && hasBeenScanned(vpath)) {
1026 return;
1027 }
1028 String[] newfiles = dir.list();
1029
1030 if (newfiles == null) {
1031 /*
1032 * two reasons are mentioned in the API docs for File.list
1033 * (1) dir is not a directory. This is impossible as
1034 * we wouldn't get here in this case.
1035 * (2) an IO error occurred (why doesn't it throw an exception
1036 * then???)
1037 */
1038 throw new BuildException("IO error scanning directory "
1039 + dir.getAbsolutePath());
1040 }
1041 if (!followSymlinks) {
1042 Vector noLinks = new Vector();
1043 for (int i = 0; i < newfiles.length; i++) {
1044 try {
1045 if (FILE_UTILS.isSymbolicLink(dir, newfiles[i])) {
1046 String name = vpath + newfiles[i];
1047 File file = new File(dir, newfiles[i]);
1048 (file.isDirectory()
1049 ? dirsExcluded : filesExcluded).addElement(name);
1050 } else {
1051 noLinks.addElement(newfiles[i]);
1052 }
1053 } catch (IOException ioe) {
1054 String msg = "IOException caught while checking "
1055 + "for links, couldn't get canonical path!";
1056 // will be caught and redirected to Ant's logging system
1057 System.err.println(msg);
1058 noLinks.addElement(newfiles[i]);
1059 }
1060 }
1061 newfiles = new String[noLinks.size()];
1062 noLinks.copyInto(newfiles);
1063 }
1064 for (int i = 0; i < newfiles.length; i++) {
1065 String name = vpath + newfiles[i];
1066 File file = new File(dir, newfiles[i]);
1067 if (file.isDirectory()) {
1068 if (isIncluded(name)) {
1069 accountForIncludedDir(name, file, fast);
1070 } else {
1071 everythingIncluded = false;
1072 dirsNotIncluded.addElement(name);
1073 if (fast && couldHoldIncluded(name)) {
1074 scandir(file, name + File.separator, fast);
1075 }
1076 }
1077 if (!fast) {
1078 scandir(file, name + File.separator, fast);
1079 }
1080 } else if (file.isFile()) {
1081 if (isIncluded(name)) {
1082 accountForIncludedFile(name, file);
1083 } else {
1084 everythingIncluded = false;
1085 filesNotIncluded.addElement(name);
1086 }
1087 }
1088 }
1089 }
1090
1091 /**
1092 * Process included file.
1093 * @param name path of the file relative to the directory of the FileSet.
1094 * @param file included File.
1095 */
1096 private void accountForIncludedFile(String name, File file) {
1097 if (filesIncluded.contains(name)
1098 || filesExcluded.contains(name)
1099 || filesDeselected.contains(name)) {
1100 return;
1101 }
1102 boolean included = false;
1103 if (isExcluded(name)) {
1104 filesExcluded.addElement(name);
1105 } else if (isSelected(name, file)) {
1106 included = true;
1107 filesIncluded.addElement(name);
1108 } else {
1109 filesDeselected.addElement(name);
1110 }
1111 everythingIncluded &= included;
1112 }
1113
1114 /**
1115 * Process included directory.
1116 * @param name path of the directory relative to the directory of
1117 * the FileSet.
1118 * @param file directory as File.
1119 * @param fast whether to perform fast scans.
1120 */
1121 private void accountForIncludedDir(String name, File file, boolean fast) {
1122 if (dirsIncluded.contains(name)
1123 || dirsExcluded.contains(name)
1124 || dirsDeselected.contains(name)) {
1125 return;
1126 }
1127 boolean included = false;
1128 if (isExcluded(name)) {
1129 dirsExcluded.addElement(name);
1130 } else if (isSelected(name, file)) {
1131 included = true;
1132 dirsIncluded.addElement(name);
1133 } else {
1134 dirsDeselected.addElement(name);
1135 }
1136 everythingIncluded &= included;
1137 if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) {
1138 scandir(file, name + File.separator, fast);
1139 }
1140 }
1141
1142 /**
1143 * Test whether or not a name matches against at least one include
1144 * pattern.
1145 *
1146 * @param name The name to match. Must not be <code>null</code>.
1147 * @return <code>true</code> when the name matches against at least one
1148 * include pattern, or <code>false</code> otherwise.
1149 */
1150 protected boolean isIncluded(String name) {
1151 ensureNonPatternSetsReady();
1152
1153 if (isCaseSensitive()
1154 ? includeNonPatterns.contains(name)
1155 : includeNonPatterns.contains(name.toUpperCase())) {
1156 return true;
1157 }
1158 for (int i = 0; i < includePatterns.length; i++) {
1159 if (matchPath(includePatterns[i], name, isCaseSensitive())) {
1160 return true;
1161 }
1162 }
1163 return false;
1164 }
1165
1166 /**
1167 * Test whether or not a name matches the start of at least one include
1168 * pattern.
1169 *
1170 * @param name The name to match. Must not be <code>null</code>.
1171 * @return <code>true</code> when the name matches against the start of at
1172 * least one include pattern, or <code>false</code> otherwise.
1173 */
1174 protected boolean couldHoldIncluded(String name) {
1175 for (int i = 0; i < includes.length; i++) {
1176 if (matchPatternStart(includes[i], name, isCaseSensitive())
1177 && isMorePowerfulThanExcludes(name, includes[i])
1178 && isDeeper(includes[i], name)) {
1179 return true;
1180 }
1181 }
1182 return false;
1183 }
1184
1185 /**
1186 * Verify that a pattern specifies files deeper
1187 * than the level of the specified file.
1188 * @param pattern the pattern to check.
1189 * @param name the name to check.
1190 * @return whether the pattern is deeper than the name.
1191 * @since Ant 1.6.3
1192 */
1193 private boolean isDeeper(String pattern, String name) {
1194 Vector p = SelectorUtils.tokenizePath(pattern);
1195 Vector n = SelectorUtils.tokenizePath(name);
1196 return p.contains("**") || p.size() > n.size();
1197 }
1198
1199 /**
1200 * Find out whether one particular include pattern is more powerful
1201 * than all the excludes.
1202 * Note: the power comparison is based on the length of the include pattern
1203 * and of the exclude patterns without the wildcards.
1204 * Ideally the comparison should be done based on the depth
1205 * of the match; that is to say how many file separators have been matched
1206 * before the first ** or the end of the pattern.
1207 *
1208 * IMPORTANT : this function should return false "with care".
1209 *
1210 * @param name the relative path to test.
1211 * @param includepattern one include pattern.
1212 * @return true if there is no exclude pattern more powerful than this include pattern.
1213 * @since Ant 1.6
1214 */
1215 private boolean isMorePowerfulThanExcludes(String name, String includepattern) {
1216 String soughtexclude = name + File.separator + "**";
1217 for (int counter = 0; counter < excludes.length; counter++) {
1218 if (excludes[counter].equals(soughtexclude)) {
1219 return false;
1220 }
1221 }
1222 return true;
1223 }
1224
1225 /**
1226 * Test whether all contents of the specified directory must be excluded.
1227 * @param name the directory name to check.
1228 * @return whether all the specified directory's contents are excluded.
1229 */
1230 private boolean contentsExcluded(String name) {
1231 name = (name.endsWith(File.separator)) ? name : name + File.separator;
1232 for (int i = 0; i < excludes.length; i++) {
1233 String e = excludes[i];
1234 if (e.endsWith("**") && SelectorUtils.matchPath(
1235 e.substring(0, e.length() - 2), name, isCaseSensitive())) {
1236 return true;
1237 }
1238 }
1239 return false;
1240 }
1241
1242 /**
1243 * Test whether or not a name matches against at least one exclude
1244 * pattern.
1245 *
1246 * @param name The name to match. Must not be <code>null</code>.
1247 * @return <code>true</code> when the name matches against at least one
1248 * exclude pattern, or <code>false</code> otherwise.
1249 */
1250 protected boolean isExcluded(String name) {
1251 ensureNonPatternSetsReady();
1252
1253 if (isCaseSensitive()
1254 ? excludeNonPatterns.contains(name)
1255 : excludeNonPatterns.contains(name.toUpperCase())) {
1256 return true;
1257 }
1258 for (int i = 0; i < excludePatterns.length; i++) {
1259 if (matchPath(excludePatterns[i], name, isCaseSensitive())) {
1260 return true;
1261 }
1262 }
1263 return false;
1264 }
1265
1266 /**
1267 * Test whether a file should be selected.
1268 *
1269 * @param name the filename to check for selecting.
1270 * @param file the java.io.File object for this filename.
1271 * @return <code>false</code> when the selectors says that the file
1272 * should not be selected, <code>true</code> otherwise.
1273 */
1274 protected boolean isSelected(String name, File file) {
1275 if (selectors != null) {
1276 for (int i = 0; i < selectors.length; i++) {
1277 if (!selectors[i].isSelected(basedir, name, file)) {
1278 return false;
1279 }
1280 }
1281 }
1282 return true;
1283 }
1284
1285 /**
1286 * Return the names of the files which matched at least one of the
1287 * include patterns and none of the exclude patterns.
1288 * The names are relative to the base directory.
1289 *
1290 * @return the names of the files which matched at least one of the
1291 * include patterns and none of the exclude patterns.
1292 */
1293 public synchronized String[] getIncludedFiles() {
1294 if (filesIncluded == null) {
1295 throw new IllegalStateException();
1296 }
1297 String[] files = new String[filesIncluded.size()];
1298 filesIncluded.copyInto(files);
1299 Arrays.sort(files);
1300 return files;
1301 }
1302
1303 /**
1304 * Return the count of included files.
1305 * @return <code>int</code>.
1306 * @since Ant 1.6.3
1307 */
1308 public synchronized int getIncludedFilesCount() {
1309 if (filesIncluded == null) {
1310 throw new IllegalStateException();
1311 }
1312 return filesIncluded.size();
1313 }
1314
1315 /**
1316 * Return the names of the files which matched none of the include
1317 * patterns. The names are relative to the base directory. This involves
1318 * performing a slow scan if one has not already been completed.
1319 *
1320 * @return the names of the files which matched none of the include
1321 * patterns.
1322 *
1323 * @see #slowScan
1324 */
1325 public synchronized String[] getNotIncludedFiles() {
1326 slowScan();
1327 String[] files = new String[filesNotIncluded.size()];
1328 filesNotIncluded.copyInto(files);
1329 return files;
1330 }
1331
1332 /**
1333 * Return the names of the files which matched at least one of the
1334 * include patterns and at least one of the exclude patterns.
1335 * The names are relative to the base directory. This involves
1336 * performing a slow scan if one has not already been completed.
1337 *
1338 * @return the names of the files which matched at least one of the
1339 * include patterns and at least one of the exclude patterns.
1340 *
1341 * @see #slowScan
1342 */
1343 public synchronized String[] getExcludedFiles() {
1344 slowScan();
1345 String[] files = new String[filesExcluded.size()];
1346 filesExcluded.copyInto(files);
1347 return files;
1348 }
1349
1350 /**
1351 * <p>Return the names of the files which were selected out and
1352 * therefore not ultimately included.</p>
1353 *
1354 * <p>The names are relative to the base directory. This involves
1355 * performing a slow scan if one has not already been completed.</p>
1356 *
1357 * @return the names of the files which were deselected.
1358 *
1359 * @see #slowScan
1360 */
1361 public synchronized String[] getDeselectedFiles() {
1362 slowScan();
1363 String[] files = new String[filesDeselected.size()];
1364 filesDeselected.copyInto(files);
1365 return files;
1366 }
1367
1368 /**
1369 * Return the names of the directories which matched at least one of the
1370 * include patterns and none of the exclude patterns.
1371 * The names are relative to the base directory.
1372 *
1373 * @return the names of the directories which matched at least one of the
1374 * include patterns and none of the exclude patterns.
1375 */
1376 public synchronized String[] getIncludedDirectories() {
1377 if (dirsIncluded == null) {
1378 throw new IllegalStateException();
1379 }
1380 String[] directories = new String[dirsIncluded.size()];
1381 dirsIncluded.copyInto(directories);
1382 Arrays.sort(directories);
1383 return directories;
1384 }
1385
1386 /**
1387 * Return the count of included directories.
1388 * @return <code>int</code>.
1389 * @since Ant 1.6.3
1390 */
1391 public synchronized int getIncludedDirsCount() {
1392 if (dirsIncluded == null) {
1393 throw new IllegalStateException();
1394 }
1395 return dirsIncluded.size();
1396 }
1397
1398 /**
1399 * Return the names of the directories which matched none of the include
1400 * patterns. The names are relative to the base directory. This involves
1401 * performing a slow scan if one has not already been completed.
1402 *
1403 * @return the names of the directories which matched none of the include
1404 * patterns.
1405 *
1406 * @see #slowScan
1407 */
1408 public synchronized String[] getNotIncludedDirectories() {
1409 slowScan();
1410 String[] directories = new String[dirsNotIncluded.size()];
1411 dirsNotIncluded.copyInto(directories);
1412 return directories;
1413 }
1414
1415 /**
1416 * Return the names of the directories which matched at least one of the
1417 * include patterns and at least one of the exclude patterns.
1418 * The names are relative to the base directory. This involves
1419 * performing a slow scan if one has not already been completed.
1420 *
1421 * @return the names of the directories which matched at least one of the
1422 * include patterns and at least one of the exclude patterns.
1423 *
1424 * @see #slowScan
1425 */
1426 public synchronized String[] getExcludedDirectories() {
1427 slowScan();
1428 String[] directories = new String[dirsExcluded.size()];
1429 dirsExcluded.copyInto(directories);
1430 return directories;
1431 }
1432
1433 /**
1434 * <p>Return the names of the directories which were selected out and
1435 * therefore not ultimately included.</p>
1436 *
1437 * <p>The names are relative to the base directory. This involves
1438 * performing a slow scan if one has not already been completed.</p>
1439 *
1440 * @return the names of the directories which were deselected.
1441 *
1442 * @see #slowScan
1443 */
1444 public synchronized String[] getDeselectedDirectories() {
1445 slowScan();
1446 String[] directories = new String[dirsDeselected.size()];
1447 dirsDeselected.copyInto(directories);
1448 return directories;
1449 }
1450
1451 /**
1452 * Add default exclusions to the current exclusions set.
1453 */
1454 public synchronized void addDefaultExcludes() {
1455 int excludesLength = excludes == null ? 0 : excludes.length;
1456 String[] newExcludes;
1457 newExcludes = new String[excludesLength + defaultExcludes.size()];
1458 if (excludesLength > 0) {
1459 System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
1460 }
1461 String[] defaultExcludesTemp = getDefaultExcludes();
1462 for (int i = 0; i < defaultExcludesTemp.length; i++) {
1463 newExcludes[i + excludesLength] =
1464 defaultExcludesTemp[i].replace('/', File.separatorChar)
1465 .replace('\\', File.separatorChar);
1466 }
1467 excludes = newExcludes;
1468 }
1469
1470 /**
1471 * Get the named resource.
1472 * @param name path name of the file relative to the dir attribute.
1473 *
1474 * @return the resource with the given name.
1475 * @since Ant 1.5.2
1476 */
1477 public synchronized Resource getResource(String name) {
1478 File f = FILE_UTILS.resolveFile(basedir, name);
1479 return new Resource(name, f.exists(), f.lastModified(),
1480 f.isDirectory(), f.length());
1481 }
1482
1483 /**
1484 * Return a cached result of list performed on file, if
1485 * available. Invokes the method and caches the result otherwise.
1486 *
1487 * @param file File (dir) to list.
1488 * @since Ant 1.6
1489 */
1490 private String[] list(File file) {
1491 String[] files = (String[]) fileListMap.get(file);
1492 if (files == null) {
1493 files = file.list();
1494 if (files != null) {
1495 fileListMap.put(file, files);
1496 }
1497 }
1498 return files;
1499 }
1500
1501 /**
1502 * From <code>base</code> traverse the filesystem in order to find
1503 * a file that matches the given name.
1504 *
1505 * @param base base File (dir).
1506 * @param path file path.
1507 * @param cs whether to scan case-sensitively.
1508 * @return File object that points to the file in question or null.
1509 *
1510 * @since Ant 1.6.3
1511 */
1512 private File findFile(File base, String path, boolean cs) {
1513 return findFile(base, SelectorUtils.tokenizePath(path), cs);
1514 }
1515
1516 /**
1517 * From <code>base</code> traverse the filesystem in order to find
1518 * a file that matches the given stack of names.
1519 *
1520 * @param base base File (dir).
1521 * @param pathElements Vector of path elements (dirs...file).
1522 * @param cs whether to scan case-sensitively.
1523 * @return File object that points to the file in question or null.
1524 *
1525 * @since Ant 1.6.3
1526 */
1527 private File findFile(File base, Vector pathElements, boolean cs) {
1528 if (pathElements.size() == 0) {
1529 return base;
1530 }
1531 if (!base.isDirectory()) {
1532 return null;
1533 }
1534 String[] files = list(base);
1535 if (files == null) {
1536 throw new BuildException("IO error scanning directory "
1537 + base.getAbsolutePath());
1538 }
1539 String current = (String) pathElements.remove(0);
1540
1541 boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
1542 for (int i = 0; i < matchCase.length; i++) {
1543 for (int j = 0; j < files.length; j++) {
1544 if (matchCase[i] ? files[j].equals(current)
1545 : files[j].equalsIgnoreCase(current)) {
1546 return findFile(new File(base, files[j]), pathElements, cs);
1547 }
1548 }
1549 }
1550 return null;
1551 }
1552
1553 /**
1554 * Do we have to traverse a symlink when trying to reach path from
1555 * basedir?
1556 * @param base base File (dir).
1557 * @param path file path.
1558 * @since Ant 1.6
1559 */
1560 private boolean isSymlink(File base, String path) {
1561 return isSymlink(base, SelectorUtils.tokenizePath(path));
1562 }
1563
1564 /**
1565 * Do we have to traverse a symlink when trying to reach path from
1566 * basedir?
1567 * @param base base File (dir).
1568 * @param pathElements Vector of path elements (dirs...file).
1569 * @since Ant 1.6
1570 */
1571 private boolean isSymlink(File base, Vector pathElements) {
1572 if (pathElements.size() > 0) {
1573 String current = (String) pathElements.remove(0);
1574 try {
1575 return FILE_UTILS.isSymbolicLink(base, current)
1576 || isSymlink(new File(base, current), pathElements);
1577 } catch (IOException ioe) {
1578 String msg = "IOException caught while checking "
1579 + "for links, couldn't get canonical path!";
1580 // will be caught and redirected to Ant's logging system
1581 System.err.println(msg);
1582 }
1583 }
1584 return false;
1585 }
1586
1587 /**
1588 * Has the directory with the given path relative to the base
1589 * directory already been scanned?
1590 *
1591 * <p>Registers the given directory as scanned as a side effect.</p>
1592 *
1593 * @since Ant 1.6
1594 */
1595 private boolean hasBeenScanned(String vpath) {
1596 return !scannedDirs.add(vpath);
1597 }
1598
1599 /**
1600 * This method is of interest for testing purposes. The returned
1601 * Set is live and should not be modified.
1602 * @return the Set of relative directory names that have been scanned.
1603 */
1604 /* package-private */ Set getScannedDirs() {
1605 return scannedDirs;
1606 }
1607
1608 /**
1609 * Clear internal caches.
1610 *
1611 * @since Ant 1.6
1612 */
1613 private synchronized void clearCaches() {
1614 fileListMap.clear();
1615 includeNonPatterns.clear();
1616 excludeNonPatterns.clear();
1617 includePatterns = null;
1618 excludePatterns = null;
1619 areNonPatternSetsReady = false;
1620 }
1621
1622 /**
1623 * Ensure that the in|exclude &quot;patterns&quot;
1624 * have been properly divided up.
1625 *
1626 * @since Ant 1.6.3
1627 */
1628 private synchronized void ensureNonPatternSetsReady() {
1629 if (!areNonPatternSetsReady) {
1630 includePatterns = fillNonPatternSet(includeNonPatterns, includes);
1631 excludePatterns = fillNonPatternSet(excludeNonPatterns, excludes);
1632 areNonPatternSetsReady = true;
1633 }
1634 }
1635
1636 /**
1637 * Add all patterns that are not real patterns (do not contain
1638 * wildcards) to the set and returns the real patterns.
1639 *
1640 * @param set Set to populate.
1641 * @param patterns String[] of patterns.
1642 * @since Ant 1.6.3
1643 */
1644 private String[] fillNonPatternSet(Set set, String[] patterns) {
1645 ArrayList al = new ArrayList(patterns.length);
1646 for (int i = 0; i < patterns.length; i++) {
1647 if (!SelectorUtils.hasWildcards(patterns[i])) {
1648 set.add(isCaseSensitive() ? patterns[i]
1649 : patterns[i].toUpperCase());
1650 } else {
1651 al.add(patterns[i]);
1652 }
1653 }
1654 return set.size() == 0 ? patterns
1655 : (String[]) al.toArray(new String[al.size()]);
1656 }
1657
1658}
Note: See TracBrowser for help on using the repository browser.