PR: 23526 Submitted by: gudnabrsam@yahoo.com git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275869 13f79535-47bb-0310-9956-ffa450edef68master
@@ -12,7 +12,8 @@ | |||||
<p>Changes the modification time of a file and possibly creates it at | <p>Changes the modification time of a file and possibly creates it at | ||||
the same time. In addition to working with a single file, this Task | the same time. In addition to working with a single file, this Task | ||||
can also work a <a href="../CoreTypes/fileset.html">Fileset</a> (which | can also work a <a href="../CoreTypes/fileset.html">Fileset</a> (which | ||||
also includes directories).</p> | |||||
also includes directories) | |||||
or a <a href="../CoreTypes/filelist.html">Filelist</a> (since Ant 1.6).</p> | |||||
<p>For JDK 1.1 only the creation of new files with a modification time | <p>For JDK 1.1 only the creation of new files with a modification time | ||||
of now works, all other cases will emit a warning.</p> | of now works, all other cases will emit a warning.</p> | ||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
@@ -26,6 +27,7 @@ of now works, all other cases will emit a warning.</p> | |||||
<td valign="top">file</td> | <td valign="top">file</td> | ||||
<td valign="top">the name of the file</td> | <td valign="top">the name of the file</td> | ||||
<td valign="top" align="center">unless a nested fileset element | <td valign="top" align="center">unless a nested fileset element | ||||
or a nested filelist element | |||||
has been specified.</td> | has been specified.</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -67,4 +69,3 @@ Reserved.</p> | |||||
</body> | </body> | ||||
</html> | </html> | ||||
@@ -12,4 +12,30 @@ | |||||
<target name="seconds"> | <target name="seconds"> | ||||
<touch file="touchtest" datetime="2003/06/24 2:20:12 pm"/> | <touch file="touchtest" datetime="2003/06/24 2:20:12 pm"/> | ||||
</target> | </target> | ||||
<target name="testNow"> | |||||
<touch file="touchtest" /> | |||||
</target> | |||||
<target name="testMillis"> | |||||
<touch file="touchtest" millis="1234567" /> | |||||
</target> | |||||
<target name="test1970"> | |||||
<touch file="touchtest" millis="0" /> | |||||
</target> | |||||
<target name="testFilelist"> | |||||
<touch millis="100000" > | |||||
<filelist dir="." files="touchtest"/> | |||||
</touch> | |||||
</target> | |||||
<target name="testFileset" depends="testNow"> | |||||
<touch millis="200000" > | |||||
<fileset dir="." includes="touchtest"/> | |||||
</touch> | |||||
</target> | |||||
</project> | </project> |
@@ -65,11 +65,13 @@ import org.apache.tools.ant.DirectoryScanner; | |||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
import org.apache.tools.ant.types.FileList; | |||||
import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
import org.apache.tools.ant.util.JavaEnvUtils; | import org.apache.tools.ant.util.JavaEnvUtils; | ||||
/** | /** | ||||
* Touch a file and/or fileset(s); corresponds to the Unix touch command. | |||||
* Touch a file and/or fileset(s) and/or filelist(s); | |||||
* corresponds to the Unix touch command. | |||||
* | * | ||||
* <p>If the file to touch doesn't exist, an empty one is | * <p>If the file to touch doesn't exist, an empty one is | ||||
* created. </p> | * created. </p> | ||||
@@ -91,6 +93,7 @@ public class Touch extends Task { | |||||
private long millis = -1; | private long millis = -1; | ||||
private String dateTime; | private String dateTime; | ||||
private Vector filesets = new Vector(); | private Vector filesets = new Vector(); | ||||
private Vector filelists = new Vector(); | |||||
private FileUtils fileUtils; | private FileUtils fileUtils; | ||||
public Touch() { | public Touch() { | ||||
@@ -131,15 +134,22 @@ public class Touch extends Task { | |||||
filesets.addElement(set); | filesets.addElement(set); | ||||
} | } | ||||
/** | |||||
* Add a filelist to touch | |||||
*/ | |||||
public void addFilelist(FileList list) { | |||||
filelists.addElement(list); | |||||
} | |||||
/** | /** | ||||
* Execute the touch operation. | * Execute the touch operation. | ||||
*/ | */ | ||||
public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
long savedMillis = millis; | long savedMillis = millis; | ||||
if (file == null && filesets.size() == 0) { | |||||
if (file == null && filesets.size() == 0 && filelists.size() == 0) { | |||||
throw | throw | ||||
new BuildException("Specify at least one source - a file or " | |||||
new BuildException("Specify at least one source - a file, filelist or " | |||||
+ "a fileset."); | + "a fileset."); | ||||
} | } | ||||
@@ -195,26 +205,9 @@ public class Touch extends Task { | |||||
} | } | ||||
/** | /** | ||||
* Does the actual work. Entry point for Untar and Expand as well. | |||||
* Does the actual work; assumes everything has been checked by now. | |||||
*/ | */ | ||||
protected void touch() throws BuildException { | protected void touch() throws BuildException { | ||||
if (file != null) { | |||||
if (!file.exists()) { | |||||
log("Creating " + file, Project.MSG_INFO); | |||||
try { | |||||
fileUtils.createNewFile(file); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Could not create " + file, ioe, | |||||
getLocation()); | |||||
} | |||||
} | |||||
} | |||||
if (millis >= 0 && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { | |||||
log("modification time of files cannot be set in JDK 1.1", | |||||
Project.MSG_WARN); | |||||
return; | |||||
} | |||||
boolean resetMillis = false; | boolean resetMillis = false; | ||||
if (millis < 0) { | if (millis < 0) { | ||||
@@ -244,21 +237,43 @@ public class Touch extends Task { | |||||
} | } | ||||
} | } | ||||
// deal with the filelists | |||||
for (int i = 0; i < filelists.size(); i++) { | |||||
FileList fl = (FileList) filelists.elementAt(i); | |||||
File fromDir = fl.getDir(getProject()); | |||||
String[] srcFiles = fl.getFiles(getProject()); | |||||
for (int j = 0; j < srcFiles.length; j++) { | |||||
touch(new File(fromDir, srcFiles[j])); | |||||
} | |||||
} | |||||
if (resetMillis) { | if (resetMillis) { | ||||
millis = -1; | millis = -1; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* touch a single file with the current timestamp (this.millis) | |||||
* @param file file to touch | |||||
* @throws BuildException | |||||
*/ | |||||
protected void touch(File file) throws BuildException { | protected void touch(File file) throws BuildException { | ||||
if (!file.exists()) { | |||||
log("Creating " + file, Project.MSG_INFO); | |||||
try { | |||||
fileUtils.createNewFile(file); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Could not create " + file, ioe, | |||||
getLocation()); | |||||
} | |||||
} | |||||
if (!file.canWrite()) { | if (!file.canWrite()) { | ||||
throw new BuildException("Can not change modification date of " | throw new BuildException("Can not change modification date of " | ||||
+ "read-only file " + file); | + "read-only file " + file); | ||||
} | } | ||||
if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { | |||||
return; | |||||
} | |||||
fileUtils.setFileLastModified(file, millis); | fileUtils.setFileLastModified(file, millis); | ||||
} | } | ||||
@@ -116,6 +116,10 @@ public class FileUtils { | |||||
*/ | */ | ||||
public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000; | public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000; | ||||
/** | |||||
* the granularity of timestamps under Unix | |||||
*/ | |||||
public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000; | |||||
// stolen from FilePathToURI of the Xerces-J team | // stolen from FilePathToURI of the Xerces-J team | ||||
static { | static { | ||||
@@ -1401,7 +1405,7 @@ public class FileUtils { | |||||
if (Os.isFamily("dos")) { | if (Os.isFamily("dos")) { | ||||
return FAT_FILE_TIMESTAMP_GRANULARITY; | return FAT_FILE_TIMESTAMP_GRANULARITY; | ||||
} else { | } else { | ||||
return 0; | |||||
return UNIX_FILE_TIMESTAMP_GRANULARITY; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -55,9 +55,15 @@ | |||||
package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
import org.apache.tools.ant.BuildFileTest; | import org.apache.tools.ant.BuildFileTest; | ||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.util.FileUtils; | |||||
import java.io.File; | |||||
public class TouchTest extends BuildFileTest { | public class TouchTest extends BuildFileTest { | ||||
private static String touchfile="src/etc/testcases/taskdefs/touchtest"; | |||||
public TouchTest(String name) { | public TouchTest(String name) { | ||||
super(name); | super(name); | ||||
} | } | ||||
@@ -69,13 +75,23 @@ public class TouchTest extends BuildFileTest { | |||||
public void tearDown() { | public void tearDown() { | ||||
executeTarget("cleanup"); | executeTarget("cleanup"); | ||||
} | } | ||||
public long getTargetTime() { | |||||
File file = new File(touchfile); | |||||
if(!file.exists()) { | |||||
throw new BuildException("failed to touch file "+touchfile); | |||||
} | |||||
return file.lastModified(); | |||||
} | |||||
/** | /** | ||||
* No real test, simply checks whether the dateformat without | * No real test, simply checks whether the dateformat without | ||||
* seconds is accepted - by erroring out otherwise. | * seconds is accepted - by erroring out otherwise. | ||||
*/ | */ | ||||
public void testNoSeconds() { | public void testNoSeconds() { | ||||
executeTarget("noSeconds"); | executeTarget("noSeconds"); | ||||
long time = getTargetTime(); | |||||
} | } | ||||
/** | /** | ||||
@@ -84,5 +100,74 @@ public class TouchTest extends BuildFileTest { | |||||
*/ | */ | ||||
public void testSeconds() { | public void testSeconds() { | ||||
executeTarget("seconds"); | executeTarget("seconds"); | ||||
long time=getTargetTime(); | |||||
} | |||||
/** | |||||
* verify that the millis test sets things up | |||||
*/ | |||||
public void testMillis() { | |||||
touchFile("testMillis", 1234567); | |||||
} | |||||
/** | |||||
* verify that the default value defaults to now | |||||
*/ | |||||
public void testNow() { | |||||
long now=System.currentTimeMillis(); | |||||
executeTarget("testNow"); | |||||
long time = getTargetTime(); | |||||
assertTimesNearlyMatch(time,now,5000); | |||||
} | |||||
/** | |||||
* verify that the millis test sets things up | |||||
*/ | |||||
public void test1970() { | |||||
touchFile("test1970", 0); | |||||
} | |||||
/** | |||||
* test the file list | |||||
*/ | |||||
public void testFilelist() { | |||||
touchFile("testFilelist", 100000); | |||||
} | |||||
/** | |||||
* test the file set | |||||
*/ | |||||
public void testFileset() { | |||||
touchFile("testFileset", 200000); | |||||
} | |||||
/** | |||||
* run a target to touch the test file; verify the timestamp is as expected | |||||
* @param targetName | |||||
* @param timestamp | |||||
*/ | |||||
private void touchFile(String targetName, long timestamp) { | |||||
executeTarget(targetName); | |||||
long time = getTargetTime(); | |||||
assertTimesNearlyMatch(timestamp,time); | |||||
} | |||||
/** | |||||
* assert that two times are within the current FS granularity; | |||||
* @param timestamp | |||||
* @param time | |||||
*/ | |||||
public void assertTimesNearlyMatch(long timestamp,long time) { | |||||
long granularity= FileUtils.newFileUtils().getFileTimestampGranularity(); | |||||
assertTimesNearlyMatch(timestamp, time, granularity); | |||||
} | |||||
/** | |||||
* assert that two times are within a specified range | |||||
* @param timestamp | |||||
* @param time | |||||
* @param range | |||||
*/ | |||||
private void assertTimesNearlyMatch(long timestamp, long time, long range) { | |||||
assertTrue("Time "+timestamp+" is not within "+range+" ms of "+time, | |||||
Math.abs(time-timestamp)<=range); | |||||
} | } | ||||
} | } |