You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

DirectoryScanner.java 50 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /*
  2. * Copyright 2000-2004 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. package org.apache.tools.ant;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.util.Arrays;
  21. import java.util.Enumeration;
  22. import java.util.HashMap;
  23. import java.util.HashSet;
  24. import java.util.Hashtable;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.Vector;
  28. import org.apache.tools.ant.taskdefs.condition.Os;
  29. import org.apache.tools.ant.types.Resource;
  30. import org.apache.tools.ant.types.ResourceFactory;
  31. import org.apache.tools.ant.types.selectors.FileSelector;
  32. import org.apache.tools.ant.types.selectors.SelectorScanner;
  33. import org.apache.tools.ant.types.selectors.SelectorUtils;
  34. import org.apache.tools.ant.util.FileUtils;
  35. /**
  36. * Class for scanning a directory for files/directories which match certain
  37. * criteria.
  38. * <p>
  39. * These criteria consist of selectors and patterns which have been specified.
  40. * With the selectors you can select which files you want to have included.
  41. * Files which are not selected are excluded. With patterns you can include
  42. * or exclude files based on their filename.
  43. * <p>
  44. * The idea is simple. A given directory is recursively scanned for all files
  45. * and directories. Each file/directory is matched against a set of selectors,
  46. * including special support for matching against filenames with include and
  47. * and exclude patterns. Only files/directories which match at least one
  48. * pattern of the include pattern list or other file selector, and don't match
  49. * any pattern of the exclude pattern list or fail to match against a required
  50. * selector will be placed in the list of files/directories found.
  51. * <p>
  52. * When no list of include patterns is supplied, "**" will be used, which
  53. * means that everything will be matched. When no list of exclude patterns is
  54. * supplied, an empty list is used, such that nothing will be excluded. When
  55. * no selectors are supplied, none are applied.
  56. * <p>
  57. * The filename pattern matching is done as follows:
  58. * The name to be matched is split up in path segments. A path segment is the
  59. * name of a directory or file, which is bounded by
  60. * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
  61. * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
  62. * "def","ghi" and "xyz.java".
  63. * The same is done for the pattern against which should be matched.
  64. * <p>
  65. * The segments of the name and the pattern are then matched against each
  66. * other. When '**' is used for a path segment in the pattern, it matches
  67. * zero or more path segments of the name.
  68. * <p>
  69. * There is a special case regarding the use of <code>File.separator</code>s
  70. * at the beginning of the pattern and the string to match:<br>
  71. * When a pattern starts with a <code>File.separator</code>, the string
  72. * to match must also start with a <code>File.separator</code>.
  73. * When a pattern does not start with a <code>File.separator</code>, the
  74. * string to match may not start with a <code>File.separator</code>.
  75. * When one of these rules is not obeyed, the string will not
  76. * match.
  77. * <p>
  78. * When a name path segment is matched against a pattern path segment, the
  79. * following special characters can be used:<br>
  80. * '*' matches zero or more characters<br>
  81. * '?' matches one character.
  82. * <p>
  83. * Examples:
  84. * <p>
  85. * "**\*.class" matches all .class files/dirs in a directory tree.
  86. * <p>
  87. * "test\a??.java" matches all files/dirs which start with an 'a', then two
  88. * more characters and then ".java", in a directory called test.
  89. * <p>
  90. * "**" matches everything in a directory tree.
  91. * <p>
  92. * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
  93. * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
  94. * <p>
  95. * Case sensitivity may be turned off if necessary. By default, it is
  96. * turned on.
  97. * <p>
  98. * Example of usage:
  99. * <pre>
  100. * String[] includes = {"**\\*.class"};
  101. * String[] excludes = {"modules\\*\\**"};
  102. * ds.setIncludes(includes);
  103. * ds.setExcludes(excludes);
  104. * ds.setBasedir(new File("test"));
  105. * ds.setCaseSensitive(true);
  106. * ds.scan();
  107. *
  108. * System.out.println("FILES:");
  109. * String[] files = ds.getIncludedFiles();
  110. * for (int i = 0; i < files.length; i++) {
  111. * System.out.println(files[i]);
  112. * }
  113. * </pre>
  114. * This will scan a directory called test for .class files, but excludes all
  115. * files in all proper subdirectories of a directory called "modules"
  116. *
  117. * @author Arnout J. Kuiper
  118. * <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
  119. * @author Magesh Umasankar
  120. * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
  121. * @author <a href="mailto:levylambert@tiscali-dsl.de">Antoine Levy-Lambert</a>
  122. */
  123. public class DirectoryScanner
  124. implements FileScanner, SelectorScanner, ResourceFactory {
  125. /** Is OpenVMS the operating system we're running on? */
  126. private static final boolean ON_VMS = Os.isFamily("openvms");
  127. /**
  128. * Patterns which should be excluded by default.
  129. *
  130. * <p>Note that you can now add patterns to the list of default
  131. * excludes. Added patterns will not become part of this array
  132. * that has only been kept around for backwards compatibility
  133. * reasons.</p>
  134. *
  135. * @deprecated use the {@link #getDefaultExcludes
  136. * getDefaultExcludes} method instead.
  137. */
  138. protected static final String[] DEFAULTEXCLUDES = {
  139. // Miscellaneous typical temporary files
  140. "**/*~",
  141. "**/#*#",
  142. "**/.#*",
  143. "**/%*%",
  144. "**/._*",
  145. // CVS
  146. "**/CVS",
  147. "**/CVS/**",
  148. "**/.cvsignore",
  149. // SCCS
  150. "**/SCCS",
  151. "**/SCCS/**",
  152. // Visual SourceSafe
  153. "**/vssver.scc",
  154. // Subversion
  155. "**/.svn",
  156. "**/.svn/**",
  157. // Mac
  158. "**/.DS_Store"
  159. };
  160. /**
  161. * Patterns which should be excluded by default.
  162. *
  163. * @see #addDefaultExcludes()
  164. */
  165. private static Vector defaultExcludes = new Vector();
  166. static {
  167. resetDefaultExcludes();
  168. }
  169. /** The base directory to be scanned. */
  170. protected File basedir;
  171. /** The patterns for the files to be included. */
  172. protected String[] includes;
  173. /** The patterns for the files to be excluded. */
  174. protected String[] excludes;
  175. /** Selectors that will filter which files are in our candidate list. */
  176. protected FileSelector[] selectors = null;
  177. /** The files which matched at least one include and no excludes
  178. * and were selected.
  179. */
  180. protected Vector filesIncluded;
  181. /** The files which did not match any includes or selectors. */
  182. protected Vector filesNotIncluded;
  183. /**
  184. * The files which matched at least one include and at least
  185. * one exclude.
  186. */
  187. protected Vector filesExcluded;
  188. /** The directories which matched at least one include and no excludes
  189. * and were selected.
  190. */
  191. protected Vector dirsIncluded;
  192. /** The directories which were found and did not match any includes. */
  193. protected Vector dirsNotIncluded;
  194. /**
  195. * The directories which matched at least one include and at least one
  196. * exclude.
  197. */
  198. protected Vector dirsExcluded;
  199. /** The files which matched at least one include and no excludes and
  200. * which a selector discarded.
  201. */
  202. protected Vector filesDeselected;
  203. /** The directories which matched at least one include and no excludes
  204. * but which a selector discarded.
  205. */
  206. protected Vector dirsDeselected;
  207. /** Whether or not our results were built by a slow scan. */
  208. protected boolean haveSlowResults = false;
  209. /**
  210. * Whether or not the file system should be treated as a case sensitive
  211. * one.
  212. */
  213. protected boolean isCaseSensitive = true;
  214. /**
  215. * Whether or not symbolic links should be followed.
  216. *
  217. * @since Ant 1.5
  218. */
  219. private boolean followSymlinks = true;
  220. /** Helper. */
  221. private static final FileUtils fileUtils = FileUtils.newFileUtils();
  222. /** Whether or not everything tested so far has been included. */
  223. protected boolean everythingIncluded = true;
  224. /**
  225. * Sole constructor.
  226. */
  227. public DirectoryScanner() {
  228. }
  229. /**
  230. * Tests whether or not a given path matches the start of a given
  231. * pattern up to the first "**".
  232. * <p>
  233. * This is not a general purpose test and should only be used if you
  234. * can live with false positives. For example, <code>pattern=**\a</code>
  235. * and <code>str=b</code> will yield <code>true</code>.
  236. *
  237. * @param pattern The pattern to match against. Must not be
  238. * <code>null</code>.
  239. * @param str The path to match, as a String. Must not be
  240. * <code>null</code>.
  241. *
  242. * @return whether or not a given path matches the start of a given
  243. * pattern up to the first "**".
  244. */
  245. protected static boolean matchPatternStart(String pattern, String str) {
  246. return SelectorUtils.matchPatternStart(pattern, str);
  247. }
  248. /**
  249. * Tests whether or not a given path matches the start of a given
  250. * pattern up to the first "**".
  251. * <p>
  252. * This is not a general purpose test and should only be used if you
  253. * can live with false positives. For example, <code>pattern=**\a</code>
  254. * and <code>str=b</code> will yield <code>true</code>.
  255. *
  256. * @param pattern The pattern to match against. Must not be
  257. * <code>null</code>.
  258. * @param str The path to match, as a String. Must not be
  259. * <code>null</code>.
  260. * @param isCaseSensitive Whether or not matching should be performed
  261. * case sensitively.
  262. *
  263. * @return whether or not a given path matches the start of a given
  264. * pattern up to the first "**".
  265. */
  266. protected static boolean matchPatternStart(String pattern, String str,
  267. boolean isCaseSensitive) {
  268. return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
  269. }
  270. /**
  271. * Tests whether or not a given path matches a given pattern.
  272. *
  273. * @param pattern The pattern to match against. Must not be
  274. * <code>null</code>.
  275. * @param str The path to match, as a String. Must not be
  276. * <code>null</code>.
  277. *
  278. * @return <code>true</code> if the pattern matches against the string,
  279. * or <code>false</code> otherwise.
  280. */
  281. protected static boolean matchPath(String pattern, String str) {
  282. return SelectorUtils.matchPath(pattern, str);
  283. }
  284. /**
  285. * Tests whether or not a given path matches a given pattern.
  286. *
  287. * @param pattern The pattern to match against. Must not be
  288. * <code>null</code>.
  289. * @param str The path to match, as a String. Must not be
  290. * <code>null</code>.
  291. * @param isCaseSensitive Whether or not matching should be performed
  292. * case sensitively.
  293. *
  294. * @return <code>true</code> if the pattern matches against the string,
  295. * or <code>false</code> otherwise.
  296. */
  297. protected static boolean matchPath(String pattern, String str,
  298. boolean isCaseSensitive) {
  299. return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
  300. }
  301. /**
  302. * Tests whether or not a string matches against a pattern.
  303. * The pattern may contain two special characters:<br>
  304. * '*' means zero or more characters<br>
  305. * '?' means one and only one character
  306. *
  307. * @param pattern The pattern to match against.
  308. * Must not be <code>null</code>.
  309. * @param str The string which must be matched against the pattern.
  310. * Must not be <code>null</code>.
  311. *
  312. * @return <code>true</code> if the string matches against the pattern,
  313. * or <code>false</code> otherwise.
  314. */
  315. public static boolean match(String pattern, String str) {
  316. return SelectorUtils.match(pattern, str);
  317. }
  318. /**
  319. * Tests whether or not a string matches against a pattern.
  320. * The pattern may contain two special characters:<br>
  321. * '*' means zero or more characters<br>
  322. * '?' means one and only one character
  323. *
  324. * @param pattern The pattern to match against.
  325. * Must not be <code>null</code>.
  326. * @param str The string which must be matched against the pattern.
  327. * Must not be <code>null</code>.
  328. * @param isCaseSensitive Whether or not matching should be performed
  329. * case sensitively.
  330. *
  331. *
  332. * @return <code>true</code> if the string matches against the pattern,
  333. * or <code>false</code> otherwise.
  334. */
  335. protected static boolean match(String pattern, String str,
  336. boolean isCaseSensitive) {
  337. return SelectorUtils.match(pattern, str, isCaseSensitive);
  338. }
  339. /**
  340. * Get the list of patterns that should be excluded by default.
  341. *
  342. * @return An array of <code>String</code> based on the current
  343. * contents of the <code>defaultExcludes</code>
  344. * <code>Vector</code>.
  345. *
  346. * @since Ant 1.6
  347. */
  348. public static String[] getDefaultExcludes() {
  349. return (String[]) defaultExcludes.toArray(new String[defaultExcludes
  350. .size()]);
  351. }
  352. /**
  353. * Add a pattern to the default excludes unless it is already a
  354. * default exclude.
  355. *
  356. * @param s A string to add as an exclude pattern.
  357. * @return <code>true</code> if the string was added
  358. * <code>false</code> if it already
  359. * existed.
  360. *
  361. * @since Ant 1.6
  362. */
  363. public static boolean addDefaultExclude(String s) {
  364. if (defaultExcludes.indexOf(s) == -1) {
  365. defaultExcludes.add(s);
  366. return true;
  367. }
  368. return false;
  369. }
  370. /**
  371. * Remove a string if it is a default exclude.
  372. *
  373. * @param s The string to attempt to remove.
  374. * @return <code>true</code> if <code>s</code> was a default
  375. * exclude (and thus was removed),
  376. * <code>false</code> if <code>s</code> was not
  377. * in the default excludes list to begin with
  378. *
  379. * @since Ant 1.6
  380. */
  381. public static boolean removeDefaultExclude(String s) {
  382. return defaultExcludes.remove(s);
  383. }
  384. /**
  385. * Go back to the hard wired default exclude patterns
  386. *
  387. * @since Ant 1.6
  388. */
  389. public static void resetDefaultExcludes() {
  390. defaultExcludes = new Vector();
  391. for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
  392. defaultExcludes.add(DEFAULTEXCLUDES[i]);
  393. }
  394. }
  395. /**
  396. * Sets the base directory to be scanned. This is the directory which is
  397. * scanned recursively. All '/' and '\' characters are replaced by
  398. * <code>File.separatorChar</code>, so the separator used need not match
  399. * <code>File.separatorChar</code>.
  400. *
  401. * @param basedir The base directory to scan.
  402. * Must not be <code>null</code>.
  403. */
  404. public void setBasedir(String basedir) {
  405. setBasedir(new File(basedir.replace('/', File.separatorChar).replace(
  406. '\\', File.separatorChar)));
  407. }
  408. /**
  409. * Sets the base directory to be scanned. This is the directory which is
  410. * scanned recursively.
  411. *
  412. * @param basedir The base directory for scanning.
  413. * Should not be <code>null</code>.
  414. */
  415. public void setBasedir(File basedir) {
  416. this.basedir = basedir;
  417. }
  418. /**
  419. * Returns the base directory to be scanned.
  420. * This is the directory which is scanned recursively.
  421. *
  422. * @return the base directory to be scanned
  423. */
  424. public File getBasedir() {
  425. return basedir;
  426. }
  427. /**
  428. * Find out whether include exclude patterns are matched in a
  429. * case sensitive way
  430. * @return whether or not the scanning is case sensitive
  431. * @since ant 1.6
  432. */
  433. public boolean isCaseSensitive() {
  434. return isCaseSensitive;
  435. }
  436. /**
  437. * Sets whether or not include and exclude patterns are matched
  438. * in a case sensitive way
  439. *
  440. * @param isCaseSensitive whether or not the file system should be
  441. * regarded as a case sensitive one
  442. */
  443. public void setCaseSensitive(boolean isCaseSensitive) {
  444. this.isCaseSensitive = isCaseSensitive;
  445. }
  446. /**
  447. * gets whether or not a DirectoryScanner follows symbolic links
  448. *
  449. * @return flag indicating whether symbolic links should be followed
  450. *
  451. * @since ant 1.6
  452. */
  453. public boolean isFollowSymlinks() {
  454. return followSymlinks;
  455. }
  456. /**
  457. * Sets whether or not symbolic links should be followed.
  458. *
  459. * @param followSymlinks whether or not symbolic links should be followed
  460. */
  461. public void setFollowSymlinks(boolean followSymlinks) {
  462. this.followSymlinks = followSymlinks;
  463. }
  464. /**
  465. * Sets the list of include patterns to use. All '/' and '\' characters
  466. * are replaced by <code>File.separatorChar</code>, so the separator used
  467. * need not match <code>File.separatorChar</code>.
  468. * <p>
  469. * When a pattern ends with a '/' or '\', "**" is appended.
  470. *
  471. * @param includes A list of include patterns.
  472. * May be <code>null</code>, indicating that all files
  473. * should be included. If a non-<code>null</code>
  474. * list is given, all elements must be
  475. * non-<code>null</code>.
  476. */
  477. public void setIncludes(String[] includes) {
  478. if (includes == null) {
  479. this.includes = null;
  480. } else {
  481. this.includes = new String[includes.length];
  482. for (int i = 0; i < includes.length; i++) {
  483. String pattern;
  484. pattern = includes[i].replace('/', File.separatorChar).replace(
  485. '\\', File.separatorChar);
  486. if (pattern.endsWith(File.separator)) {
  487. pattern += "**";
  488. }
  489. this.includes[i] = pattern;
  490. }
  491. }
  492. }
  493. /**
  494. * Sets the list of exclude patterns to use. All '/' and '\' characters
  495. * are replaced by <code>File.separatorChar</code>, so the separator used
  496. * need not match <code>File.separatorChar</code>.
  497. * <p>
  498. * When a pattern ends with a '/' or '\', "**" is appended.
  499. *
  500. * @param excludes A list of exclude patterns.
  501. * May be <code>null</code>, indicating that no files
  502. * should be excluded. If a non-<code>null</code> list is
  503. * given, all elements must be non-<code>null</code>.
  504. */
  505. public void setExcludes(String[] excludes) {
  506. if (excludes == null) {
  507. this.excludes = null;
  508. } else {
  509. this.excludes = new String[excludes.length];
  510. for (int i = 0; i < excludes.length; i++) {
  511. String pattern;
  512. pattern = excludes[i].replace('/', File.separatorChar).replace(
  513. '\\', File.separatorChar);
  514. if (pattern.endsWith(File.separator)) {
  515. pattern += "**";
  516. }
  517. this.excludes[i] = pattern;
  518. }
  519. }
  520. }
  521. /**
  522. * Sets the selectors that will select the filelist.
  523. *
  524. * @param selectors specifies the selectors to be invoked on a scan
  525. */
  526. public void setSelectors(FileSelector[] selectors) {
  527. this.selectors = selectors;
  528. }
  529. /**
  530. * Returns whether or not the scanner has included all the files or
  531. * directories it has come across so far.
  532. *
  533. * @return <code>true</code> if all files and directories which have
  534. * been found so far have been included.
  535. */
  536. public boolean isEverythingIncluded() {
  537. return everythingIncluded;
  538. }
  539. /**
  540. * Scans the base directory for files which match at least one include
  541. * pattern and don't match any exclude patterns. If there are selectors
  542. * then the files must pass muster there, as well.
  543. *
  544. * @exception IllegalStateException if the base directory was set
  545. * incorrectly (i.e. if it is <code>null</code>, doesn't exist,
  546. * or isn't a directory).
  547. */
  548. public void scan() throws IllegalStateException {
  549. if (basedir == null) {
  550. throw new IllegalStateException("No basedir set");
  551. }
  552. if (!basedir.exists()) {
  553. throw new IllegalStateException("basedir " + basedir
  554. + " does not exist");
  555. }
  556. if (!basedir.isDirectory()) {
  557. throw new IllegalStateException("basedir " + basedir
  558. + " is not a directory");
  559. }
  560. if (includes == null) {
  561. // No includes supplied, so set it to 'matches all'
  562. includes = new String[1];
  563. includes[0] = "**";
  564. }
  565. if (excludes == null) {
  566. excludes = new String[0];
  567. }
  568. filesIncluded = new Vector();
  569. filesNotIncluded = new Vector();
  570. filesExcluded = new Vector();
  571. filesDeselected = new Vector();
  572. dirsIncluded = new Vector();
  573. dirsNotIncluded = new Vector();
  574. dirsExcluded = new Vector();
  575. dirsDeselected = new Vector();
  576. if (isIncluded("")) {
  577. if (!isExcluded("")) {
  578. if (isSelected("", basedir)) {
  579. dirsIncluded.addElement("");
  580. } else {
  581. dirsDeselected.addElement("");
  582. }
  583. } else {
  584. dirsExcluded.addElement("");
  585. }
  586. } else {
  587. dirsNotIncluded.addElement("");
  588. }
  589. checkIncludePatterns();
  590. clearCaches();
  591. }
  592. /**
  593. * this routine is actually checking all the include patterns in
  594. * order to avoid scanning everything under base dir
  595. * @since ant1.6
  596. */
  597. private void checkIncludePatterns() {
  598. Hashtable newroots = new Hashtable();
  599. // put in the newroots vector the include patterns without
  600. // wildcard tokens
  601. for (int icounter = 0; icounter < includes.length; icounter++) {
  602. String newpattern =
  603. SelectorUtils.rtrimWildcardTokens(includes[icounter]);
  604. newroots.put(newpattern, includes[icounter]);
  605. }
  606. if (newroots.containsKey("")) {
  607. // we are going to scan everything anyway
  608. scandir(basedir, "", true);
  609. } else {
  610. // only scan directories that can include matched files or
  611. // directories
  612. Enumeration enum2 = newroots.keys();
  613. File canonBase = null;
  614. try {
  615. canonBase = basedir.getCanonicalFile();
  616. } catch (IOException ex) {
  617. throw new BuildException(ex);
  618. }
  619. while (enum2.hasMoreElements()) {
  620. String currentelement = (String) enum2.nextElement();
  621. String originalpattern = (String) newroots.get(currentelement);
  622. File myfile = new File(basedir, currentelement);
  623. if (myfile.exists()) {
  624. // may be on a case insensitive file system. We want
  625. // the results to show what's really on the disk, so
  626. // we need to double check.
  627. try {
  628. File canonFile = myfile.getCanonicalFile();
  629. String path = fileUtils.removeLeadingPath(canonBase,
  630. canonFile);
  631. if (!path.equals(currentelement) || ON_VMS) {
  632. myfile = findFile(basedir, currentelement);
  633. if (myfile != null) {
  634. currentelement =
  635. fileUtils.removeLeadingPath(basedir,
  636. myfile);
  637. }
  638. }
  639. } catch (IOException ex) {
  640. throw new BuildException(ex);
  641. }
  642. }
  643. if ((myfile == null || !myfile.exists()) && !isCaseSensitive) {
  644. File f = findFileCaseInsensitive(basedir, currentelement);
  645. if (f.exists()) {
  646. // adapt currentelement to the case we've
  647. // actually found
  648. currentelement = fileUtils.removeLeadingPath(basedir,
  649. f);
  650. myfile = f;
  651. }
  652. }
  653. if (myfile != null && myfile.exists()) {
  654. if (!followSymlinks
  655. && isSymlink(basedir, currentelement)) {
  656. continue;
  657. }
  658. if (myfile.isDirectory()) {
  659. if (isIncluded(currentelement)
  660. && currentelement.length() > 0) {
  661. accountForIncludedDir(currentelement, myfile, true);
  662. } else {
  663. if (currentelement.length() > 0) {
  664. if (currentelement.charAt(currentelement
  665. .length() - 1)
  666. != File.separatorChar) {
  667. currentelement =
  668. currentelement + File.separatorChar;
  669. }
  670. }
  671. scandir(myfile, currentelement, true);
  672. }
  673. } else {
  674. if (isCaseSensitive
  675. && originalpattern.equals(currentelement)) {
  676. accountForIncludedFile(currentelement, myfile);
  677. } else if (!isCaseSensitive
  678. && originalpattern
  679. .equalsIgnoreCase(currentelement)) {
  680. accountForIncludedFile(currentelement, myfile);
  681. }
  682. }
  683. }
  684. }
  685. }
  686. }
  687. /**
  688. * Top level invocation for a slow scan. A slow scan builds up a full
  689. * list of excluded/included files/directories, whereas a fast scan
  690. * will only have full results for included files, as it ignores
  691. * directories which can't possibly hold any included files/directories.
  692. * <p>
  693. * Returns immediately if a slow scan has already been completed.
  694. */
  695. protected void slowScan() {
  696. if (haveSlowResults) {
  697. return;
  698. }
  699. String[] excl = new String[dirsExcluded.size()];
  700. dirsExcluded.copyInto(excl);
  701. String[] notIncl = new String[dirsNotIncluded.size()];
  702. dirsNotIncluded.copyInto(notIncl);
  703. for (int i = 0; i < excl.length; i++) {
  704. if (!couldHoldIncluded(excl[i])) {
  705. scandir(new File(basedir, excl[i]),
  706. excl[i] + File.separator, false);
  707. }
  708. }
  709. for (int i = 0; i < notIncl.length; i++) {
  710. if (!couldHoldIncluded(notIncl[i])) {
  711. scandir(new File(basedir, notIncl[i]),
  712. notIncl[i] + File.separator, false);
  713. }
  714. }
  715. haveSlowResults = true;
  716. }
  717. /**
  718. * Scans the given directory for files and directories. Found files and
  719. * directories are placed in their respective collections, based on the
  720. * matching of includes, excludes, and the selectors. When a directory
  721. * is found, it is scanned recursively.
  722. *
  723. * @param dir The directory to scan. Must not be <code>null</code>.
  724. * @param vpath The path relative to the base directory (needed to
  725. * prevent problems with an absolute path when using
  726. * dir). Must not be <code>null</code>.
  727. * @param fast Whether or not this call is part of a fast scan.
  728. *
  729. * @see #filesIncluded
  730. * @see #filesNotIncluded
  731. * @see #filesExcluded
  732. * @see #dirsIncluded
  733. * @see #dirsNotIncluded
  734. * @see #dirsExcluded
  735. * @see #slowScan
  736. */
  737. protected void scandir(File dir, String vpath, boolean fast) {
  738. if (dir == null) {
  739. throw new BuildException("dir must not be null.");
  740. } else if (!dir.exists()) {
  741. throw new BuildException(dir + " doesn't exists.");
  742. } else if (!dir.isDirectory()) {
  743. throw new BuildException(dir + " is not a directory.");
  744. }
  745. // avoid double scanning of directories, can only happen in fast mode
  746. if (fast && hasBeenScanned(vpath)) {
  747. return;
  748. }
  749. String[] newfiles = dir.list();
  750. if (newfiles == null) {
  751. /*
  752. * two reasons are mentioned in the API docs for File.list
  753. * (1) dir is not a directory. This is impossible as
  754. * we wouldn't get here in this case.
  755. * (2) an IO error occurred (why doesn't it throw an exception
  756. * then???)
  757. */
  758. throw new BuildException("IO error scanning directory "
  759. + dir.getAbsolutePath());
  760. }
  761. if (!followSymlinks) {
  762. Vector noLinks = new Vector();
  763. for (int i = 0; i < newfiles.length; i++) {
  764. try {
  765. if (fileUtils.isSymbolicLink(dir, newfiles[i])) {
  766. String name = vpath + newfiles[i];
  767. File file = new File(dir, newfiles[i]);
  768. if (file.isDirectory()) {
  769. dirsExcluded.addElement(name);
  770. } else {
  771. filesExcluded.addElement(name);
  772. }
  773. } else {
  774. noLinks.addElement(newfiles[i]);
  775. }
  776. } catch (IOException ioe) {
  777. String msg = "IOException caught while checking "
  778. + "for links, couldn't get canonical path!";
  779. // will be caught and redirected to Ant's logging system
  780. System.err.println(msg);
  781. noLinks.addElement(newfiles[i]);
  782. }
  783. }
  784. newfiles = new String[noLinks.size()];
  785. noLinks.copyInto(newfiles);
  786. }
  787. for (int i = 0; i < newfiles.length; i++) {
  788. String name = vpath + newfiles[i];
  789. File file = new File(dir, newfiles[i]);
  790. if (file.isDirectory()) {
  791. if (isIncluded(name)) {
  792. accountForIncludedDir(name, file, fast);
  793. } else {
  794. everythingIncluded = false;
  795. dirsNotIncluded.addElement(name);
  796. if (fast && couldHoldIncluded(name)) {
  797. scandir(file, name + File.separator, fast);
  798. }
  799. }
  800. if (!fast) {
  801. scandir(file, name + File.separator, fast);
  802. }
  803. } else if (file.isFile()) {
  804. if (isIncluded(name)) {
  805. accountForIncludedFile(name, file);
  806. } else {
  807. everythingIncluded = false;
  808. filesNotIncluded.addElement(name);
  809. }
  810. }
  811. }
  812. }
  813. /**
  814. * process included file
  815. * @param name path of the file relative to the directory of the fileset
  816. * @param file included file
  817. */
  818. private void accountForIncludedFile(String name, File file) {
  819. if (!filesIncluded.contains(name)
  820. && !filesExcluded.contains(name)
  821. && !filesDeselected.contains(name)) {
  822. if (!isExcluded(name)) {
  823. if (isSelected(name, file)) {
  824. filesIncluded.addElement(name);
  825. } else {
  826. everythingIncluded = false;
  827. filesDeselected.addElement(name);
  828. }
  829. } else {
  830. everythingIncluded = false;
  831. filesExcluded.addElement(name);
  832. }
  833. }
  834. }
  835. /**
  836. *
  837. * @param name path of the directory relative to the directory of
  838. * the fileset
  839. * @param file directory as file
  840. * @param fast
  841. */
  842. private void accountForIncludedDir(String name, File file, boolean fast) {
  843. if (!dirsIncluded.contains(name)
  844. && !dirsExcluded.contains(name)
  845. && !dirsDeselected.contains(name)) {
  846. if (!isExcluded(name)) {
  847. if (isSelected(name, file)) {
  848. dirsIncluded.addElement(name);
  849. if (fast) {
  850. scandir(file, name + File.separator, fast);
  851. }
  852. } else {
  853. everythingIncluded = false;
  854. dirsDeselected.addElement(name);
  855. if (fast && couldHoldIncluded(name)) {
  856. scandir(file, name + File.separator, fast);
  857. }
  858. }
  859. } else {
  860. everythingIncluded = false;
  861. dirsExcluded.addElement(name);
  862. if (fast && couldHoldIncluded(name)) {
  863. scandir(file, name + File.separator, fast);
  864. }
  865. }
  866. }
  867. }
  868. /**
  869. * Tests whether or not a name matches against at least one include
  870. * pattern.
  871. *
  872. * @param name The name to match. Must not be <code>null</code>.
  873. * @return <code>true</code> when the name matches against at least one
  874. * include pattern, or <code>false</code> otherwise.
  875. */
  876. protected boolean isIncluded(String name) {
  877. for (int i = 0; i < includes.length; i++) {
  878. if (matchPath(includes[i], name, isCaseSensitive)) {
  879. return true;
  880. }
  881. }
  882. return false;
  883. }
  884. /**
  885. * Tests whether or not a name matches the start of at least one include
  886. * pattern.
  887. *
  888. * @param name The name to match. Must not be <code>null</code>.
  889. * @return <code>true</code> when the name matches against the start of at
  890. * least one include pattern, or <code>false</code> otherwise.
  891. */
  892. protected boolean couldHoldIncluded(String name) {
  893. for (int i = 0; i < includes.length; i++) {
  894. if (matchPatternStart(includes[i], name, isCaseSensitive)) {
  895. if (isMorePowerfulThanExcludes(name, includes[i])) {
  896. return true;
  897. }
  898. }
  899. }
  900. return false;
  901. }
  902. /**
  903. * find out whether one particular include pattern is more powerful
  904. * than all the excludes
  905. * note : the power comparison is based on the length of the include pattern
  906. * and of the exclude patterns without the wildcards
  907. * ideally the comparison should be done based on the depth
  908. * of the match, that is to say how many file separators have been matched
  909. * before the first ** or the end of the pattern
  910. *
  911. * IMPORTANT : this function should return false "with care"
  912. *
  913. * @param name the relative path that one want to test
  914. * @param includepattern one include pattern
  915. * @return true if there is no exclude pattern more powerful than this include pattern
  916. * @since ant1.6
  917. */
  918. private boolean isMorePowerfulThanExcludes(String name, String includepattern) {
  919. String soughtexclude = name + File.separator + "**";
  920. for (int counter = 0; counter < excludes.length; counter++) {
  921. if (excludes[counter].equals(soughtexclude)) {
  922. return false;
  923. }
  924. }
  925. return true;
  926. }
  927. /**
  928. * Tests whether or not a name matches against at least one exclude
  929. * pattern.
  930. *
  931. * @param name The name to match. Must not be <code>null</code>.
  932. * @return <code>true</code> when the name matches against at least one
  933. * exclude pattern, or <code>false</code> otherwise.
  934. */
  935. protected boolean isExcluded(String name) {
  936. for (int i = 0; i < excludes.length; i++) {
  937. if (matchPath(excludes[i], name, isCaseSensitive)) {
  938. return true;
  939. }
  940. }
  941. return false;
  942. }
  943. /**
  944. * Tests whether a name should be selected.
  945. *
  946. * @param name the filename to check for selecting
  947. * @param file the java.io.File object for this filename
  948. * @return <code>false</code> when the selectors says that the file
  949. * should not be selected, <code>true</code> otherwise.
  950. */
  951. protected boolean isSelected(String name, File file) {
  952. if (selectors != null) {
  953. for (int i = 0; i < selectors.length; i++) {
  954. if (!selectors[i].isSelected(basedir, name, file)) {
  955. return false;
  956. }
  957. }
  958. }
  959. return true;
  960. }
  961. /**
  962. * Returns the names of the files which matched at least one of the
  963. * include patterns and none of the exclude patterns.
  964. * The names are relative to the base directory.
  965. *
  966. * @return the names of the files which matched at least one of the
  967. * include patterns and none of the exclude patterns.
  968. */
  969. public String[] getIncludedFiles() {
  970. String[] files = new String[filesIncluded.size()];
  971. filesIncluded.copyInto(files);
  972. Arrays.sort(files);
  973. return files;
  974. }
  975. /**
  976. * Returns the names of the files which matched none of the include
  977. * patterns. The names are relative to the base directory. This involves
  978. * performing a slow scan if one has not already been completed.
  979. *
  980. * @return the names of the files which matched none of the include
  981. * patterns.
  982. *
  983. * @see #slowScan
  984. */
  985. public String[] getNotIncludedFiles() {
  986. slowScan();
  987. String[] files = new String[filesNotIncluded.size()];
  988. filesNotIncluded.copyInto(files);
  989. return files;
  990. }
  991. /**
  992. * Returns the names of the files which matched at least one of the
  993. * include patterns and at least one of the exclude patterns.
  994. * The names are relative to the base directory. This involves
  995. * performing a slow scan if one has not already been completed.
  996. *
  997. * @return the names of the files which matched at least one of the
  998. * include patterns and at least one of the exclude patterns.
  999. *
  1000. * @see #slowScan
  1001. */
  1002. public String[] getExcludedFiles() {
  1003. slowScan();
  1004. String[] files = new String[filesExcluded.size()];
  1005. filesExcluded.copyInto(files);
  1006. return files;
  1007. }
  1008. /**
  1009. * <p>Returns the names of the files which were selected out and
  1010. * therefore not ultimately included.</p>
  1011. *
  1012. * <p>The names are relative to the base directory. This involves
  1013. * performing a slow scan if one has not already been completed.</p>
  1014. *
  1015. * @return the names of the files which were deselected.
  1016. *
  1017. * @see #slowScan
  1018. */
  1019. public String[] getDeselectedFiles() {
  1020. slowScan();
  1021. String[] files = new String[filesDeselected.size()];
  1022. filesDeselected.copyInto(files);
  1023. return files;
  1024. }
  1025. /**
  1026. * Returns the names of the directories which matched at least one of the
  1027. * include patterns and none of the exclude patterns.
  1028. * The names are relative to the base directory.
  1029. *
  1030. * @return the names of the directories which matched at least one of the
  1031. * include patterns and none of the exclude patterns.
  1032. */
  1033. public String[] getIncludedDirectories() {
  1034. String[] directories = new String[dirsIncluded.size()];
  1035. dirsIncluded.copyInto(directories);
  1036. Arrays.sort(directories);
  1037. return directories;
  1038. }
  1039. /**
  1040. * Returns the names of the directories which matched none of the include
  1041. * patterns. The names are relative to the base directory. This involves
  1042. * performing a slow scan if one has not already been completed.
  1043. *
  1044. * @return the names of the directories which matched none of the include
  1045. * patterns.
  1046. *
  1047. * @see #slowScan
  1048. */
  1049. public String[] getNotIncludedDirectories() {
  1050. slowScan();
  1051. String[] directories = new String[dirsNotIncluded.size()];
  1052. dirsNotIncluded.copyInto(directories);
  1053. return directories;
  1054. }
  1055. /**
  1056. * Returns the names of the directories which matched at least one of the
  1057. * include patterns and at least one of the exclude patterns.
  1058. * The names are relative to the base directory. This involves
  1059. * performing a slow scan if one has not already been completed.
  1060. *
  1061. * @return the names of the directories which matched at least one of the
  1062. * include patterns and at least one of the exclude patterns.
  1063. *
  1064. * @see #slowScan
  1065. */
  1066. public String[] getExcludedDirectories() {
  1067. slowScan();
  1068. String[] directories = new String[dirsExcluded.size()];
  1069. dirsExcluded.copyInto(directories);
  1070. return directories;
  1071. }
  1072. /**
  1073. * <p>Returns the names of the directories which were selected out and
  1074. * therefore not ultimately included.</p>
  1075. *
  1076. * <p>The names are relative to the base directory. This involves
  1077. * performing a slow scan if one has not already been completed.</p>
  1078. *
  1079. * @return the names of the directories which were deselected.
  1080. *
  1081. * @see #slowScan
  1082. */
  1083. public String[] getDeselectedDirectories() {
  1084. slowScan();
  1085. String[] directories = new String[dirsDeselected.size()];
  1086. dirsDeselected.copyInto(directories);
  1087. return directories;
  1088. }
  1089. /**
  1090. * Adds default exclusions to the current exclusions set.
  1091. */
  1092. public void addDefaultExcludes() {
  1093. int excludesLength = excludes == null ? 0 : excludes.length;
  1094. String[] newExcludes;
  1095. newExcludes = new String[excludesLength + defaultExcludes.size()];
  1096. if (excludesLength > 0) {
  1097. System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
  1098. }
  1099. String[] defaultExcludesTemp = getDefaultExcludes();
  1100. for (int i = 0; i < defaultExcludesTemp.length; i++) {
  1101. newExcludes[i + excludesLength] =
  1102. defaultExcludesTemp[i].replace('/', File.separatorChar)
  1103. .replace('\\', File.separatorChar);
  1104. }
  1105. excludes = newExcludes;
  1106. }
  1107. /**
  1108. * Get the named resource
  1109. * @param name path name of the file relative to the dir attribute.
  1110. *
  1111. * @return the resource with the given name.
  1112. * @since Ant 1.5.2
  1113. */
  1114. public Resource getResource(String name) {
  1115. File f = fileUtils.resolveFile(basedir, name);
  1116. return new Resource(name, f.exists(), f.lastModified(),
  1117. f.isDirectory());
  1118. }
  1119. /**
  1120. * temporary table to speed up the various scanning methods below
  1121. *
  1122. * @since Ant 1.6
  1123. */
  1124. private Map fileListMap = new HashMap();
  1125. /**
  1126. * Returns a cached result of list performed on file, if
  1127. * available. Invokes the method and caches the result otherwise.
  1128. *
  1129. * @since Ant 1.6
  1130. */
  1131. private String[] list(File file) {
  1132. String[] files = (String[]) fileListMap.get(file);
  1133. if (files == null) {
  1134. files = file.list();
  1135. if (files != null) {
  1136. fileListMap.put(file, files);
  1137. }
  1138. }
  1139. return files;
  1140. }
  1141. /**
  1142. * From <code>base</code> traverse the filesystem in a case
  1143. * insensitive manner in order to find a file that matches the
  1144. * given name.
  1145. *
  1146. * @return File object that points to the file in question. if it
  1147. * hasn't been found it will simply be <code>new File(base,
  1148. * path)</code>.
  1149. *
  1150. * @since Ant 1.6
  1151. */
  1152. private File findFileCaseInsensitive(File base, String path) {
  1153. File f = findFileCaseInsensitive(base,
  1154. SelectorUtils.tokenizePath(path));
  1155. return f == null ? new File(base, path) : f;
  1156. }
  1157. /**
  1158. * From <code>base</code> traverse the filesystem in a case
  1159. * insensitive manner in order to find a file that matches the
  1160. * given stack of names.
  1161. *
  1162. * @return File object that points to the file in question or null.
  1163. *
  1164. * @since Ant 1.6
  1165. */
  1166. private File findFileCaseInsensitive(File base, Vector pathElements) {
  1167. if (pathElements.size() == 0) {
  1168. return base;
  1169. } else {
  1170. if (!base.isDirectory()) {
  1171. return null;
  1172. }
  1173. String[] files = list(base);
  1174. if (files == null) {
  1175. throw new BuildException("IO error scanning directory "
  1176. + base.getAbsolutePath());
  1177. }
  1178. String current = (String) pathElements.remove(0);
  1179. for (int i = 0; i < files.length; i++) {
  1180. if (files[i].equals(current)) {
  1181. base = new File(base, files[i]);
  1182. return findFileCaseInsensitive(base, pathElements);
  1183. }
  1184. }
  1185. for (int i = 0; i < files.length; i++) {
  1186. if (files[i].equalsIgnoreCase(current)) {
  1187. base = new File(base, files[i]);
  1188. return findFileCaseInsensitive(base, pathElements);
  1189. }
  1190. }
  1191. }
  1192. return null;
  1193. }
  1194. /**
  1195. * From <code>base</code> traverse the filesystem in order to find
  1196. * a file that matches the given name.
  1197. *
  1198. * @return File object that points to the file in question or null.
  1199. *
  1200. * @since Ant 1.6
  1201. */
  1202. private File findFile(File base, String path) {
  1203. return findFile(base, SelectorUtils.tokenizePath(path));
  1204. }
  1205. /**
  1206. * From <code>base</code> traverse the filesystem in order to find
  1207. * a file that matches the given stack of names.
  1208. *
  1209. * @return File object that points to the file in question or null.
  1210. *
  1211. * @since Ant 1.6
  1212. */
  1213. private File findFile(File base, Vector pathElements) {
  1214. if (pathElements.size() == 0) {
  1215. return base;
  1216. } else {
  1217. if (!base.isDirectory()) {
  1218. return null;
  1219. }
  1220. String[] files = list(base);
  1221. if (files == null) {
  1222. throw new BuildException("IO error scanning directory "
  1223. + base.getAbsolutePath());
  1224. }
  1225. String current = (String) pathElements.remove(0);
  1226. for (int i = 0; i < files.length; i++) {
  1227. if (files[i].equals(current)) {
  1228. base = new File(base, files[i]);
  1229. return findFile(base, pathElements);
  1230. }
  1231. }
  1232. }
  1233. return null;
  1234. }
  1235. /**
  1236. * Do we have to traverse a symlink when trying to reach path from
  1237. * basedir?
  1238. * @since Ant 1.6
  1239. */
  1240. private boolean isSymlink(File base, String path) {
  1241. return isSymlink(base, SelectorUtils.tokenizePath(path));
  1242. }
  1243. /**
  1244. * Do we have to traverse a symlink when trying to reach path from
  1245. * basedir?
  1246. * @since Ant 1.6
  1247. */
  1248. private boolean isSymlink(File base, Vector pathElements) {
  1249. if (pathElements.size() > 0) {
  1250. String current = (String) pathElements.remove(0);
  1251. try {
  1252. if (fileUtils.isSymbolicLink(base, current)) {
  1253. return true;
  1254. } else {
  1255. base = new File(base, current);
  1256. return isSymlink(base, pathElements);
  1257. }
  1258. } catch (IOException ioe) {
  1259. String msg = "IOException caught while checking "
  1260. + "for links, couldn't get canonical path!";
  1261. // will be caught and redirected to Ant's logging system
  1262. System.err.println(msg);
  1263. return false;
  1264. }
  1265. }
  1266. return false;
  1267. }
  1268. /**
  1269. * List of all scanned directories.
  1270. *
  1271. * @since Ant 1.6
  1272. */
  1273. private Set scannedDirs = new HashSet();
  1274. /**
  1275. * Has the directory with the given path relative to the base
  1276. * directory already been scanned?
  1277. *
  1278. * <p>Registers the given directory as scanned as a side effect.</p>
  1279. *
  1280. * @since Ant 1.6
  1281. */
  1282. private boolean hasBeenScanned(String vpath) {
  1283. return !scannedDirs.add(vpath);
  1284. }
  1285. /**
  1286. * Clear internal caches.
  1287. *
  1288. * @since Ant 1.6
  1289. */
  1290. private void clearCaches() {
  1291. fileListMap.clear();
  1292. scannedDirs.clear();
  1293. }
  1294. }