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 58 kB

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