1. /*
  2. * Copyright 2001-2002,2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.File;
  19. import java.util.Date;
  20. import java.util.Enumeration;
  21. import java.util.Vector;
  22. import org.apache.tools.ant.BuildException;
  23. import org.apache.tools.ant.DirectoryScanner;
  24. import org.apache.tools.ant.Project;
  25. import org.apache.tools.ant.taskdefs.condition.Os;
  26. import org.apache.tools.ant.types.FileList;
  27. import org.apache.tools.ant.types.FileSet;
  28. /**
  29. * Examines and removes out of date target files. If any of the target files
  30. * are out of date with respect to any of the source files, all target
  31. * files are removed. This is useful where dependencies cannot be
  32. * computed (for example, dynamically interpreted parameters or files
  33. * that need to stay in synch but are not directly linked) or where
  34. * the ant task in question could compute them but does not (for
  35. * example, the linked DTD for an XML file using the style task).
  36. *
  37. * nested arguments:
  38. * <ul>
  39. * <li>srcfileset (fileset describing the source files to examine)
  40. * <li>srcfilelist (filelist describing the source files to examine)
  41. * <li>targetfileset (fileset describing the target files to examine)
  42. * <li>targetfilelist (filelist describing the target files to examine)
  43. * </ul>
  44. * At least one instance of either a fileset or filelist for both source and
  45. * target are required.
  46. * <p>
  47. * This task will examine each of the source files against each of the target
  48. * files. If any target files are out of date with respect to any of the source
  49. * files, all targets are removed. If any files named in a (src or target)
  50. * filelist do not exist, all targets are removed.
  51. * Hint: If missing files should be ignored, specify them as include patterns
  52. * in filesets, rather than using filelists.
  53. * </p><p>
  54. * This task attempts to optimize speed of dependency checking. It will stop
  55. * after the first out of date file is found and remove all targets, rather
  56. * than exhaustively checking every source vs target combination unnecessarily.
  57. * </p><p>
  58. * Example uses:
  59. * <ul><li>
  60. * Record the fact that an XML file must be up to date
  61. * with respect to its XSD (Schema file), even though the XML file
  62. * itself includes no reference to its XSD.
  63. * </li><li>
  64. * Record the fact that an XSL stylesheet includes other
  65. * sub-stylesheets
  66. * </li><li>
  67. * Record the fact that java files must be recompiled if the ant build
  68. * file changes
  69. * </li></ul>
  70. *
  71. * @ant.task category="filesystem"
  72. * @version $Revision: 1.23.2.4 $ $Date: 2004/03/09 17:01:33 $
  73. * @since Ant 1.4
  74. */
  75. public class DependSet extends MatchingTask {
  76. private Vector sourceFileSets = new Vector();
  77. private Vector sourceFileLists = new Vector();
  78. private Vector targetFileSets = new Vector();
  79. private Vector targetFileLists = new Vector();
  80. /**
  81. * Creates a new DependSet Task.
  82. **/
  83. public DependSet() {
  84. } //-- DependSet
  85. /**
  86. * Add a set of source files.
  87. */
  88. public void addSrcfileset(FileSet fs) {
  89. sourceFileSets.addElement(fs);
  90. }
  91. /**
  92. * Add a list of source files.
  93. */
  94. public void addSrcfilelist(FileList fl) {
  95. sourceFileLists.addElement(fl);
  96. }
  97. /**
  98. * Add a set of target files.
  99. */
  100. public void addTargetfileset(FileSet fs) {
  101. targetFileSets.addElement(fs);
  102. }
  103. /**
  104. * Add a list of target files.
  105. */
  106. public void addTargetfilelist(FileList fl) {
  107. targetFileLists.addElement(fl);
  108. }
  109. /**
  110. * Executes the task.
  111. */
  112. public void execute() throws BuildException {
  113. if ((sourceFileSets.size() == 0) && (sourceFileLists.size() == 0)) {
  114. throw new BuildException("At least one <srcfileset> or <srcfilelist>"
  115. + " element must be set");
  116. }
  117. if ((targetFileSets.size() == 0) && (targetFileLists.size() == 0)) {
  118. throw new BuildException("At least one <targetfileset> or"
  119. + " <targetfilelist> element must be set");
  120. }
  121. long now = (new Date()).getTime();
  122. /*
  123. If we're on Windows, we have to munge the time up to 2 secs to
  124. be able to check file modification times.
  125. (Windows has a max resolution of two secs for modification times)
  126. */
  127. if (Os.isFamily("windows")) {
  128. now += 2000;
  129. }
  130. //
  131. // Grab all the target files specified via filesets
  132. //
  133. Vector allTargets = new Vector();
  134. long oldestTargetTime = 0;
  135. File oldestTarget = null;
  136. Enumeration enumTargetSets = targetFileSets.elements();
  137. while (enumTargetSets.hasMoreElements()) {
  138. FileSet targetFS = (FileSet) enumTargetSets.nextElement();
  139. if (!targetFS.getDir(getProject()).exists()) {
  140. // this is the same as if it was empty, no target files found
  141. continue;
  142. }
  143. DirectoryScanner targetDS = targetFS.getDirectoryScanner(getProject());
  144. String[] targetFiles = targetDS.getIncludedFiles();
  145. for (int i = 0; i < targetFiles.length; i++) {
  146. File dest = new File(targetFS.getDir(getProject()), targetFiles[i]);
  147. allTargets.addElement(dest);
  148. if (dest.lastModified() > now) {
  149. log("Warning: " + targetFiles[i] + " modified in the future.",
  150. Project.MSG_WARN);
  151. }
  152. if (oldestTarget == null
  153. || dest.lastModified() < oldestTargetTime) {
  154. oldestTargetTime = dest.lastModified();
  155. oldestTarget = dest;
  156. }
  157. }
  158. }
  159. //
  160. // Grab all the target files specified via filelists
  161. //
  162. boolean upToDate = true;
  163. Enumeration enumTargetLists = targetFileLists.elements();
  164. while (enumTargetLists.hasMoreElements()) {
  165. FileList targetFL = (FileList) enumTargetLists.nextElement();
  166. String[] targetFiles = targetFL.getFiles(getProject());
  167. for (int i = 0; i < targetFiles.length; i++) {
  168. File dest = new File(targetFL.getDir(getProject()), targetFiles[i]);
  169. if (!dest.exists()) {
  170. log(targetFiles[i] + " does not exist.", Project.MSG_VERBOSE);
  171. upToDate = false;
  172. continue;
  173. } else {
  174. allTargets.addElement(dest);
  175. }
  176. if (dest.lastModified() > now) {
  177. log("Warning: " + targetFiles[i] + " modified in the future.",
  178. Project.MSG_WARN);
  179. }
  180. if (oldestTarget == null
  181. || dest.lastModified() < oldestTargetTime) {
  182. oldestTargetTime = dest.lastModified();
  183. oldestTarget = dest;
  184. }
  185. }
  186. }
  187. if (oldestTarget != null) {
  188. log(oldestTarget + " is oldest target file", Project.MSG_VERBOSE);
  189. } else {
  190. // no target files, then we cannot remove any target files and
  191. // skip the following tests right away
  192. upToDate = false;
  193. }
  194. //
  195. // Check targets vs source files specified via filelists
  196. //
  197. if (upToDate) {
  198. Enumeration enumSourceLists = sourceFileLists.elements();
  199. while (upToDate && enumSourceLists.hasMoreElements()) {
  200. FileList sourceFL = (FileList) enumSourceLists.nextElement();
  201. String[] sourceFiles = sourceFL.getFiles(getProject());
  202. for (int i = 0; upToDate && i < sourceFiles.length; i++) {
  203. File src = new File(sourceFL.getDir(getProject()), sourceFiles[i]);
  204. if (src.lastModified() > now) {
  205. log("Warning: " + sourceFiles[i]
  206. + " modified in the future.", Project.MSG_WARN);
  207. }
  208. if (!src.exists()) {
  209. log(sourceFiles[i] + " does not exist.",
  210. Project.MSG_VERBOSE);
  211. upToDate = false;
  212. break;
  213. }
  214. if (src.lastModified() > oldestTargetTime) {
  215. upToDate = false;
  216. log(oldestTarget + " is out of date with respect to "
  217. + sourceFiles[i], Project.MSG_VERBOSE);
  218. }
  219. }
  220. }
  221. }
  222. //
  223. // Check targets vs source files specified via filesets
  224. //
  225. if (upToDate) {
  226. Enumeration enumSourceSets = sourceFileSets.elements();
  227. while (upToDate && enumSourceSets.hasMoreElements()) {
  228. FileSet sourceFS = (FileSet) enumSourceSets.nextElement();
  229. DirectoryScanner sourceDS = sourceFS.getDirectoryScanner(getProject());
  230. String[] sourceFiles = sourceDS.getIncludedFiles();
  231. for (int i = 0; upToDate && i < sourceFiles.length; i++) {
  232. File src = new File(sourceFS.getDir(getProject()), sourceFiles[i]);
  233. if (src.lastModified() > now) {
  234. log("Warning: " + sourceFiles[i]
  235. + " modified in the future.", Project.MSG_WARN);
  236. }
  237. if (src.lastModified() > oldestTargetTime) {
  238. upToDate = false;
  239. log(oldestTarget + " is out of date with respect to "
  240. + sourceFiles[i], Project.MSG_VERBOSE);
  241. }
  242. }
  243. }
  244. }
  245. if (!upToDate) {
  246. log("Deleting all target files. ", Project.MSG_VERBOSE);
  247. for (Enumeration e = allTargets.elements(); e.hasMoreElements();) {
  248. File fileToRemove = (File) e.nextElement();
  249. log("Deleting file " + fileToRemove.getAbsolutePath(),
  250. Project.MSG_VERBOSE);
  251. fileToRemove.delete();
  252. }
  253. }
  254. } //-- execute
  255. } //-- DependSet.java