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.

Delete.java 29 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant.taskdefs;
  19. import java.io.File;
  20. import java.util.Arrays;
  21. import java.util.Comparator;
  22. import java.util.Iterator;
  23. import java.util.Vector;
  24. import org.apache.tools.ant.BuildException;
  25. import org.apache.tools.ant.DirectoryScanner;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.taskdefs.condition.Os;
  28. import org.apache.tools.ant.types.FileSet;
  29. import org.apache.tools.ant.types.PatternSet;
  30. import org.apache.tools.ant.types.Resource;
  31. import org.apache.tools.ant.types.ResourceCollection;
  32. import org.apache.tools.ant.types.resources.FileProvider;
  33. import org.apache.tools.ant.types.resources.FileResourceIterator;
  34. import org.apache.tools.ant.types.resources.Resources;
  35. import org.apache.tools.ant.types.resources.Restrict;
  36. import org.apache.tools.ant.types.resources.Sort;
  37. import org.apache.tools.ant.types.resources.comparators.FileSystem;
  38. import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
  39. import org.apache.tools.ant.types.resources.comparators.Reverse;
  40. import org.apache.tools.ant.types.resources.selectors.Exists;
  41. import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
  42. import org.apache.tools.ant.types.selectors.AndSelector;
  43. import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
  44. import org.apache.tools.ant.types.selectors.ContainsSelector;
  45. import org.apache.tools.ant.types.selectors.DateSelector;
  46. import org.apache.tools.ant.types.selectors.DependSelector;
  47. import org.apache.tools.ant.types.selectors.DepthSelector;
  48. import org.apache.tools.ant.types.selectors.ExtendSelector;
  49. import org.apache.tools.ant.types.selectors.FileSelector;
  50. import org.apache.tools.ant.types.selectors.FilenameSelector;
  51. import org.apache.tools.ant.types.selectors.MajoritySelector;
  52. import org.apache.tools.ant.types.selectors.NoneSelector;
  53. import org.apache.tools.ant.types.selectors.NotSelector;
  54. import org.apache.tools.ant.types.selectors.OrSelector;
  55. import org.apache.tools.ant.types.selectors.PresentSelector;
  56. import org.apache.tools.ant.types.selectors.SelectSelector;
  57. import org.apache.tools.ant.types.selectors.SizeSelector;
  58. import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
  59. import org.apache.tools.ant.util.FileUtils;
  60. import org.apache.tools.ant.util.SymbolicLinkUtils;
  61. /**
  62. * Deletes a file or directory, or set of files defined by a fileset.
  63. * The original delete task would delete a file, or a set of files
  64. * using the include/exclude syntax. The deltree task would delete a
  65. * directory tree. This task combines the functionality of these two
  66. * originally distinct tasks.
  67. * <p>Currently Delete extends MatchingTask. This is intended <i>only</i>
  68. * to provide backwards compatibility for a release. The future position
  69. * is to use nested filesets exclusively.</p>
  70. *
  71. * @since Ant 1.2
  72. *
  73. * @ant.task category="filesystem"
  74. */
  75. public class Delete extends MatchingTask {
  76. private static final ResourceComparator REVERSE_FILESYSTEM = new Reverse(new FileSystem());
  77. private static final ResourceSelector EXISTS = new Exists();
  78. private static class ReverseDirs implements ResourceCollection {
  79. static final Comparator<Comparable<?>> REVERSE = new Comparator<Comparable<?>>() {
  80. public int compare(Comparable<?> foo, Comparable<?> bar) {
  81. return ((Comparable) foo).compareTo(bar) * -1;
  82. }
  83. };
  84. private Project project;
  85. private File basedir;
  86. private String[] dirs;
  87. ReverseDirs(Project project, File basedir, String[] dirs) {
  88. this.project = project;
  89. this.basedir = basedir;
  90. this.dirs = dirs;
  91. Arrays.sort(this.dirs, REVERSE);
  92. }
  93. public Iterator<Resource> iterator() {
  94. return new FileResourceIterator(project, basedir, dirs);
  95. }
  96. public boolean isFilesystemOnly() { return true; }
  97. public int size() { return dirs.length; }
  98. }
  99. // CheckStyle:VisibilityModifier OFF - bc
  100. protected File file = null;
  101. protected File dir = null;
  102. protected Vector<FileSet> filesets = new Vector<FileSet>();
  103. protected boolean usedMatchingTask = false;
  104. // by default, remove matching empty dirs
  105. protected boolean includeEmpty = false;
  106. // CheckStyle:VisibilityModifier ON
  107. private int verbosity = Project.MSG_VERBOSE;
  108. private boolean quiet = false;
  109. private boolean failonerror = true;
  110. private boolean deleteOnExit = false;
  111. private boolean removeNotFollowedSymlinks = false;
  112. private Resources rcs = null;
  113. private static FileUtils FILE_UTILS = FileUtils.getFileUtils();
  114. private static SymbolicLinkUtils SYMLINK_UTILS =
  115. SymbolicLinkUtils.getSymbolicLinkUtils();
  116. private boolean performGc = Os.isFamily("windows");
  117. /**
  118. * Set the name of a single file to be removed.
  119. *
  120. * @param file the file to be deleted
  121. */
  122. public void setFile(File file) {
  123. this.file = file;
  124. }
  125. /**
  126. * Set the directory from which files are to be deleted
  127. *
  128. * @param dir the directory path.
  129. */
  130. public void setDir(File dir) {
  131. this.dir = dir;
  132. getImplicitFileSet().setDir(dir);
  133. }
  134. /**
  135. * If true, list all names of deleted files.
  136. *
  137. * @param verbose "true" or "on"
  138. */
  139. public void setVerbose(boolean verbose) {
  140. if (verbose) {
  141. this.verbosity = Project.MSG_INFO;
  142. } else {
  143. this.verbosity = Project.MSG_VERBOSE;
  144. }
  145. }
  146. /**
  147. * If true and the file does not exist, do not display a diagnostic
  148. * message or modify the exit status to reflect an error.
  149. * This means that if a file or directory cannot be deleted,
  150. * then no error is reported. This setting emulates the
  151. * -f option to the Unix &quot;rm&quot; command.
  152. * Default is false meaning things are &quot;noisy&quot;
  153. * @param quiet "true" or "on"
  154. */
  155. public void setQuiet(boolean quiet) {
  156. this.quiet = quiet;
  157. if (quiet) {
  158. this.failonerror = false;
  159. }
  160. }
  161. /**
  162. * If false, note errors but continue.
  163. *
  164. * @param failonerror true or false
  165. */
  166. public void setFailOnError(boolean failonerror) {
  167. this.failonerror = failonerror;
  168. }
  169. /**
  170. * If true, on failure to delete, note the error and set
  171. * the deleteonexit flag, and continue
  172. *
  173. * @param deleteOnExit true or false
  174. */
  175. public void setDeleteOnExit(boolean deleteOnExit) {
  176. this.deleteOnExit = deleteOnExit;
  177. }
  178. /**
  179. * If true, delete empty directories.
  180. * @param includeEmpty if true delete empty directories (only
  181. * for filesets). Default is false.
  182. */
  183. public void setIncludeEmptyDirs(boolean includeEmpty) {
  184. this.includeEmpty = includeEmpty;
  185. }
  186. /**
  187. * Whether to perform a garbage collection before retrying a failed delete.
  188. *
  189. * <p>This may be required on Windows (where it is set to true by
  190. * default) but also on other operating systems, for example when
  191. * deleting directories from an NFS share.</p>
  192. *
  193. * @param b boolean
  194. * @since Ant 1.8.3
  195. */
  196. public void setPerformGcOnFailedDelete(boolean b) {
  197. performGc = b;
  198. }
  199. /**
  200. * Adds a set of files to be deleted.
  201. * @param set the set of files to be deleted
  202. */
  203. public void addFileset(FileSet set) {
  204. filesets.addElement(set);
  205. }
  206. /**
  207. * Add an arbitrary ResourceCollection to be deleted.
  208. * @param rc the filesystem-only ResourceCollection.
  209. */
  210. public void add(ResourceCollection rc) {
  211. if (rc == null) {
  212. return;
  213. }
  214. if (rcs == null) {
  215. rcs = new Resources();
  216. rcs.setCache(true);
  217. }
  218. rcs.add(rc);
  219. }
  220. /**
  221. * add a name entry on the include list
  222. * @return a NameEntry object to be configured
  223. */
  224. public PatternSet.NameEntry createInclude() {
  225. usedMatchingTask = true;
  226. return super.createInclude();
  227. }
  228. /**
  229. * add a name entry on the include files list
  230. * @return a NameEntry object to be configured
  231. */
  232. public PatternSet.NameEntry createIncludesFile() {
  233. usedMatchingTask = true;
  234. return super.createIncludesFile();
  235. }
  236. /**
  237. * add a name entry on the exclude list
  238. * @return a NameEntry object to be configured
  239. */
  240. public PatternSet.NameEntry createExclude() {
  241. usedMatchingTask = true;
  242. return super.createExclude();
  243. }
  244. /**
  245. * add a name entry on the include files list
  246. * @return a NameEntry object to be configured
  247. */
  248. public PatternSet.NameEntry createExcludesFile() {
  249. usedMatchingTask = true;
  250. return super.createExcludesFile();
  251. }
  252. /**
  253. * add a set of patterns
  254. * @return PatternSet object to be configured
  255. */
  256. public PatternSet createPatternSet() {
  257. usedMatchingTask = true;
  258. return super.createPatternSet();
  259. }
  260. /**
  261. * Sets the set of include patterns. Patterns may be separated by a comma
  262. * or a space.
  263. *
  264. * @param includes the string containing the include patterns
  265. */
  266. public void setIncludes(String includes) {
  267. usedMatchingTask = true;
  268. super.setIncludes(includes);
  269. }
  270. /**
  271. * Sets the set of exclude patterns. Patterns may be separated by a comma
  272. * or a space.
  273. *
  274. * @param excludes the string containing the exclude patterns
  275. */
  276. public void setExcludes(String excludes) {
  277. usedMatchingTask = true;
  278. super.setExcludes(excludes);
  279. }
  280. /**
  281. * Sets whether default exclusions should be used or not.
  282. *
  283. * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
  284. * should be used, "false"|"off"|"no" when they
  285. * shouldn't be used.
  286. */
  287. public void setDefaultexcludes(boolean useDefaultExcludes) {
  288. usedMatchingTask = true;
  289. super.setDefaultexcludes(useDefaultExcludes);
  290. }
  291. /**
  292. * Sets the name of the file containing the includes patterns.
  293. *
  294. * @param includesfile A string containing the filename to fetch
  295. * the include patterns from.
  296. */
  297. public void setIncludesfile(File includesfile) {
  298. usedMatchingTask = true;
  299. super.setIncludesfile(includesfile);
  300. }
  301. /**
  302. * Sets the name of the file containing the includes patterns.
  303. *
  304. * @param excludesfile A string containing the filename to fetch
  305. * the include patterns from.
  306. */
  307. public void setExcludesfile(File excludesfile) {
  308. usedMatchingTask = true;
  309. super.setExcludesfile(excludesfile);
  310. }
  311. /**
  312. * Sets case sensitivity of the file system
  313. *
  314. * @param isCaseSensitive "true"|"on"|"yes" if file system is case
  315. * sensitive, "false"|"off"|"no" when not.
  316. */
  317. public void setCaseSensitive(boolean isCaseSensitive) {
  318. usedMatchingTask = true;
  319. super.setCaseSensitive(isCaseSensitive);
  320. }
  321. /**
  322. * Sets whether or not symbolic links should be followed.
  323. *
  324. * @param followSymlinks whether or not symbolic links should be followed
  325. */
  326. public void setFollowSymlinks(boolean followSymlinks) {
  327. usedMatchingTask = true;
  328. super.setFollowSymlinks(followSymlinks);
  329. }
  330. /**
  331. * Sets whether the symbolic links that have not been followed
  332. * shall be removed (the links, not the locations they point at).
  333. *
  334. * @param b boolean
  335. * @since Ant 1.8.0
  336. */
  337. public void setRemoveNotFollowedSymlinks(boolean b) {
  338. removeNotFollowedSymlinks = b;
  339. }
  340. /**
  341. * add a "Select" selector entry on the selector list
  342. *
  343. * @param selector the selector to be added
  344. */
  345. public void addSelector(SelectSelector selector) {
  346. usedMatchingTask = true;
  347. super.addSelector(selector);
  348. }
  349. /**
  350. * add an "And" selector entry on the selector list
  351. *
  352. * @param selector the selector to be added
  353. */
  354. public void addAnd(AndSelector selector) {
  355. usedMatchingTask = true;
  356. super.addAnd(selector);
  357. }
  358. /**
  359. * add an "Or" selector entry on the selector list
  360. *
  361. * @param selector the selector to be added
  362. */
  363. public void addOr(OrSelector selector) {
  364. usedMatchingTask = true;
  365. super.addOr(selector);
  366. }
  367. /**
  368. * add a "Not" selector entry on the selector list
  369. *
  370. * @param selector the selector to be added
  371. */
  372. public void addNot(NotSelector selector) {
  373. usedMatchingTask = true;
  374. super.addNot(selector);
  375. }
  376. /**
  377. * add a "None" selector entry on the selector list
  378. *
  379. * @param selector the selector to be added
  380. */
  381. public void addNone(NoneSelector selector) {
  382. usedMatchingTask = true;
  383. super.addNone(selector);
  384. }
  385. /**
  386. * add a majority selector entry on the selector list
  387. *
  388. * @param selector the selector to be added
  389. */
  390. public void addMajority(MajoritySelector selector) {
  391. usedMatchingTask = true;
  392. super.addMajority(selector);
  393. }
  394. /**
  395. * add a selector date entry on the selector list
  396. *
  397. * @param selector the selector to be added
  398. */
  399. public void addDate(DateSelector selector) {
  400. usedMatchingTask = true;
  401. super.addDate(selector);
  402. }
  403. /**
  404. * add a selector size entry on the selector list
  405. *
  406. * @param selector the selector to be added
  407. */
  408. public void addSize(SizeSelector selector) {
  409. usedMatchingTask = true;
  410. super.addSize(selector);
  411. }
  412. /**
  413. * add a selector filename entry on the selector list
  414. *
  415. * @param selector the selector to be added
  416. */
  417. public void addFilename(FilenameSelector selector) {
  418. usedMatchingTask = true;
  419. super.addFilename(selector);
  420. }
  421. /**
  422. * add an extended selector entry on the selector list
  423. *
  424. * @param selector the selector to be added
  425. */
  426. public void addCustom(ExtendSelector selector) {
  427. usedMatchingTask = true;
  428. super.addCustom(selector);
  429. }
  430. /**
  431. * add a contains selector entry on the selector list
  432. *
  433. * @param selector the selector to be added
  434. */
  435. public void addContains(ContainsSelector selector) {
  436. usedMatchingTask = true;
  437. super.addContains(selector);
  438. }
  439. /**
  440. * add a present selector entry on the selector list
  441. *
  442. * @param selector the selector to be added
  443. */
  444. public void addPresent(PresentSelector selector) {
  445. usedMatchingTask = true;
  446. super.addPresent(selector);
  447. }
  448. /**
  449. * add a depth selector entry on the selector list
  450. *
  451. * @param selector the selector to be added
  452. */
  453. public void addDepth(DepthSelector selector) {
  454. usedMatchingTask = true;
  455. super.addDepth(selector);
  456. }
  457. /**
  458. * add a depends selector entry on the selector list
  459. *
  460. * @param selector the selector to be added
  461. */
  462. public void addDepend(DependSelector selector) {
  463. usedMatchingTask = true;
  464. super.addDepend(selector);
  465. }
  466. /**
  467. * add a regular expression selector entry on the selector list
  468. *
  469. * @param selector the selector to be added
  470. */
  471. public void addContainsRegexp(ContainsRegexpSelector selector) {
  472. usedMatchingTask = true;
  473. super.addContainsRegexp(selector);
  474. }
  475. /**
  476. * add the modified selector
  477. *
  478. * @param selector the selector to add
  479. * @since ant 1.6
  480. */
  481. public void addModified(ModifiedSelector selector) {
  482. usedMatchingTask = true;
  483. super.addModified(selector);
  484. }
  485. /**
  486. * add an arbitrary selector
  487. *
  488. * @param selector the selector to be added
  489. * @since Ant 1.6
  490. */
  491. public void add(FileSelector selector) {
  492. usedMatchingTask = true;
  493. super.add(selector);
  494. }
  495. /**
  496. * Delete the file(s).
  497. *
  498. * @exception BuildException if an error occurs
  499. */
  500. public void execute() throws BuildException {
  501. if (usedMatchingTask) {
  502. log("DEPRECATED - Use of the implicit FileSet is deprecated. "
  503. + "Use a nested fileset element instead.", quiet ? Project.MSG_VERBOSE : verbosity);
  504. }
  505. if (file == null && dir == null && filesets.size() == 0 && rcs == null) {
  506. throw new BuildException("At least one of the file or dir "
  507. + "attributes, or a nested resource collection, "
  508. + "must be set.");
  509. }
  510. if (quiet && failonerror) {
  511. throw new BuildException("quiet and failonerror cannot both be set to true", getLocation());
  512. }
  513. // delete the single file
  514. if (file != null) {
  515. if (file.exists()) {
  516. if (file.isDirectory()) {
  517. log("Directory " + file.getAbsolutePath()
  518. + " cannot be removed using the file attribute. "
  519. + "Use dir instead.", quiet ? Project.MSG_VERBOSE : verbosity);
  520. } else {
  521. log("Deleting: " + file.getAbsolutePath());
  522. if (!delete(file)) {
  523. handle("Unable to delete file " + file.getAbsolutePath());
  524. }
  525. }
  526. } else if (isDanglingSymlink(file)) {
  527. log("Trying to delete file " + file.getAbsolutePath()
  528. + " which looks like a broken symlink.",
  529. quiet ? Project.MSG_VERBOSE : verbosity);
  530. if (!delete(file)) {
  531. handle("Unable to delete file " + file.getAbsolutePath());
  532. }
  533. } else {
  534. log("Could not find file " + file.getAbsolutePath()
  535. + " to delete.", quiet ? Project.MSG_VERBOSE : verbosity);
  536. }
  537. }
  538. // delete the directory
  539. if (dir != null && !usedMatchingTask) {
  540. if (dir.exists() && dir.isDirectory()) {
  541. /*
  542. If verbosity is MSG_VERBOSE, that mean we are doing
  543. regular logging (backwards as that sounds). In that
  544. case, we want to print one message about deleting the
  545. top of the directory tree. Otherwise, the removeDir
  546. method will handle messages for _all_ directories.
  547. */
  548. if (verbosity == Project.MSG_VERBOSE) {
  549. log("Deleting directory " + dir.getAbsolutePath());
  550. }
  551. removeDir(dir);
  552. } else if (isDanglingSymlink(dir)) {
  553. log("Trying to delete directory " + dir.getAbsolutePath()
  554. + " which looks like a broken symlink.",
  555. quiet ? Project.MSG_VERBOSE : verbosity);
  556. if (!delete(dir)) {
  557. handle("Unable to delete directory " + dir.getAbsolutePath());
  558. }
  559. }
  560. }
  561. Resources resourcesToDelete = new Resources();
  562. resourcesToDelete.setProject(getProject());
  563. resourcesToDelete.setCache(true);
  564. Resources filesetDirs = new Resources();
  565. filesetDirs.setProject(getProject());
  566. filesetDirs.setCache(true);
  567. FileSet implicit = null;
  568. if (usedMatchingTask && dir != null && dir.isDirectory()) {
  569. //add the files from the default fileset:
  570. implicit = getImplicitFileSet();
  571. implicit.setProject(getProject());
  572. filesets.add(implicit);
  573. }
  574. final int size = filesets.size();
  575. for (int i = 0; i < size; i++) {
  576. FileSet fs = (FileSet) filesets.get(i);
  577. if (fs.getProject() == null) {
  578. log("Deleting fileset with no project specified;"
  579. + " assuming executing project", Project.MSG_VERBOSE);
  580. fs = (FileSet) fs.clone();
  581. fs.setProject(getProject());
  582. }
  583. final File fsDir = fs.getDir();
  584. if (!fs.getErrorOnMissingDir() && (fsDir == null || !fsDir.exists())) {
  585. continue;
  586. }
  587. if (fsDir == null) {
  588. throw new BuildException("File or Resource without directory or file specified");
  589. } else if (!fsDir.isDirectory()) {
  590. handle("Directory does not exist: " + fsDir);
  591. } else {
  592. DirectoryScanner ds = fs.getDirectoryScanner();
  593. // the previous line has already scanned the
  594. // filesystem, in order to avoid a rescan when later
  595. // iterating, capture the results now and store them
  596. final String[] files = ds.getIncludedFiles();
  597. resourcesToDelete.add(new ResourceCollection() {
  598. public boolean isFilesystemOnly() {
  599. return true;
  600. }
  601. public int size() {
  602. return files.length;
  603. }
  604. public Iterator<Resource> iterator() {
  605. return new FileResourceIterator(getProject(),
  606. fsDir, files);
  607. }
  608. });
  609. if (includeEmpty) {
  610. filesetDirs.add(new ReverseDirs(getProject(), fsDir,
  611. ds.getIncludedDirectories()));
  612. }
  613. if (removeNotFollowedSymlinks) {
  614. String[] n = ds.getNotFollowedSymlinks();
  615. if (n.length > 0) {
  616. String[] links = new String[n.length];
  617. System.arraycopy(n, 0, links, 0, n.length);
  618. Arrays.sort(links, ReverseDirs.REVERSE);
  619. for (int l = 0; l < links.length; l++) {
  620. try {
  621. SYMLINK_UTILS
  622. .deleteSymbolicLink(new File(links[l]),
  623. this);
  624. } catch (java.io.IOException ex) {
  625. handle(ex);
  626. }
  627. }
  628. }
  629. }
  630. }
  631. }
  632. resourcesToDelete.add(filesetDirs);
  633. if (rcs != null) {
  634. // sort first to files, then dirs
  635. Restrict exists = new Restrict();
  636. exists.add(EXISTS);
  637. exists.add(rcs);
  638. Sort s = new Sort();
  639. s.add(REVERSE_FILESYSTEM);
  640. s.add(exists);
  641. resourcesToDelete.add(s);
  642. }
  643. try {
  644. if (resourcesToDelete.isFilesystemOnly()) {
  645. for (Resource r : resourcesToDelete) {
  646. // nonexistent resources could only occur if we already
  647. // deleted something from a fileset:
  648. File f = r.as(FileProvider.class).getFile();
  649. if (!f.exists()) {
  650. continue;
  651. }
  652. if (!(f.isDirectory()) || f.list().length == 0) {
  653. log("Deleting " + f, verbosity);
  654. if (!delete(f) && failonerror) {
  655. handle("Unable to delete "
  656. + (f.isDirectory() ? "directory " : "file ") + f);
  657. }
  658. }
  659. }
  660. } else {
  661. handle(getTaskName() + " handles only filesystem resources");
  662. }
  663. } catch (Exception e) {
  664. handle(e);
  665. } finally {
  666. if (implicit != null) {
  667. filesets.remove(implicit);
  668. }
  669. }
  670. }
  671. //************************************************************************
  672. // protected and private methods
  673. //************************************************************************
  674. private void handle(String msg) {
  675. handle(new BuildException(msg));
  676. }
  677. private void handle(Exception e) {
  678. if (failonerror) {
  679. throw (e instanceof BuildException) ? (BuildException) e : new BuildException(e);
  680. }
  681. log(e, quiet ? Project.MSG_VERBOSE : verbosity);
  682. }
  683. /**
  684. * Accommodate Windows bug encountered in both Sun and IBM JDKs.
  685. * Others possible. If the delete does not work, call System.gc(),
  686. * wait a little and try again.
  687. */
  688. private boolean delete(File f) {
  689. if (!FILE_UTILS.tryHardToDelete(f, performGc)) {
  690. if (deleteOnExit) {
  691. int level = quiet ? Project.MSG_VERBOSE : Project.MSG_INFO;
  692. log("Failed to delete " + f + ", calling deleteOnExit."
  693. + " This attempts to delete the file when the Ant jvm"
  694. + " has exited and might not succeed.", level);
  695. f.deleteOnExit();
  696. return true;
  697. }
  698. return false;
  699. }
  700. return true;
  701. }
  702. /**
  703. * Delete a directory
  704. *
  705. * @param d the directory to delete
  706. */
  707. protected void removeDir(File d) {
  708. String[] list = d.list();
  709. if (list == null) {
  710. list = new String[0];
  711. }
  712. for (int i = 0; i < list.length; i++) {
  713. String s = list[i];
  714. File f = new File(d, s);
  715. if (f.isDirectory()) {
  716. removeDir(f);
  717. } else {
  718. log("Deleting " + f.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
  719. if (!delete(f)) {
  720. handle("Unable to delete file " + f.getAbsolutePath());
  721. }
  722. }
  723. }
  724. log("Deleting directory " + d.getAbsolutePath(), verbosity);
  725. if (!delete(d)) {
  726. handle("Unable to delete directory " + d.getAbsolutePath());
  727. }
  728. }
  729. /**
  730. * remove an array of files in a directory, and a list of subdirectories
  731. * which will only be deleted if 'includeEmpty' is true
  732. * @param d directory to work from
  733. * @param files array of files to delete; can be of zero length
  734. * @param dirs array of directories to delete; can of zero length
  735. */
  736. protected void removeFiles(File d, String[] files, String[] dirs) {
  737. if (files.length > 0) {
  738. log("Deleting " + files.length + " files from "
  739. + d.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
  740. for (int j = 0; j < files.length; j++) {
  741. File f = new File(d, files[j]);
  742. log("Deleting " + f.getAbsolutePath(),
  743. quiet ? Project.MSG_VERBOSE : verbosity);
  744. if (!delete(f)) {
  745. handle("Unable to delete file " + f.getAbsolutePath());
  746. }
  747. }
  748. }
  749. if (dirs.length > 0 && includeEmpty) {
  750. int dirCount = 0;
  751. for (int j = dirs.length - 1; j >= 0; j--) {
  752. File currDir = new File(d, dirs[j]);
  753. String[] dirFiles = currDir.list();
  754. if (dirFiles == null || dirFiles.length == 0) {
  755. log("Deleting " + currDir.getAbsolutePath(),
  756. quiet ? Project.MSG_VERBOSE : verbosity);
  757. if (!delete(currDir)) {
  758. handle("Unable to delete directory " + currDir.getAbsolutePath());
  759. } else {
  760. dirCount++;
  761. }
  762. }
  763. }
  764. if (dirCount > 0) {
  765. log("Deleted " + dirCount
  766. + " director" + (dirCount == 1 ? "y" : "ies")
  767. + " form " + d.getAbsolutePath(),
  768. quiet ? Project.MSG_VERBOSE : verbosity);
  769. }
  770. }
  771. }
  772. private boolean isDanglingSymlink(File f) {
  773. try {
  774. return SYMLINK_UTILS.isDanglingSymbolicLink(f);
  775. } catch (java.io.IOException e) {
  776. log("Error while trying to detect " + f.getAbsolutePath()
  777. + " as broken symbolic link. " + e.getMessage(),
  778. quiet ? Project.MSG_VERBOSE : verbosity);
  779. return false;
  780. }
  781. }
  782. }