1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.text.DateFormat;
  21. import java.text.ParseException;
  22. import java.util.Locale;
  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.Task;
  28. import org.apache.tools.ant.types.FileSet;
  29. import org.apache.tools.ant.types.FileList;
  30. import org.apache.tools.ant.util.FileUtils;
  31. import org.apache.tools.ant.util.JavaEnvUtils;
  32. /**
  33. * Touch a file and/or fileset(s) and/or filelist(s);
  34. * corresponds to the Unix touch command.
  35. *
  36. * <p>If the file to touch doesn't exist, an empty one is
  37. * created. </p>
  38. *
  39. * <p>Note: Setting the modification time of files is not supported in
  40. * JDK 1.1.</p>
  41. *
  42. * @since Ant 1.1
  43. *
  44. * @ant.task category="filesystem"
  45. */
  46. public class Touch extends Task {
  47. private File file;
  48. private long millis = -1;
  49. private String dateTime;
  50. private Vector filesets = new Vector();
  51. private Vector filelists = new Vector();
  52. private FileUtils fileUtils;
  53. public Touch() {
  54. fileUtils = FileUtils.newFileUtils();
  55. }
  56. /**
  57. * Sets a single source file to touch. If the file does not exist
  58. * an empty file will be created.
  59. */
  60. public void setFile(File file) {
  61. this.file = file;
  62. }
  63. /**
  64. * the new modification time of the file
  65. * in milliseconds since midnight Jan 1 1970.
  66. * Optional, default=now
  67. */
  68. public void setMillis(long millis) {
  69. this.millis = millis;
  70. }
  71. /**
  72. * the new modification time of the file
  73. * in the format "MM/DD/YYYY HH:MM AM <i>or</i> PM"
  74. * or "MM/DD/YYYY HH:MM:SS AM <i>or</i> PM".
  75. * Optional, default=now
  76. */
  77. public void setDatetime(String dateTime) {
  78. this.dateTime = dateTime;
  79. }
  80. /**
  81. * Add a set of files to touch
  82. */
  83. public void addFileset(FileSet set) {
  84. filesets.addElement(set);
  85. }
  86. /**
  87. * Add a filelist to touch
  88. */
  89. public void addFilelist(FileList list) {
  90. filelists.addElement(list);
  91. }
  92. /**
  93. * Execute the touch operation.
  94. */
  95. public void execute() throws BuildException {
  96. long savedMillis = millis;
  97. if (file == null && filesets.size() == 0 && filelists.size() == 0) {
  98. throw
  99. new BuildException("Specify at least one source - a file, filelist or "
  100. + "a fileset.");
  101. }
  102. if (file != null && file.exists() && file.isDirectory()) {
  103. throw new BuildException("Use a fileset to touch directories.");
  104. }
  105. try {
  106. if (dateTime != null) {
  107. /*
  108. * The initial version used DateFormat.SHORT for the
  109. * time format, which ignores seconds. If we want
  110. * seconds as well, we need DateFormat.MEDIUM, which
  111. * in turn would break all old build files.
  112. *
  113. * First try to parse with DateFormat.SHORT and if
  114. * that fails with MEDIUM - throw an exception if both
  115. * fail.
  116. */
  117. DateFormat df =
  118. DateFormat.getDateTimeInstance(DateFormat.SHORT,
  119. DateFormat.SHORT,
  120. Locale.US);
  121. try {
  122. setMillis(df.parse(dateTime).getTime());
  123. } catch (ParseException pe) {
  124. df =
  125. DateFormat.getDateTimeInstance(DateFormat.SHORT,
  126. DateFormat.MEDIUM,
  127. Locale.US);
  128. try {
  129. setMillis(df.parse(dateTime).getTime());
  130. } catch (ParseException pe2) {
  131. throw new BuildException(pe2.getMessage(), pe,
  132. getLocation());
  133. }
  134. }
  135. if (millis < 0) {
  136. throw new BuildException("Date of " + dateTime
  137. + " results in negative "
  138. + "milliseconds value "
  139. + "relative to epoch "
  140. + "(January 1, 1970, "
  141. + "00:00:00 GMT).");
  142. }
  143. }
  144. touch();
  145. } finally {
  146. millis = savedMillis;
  147. }
  148. }
  149. /**
  150. * Does the actual work; assumes everything has been checked by now.
  151. */
  152. protected void touch() throws BuildException {
  153. boolean resetMillis = false;
  154. if (millis < 0) {
  155. resetMillis = true;
  156. millis = System.currentTimeMillis();
  157. }
  158. if (file != null) {
  159. touch(file);
  160. }
  161. // deal with the filesets
  162. for (int i = 0; i < filesets.size(); i++) {
  163. FileSet fs = (FileSet) filesets.elementAt(i);
  164. DirectoryScanner ds = fs.getDirectoryScanner(getProject());
  165. File fromDir = fs.getDir(getProject());
  166. String[] srcFiles = ds.getIncludedFiles();
  167. String[] srcDirs = ds.getIncludedDirectories();
  168. for (int j = 0; j < srcFiles.length; j++) {
  169. touch(new File(fromDir, srcFiles[j]));
  170. }
  171. for (int j = 0; j < srcDirs.length; j++) {
  172. touch(new File(fromDir, srcDirs[j]));
  173. }
  174. }
  175. // deal with the filelists
  176. for (int i = 0; i < filelists.size(); i++) {
  177. FileList fl = (FileList) filelists.elementAt(i);
  178. File fromDir = fl.getDir(getProject());
  179. String[] srcFiles = fl.getFiles(getProject());
  180. for (int j = 0; j < srcFiles.length; j++) {
  181. touch(new File(fromDir, srcFiles[j]));
  182. }
  183. }
  184. if (resetMillis) {
  185. millis = -1;
  186. }
  187. }
  188. /**
  189. * touch a single file with the current timestamp (this.millis)
  190. * @param file file to touch
  191. * @throws BuildException
  192. */
  193. protected void touch(File file) throws BuildException {
  194. if (!file.exists()) {
  195. log("Creating " + file, Project.MSG_INFO);
  196. try {
  197. fileUtils.createNewFile(file);
  198. } catch (IOException ioe) {
  199. throw new BuildException("Could not create " + file, ioe,
  200. getLocation());
  201. }
  202. }
  203. if (!file.canWrite()) {
  204. throw new BuildException("Can not change modification date of "
  205. + "read-only file " + file);
  206. }
  207. fileUtils.setFileLastModified(file, millis);
  208. }
  209. }