the same way as the attribute of the <depend> selector. PR: 22150 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275307 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -135,6 +135,16 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a> | |||
| <em>since Ant 1.6</em>.</td> | |||
| <td align="center">No - defaults to false.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">granularity</td> | |||
| <td valign="top">The number of milliseconds leeway to give before | |||
| deciding a file is out of date. This is needed because not every | |||
| file system supports tracking the last modified time to the | |||
| millisecond level. Default is 0 milliseconds, or 2 seconds on DOS | |||
| systems. This can also be useful if source and target files live | |||
| on separate machines with clocks being out of sync. <em>since Ant | |||
| 1.6</em>.</td> | |||
| </tr> | |||
| </table> | |||
| <h3>Parameters specified as nested elements</h3> | |||
| @@ -113,6 +113,16 @@ to move to the <var>todir</var> directory.</p> | |||
| <em>since Ant 1.6</em>.</td> | |||
| <td align="center">No - defaults to false.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">granularity</td> | |||
| <td valign="top">The number of milliseconds leeway to give before | |||
| deciding a file is out of date. This is needed because not every | |||
| file system supports tracking the last modified time to the | |||
| millisecond level. Default is 0 milliseconds, or 2 seconds on DOS | |||
| systems. This can also be useful if source and target files live | |||
| on separate machines with clocks being out of sync. <em>since Ant | |||
| 1.6</em>.</td> | |||
| </tr> | |||
| </table> | |||
| <h3>Parameters specified as nested elements</h3> | |||
| <h4>mapper</h4> | |||
| @@ -51,6 +51,16 @@ more filesets.</p> | |||
| <td valign="top">Log the files that are being copied.</td> | |||
| <td valign="top" align="center">No; defaults to false.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">granularity</td> | |||
| <td valign="top">The number of milliseconds leeway to give before | |||
| deciding a file is out of date. This is needed because not every | |||
| file system supports tracking the last modified time to the | |||
| millisecond level. Default is 0 milliseconds, or 2 seconds on DOS | |||
| systems. This can also be useful if source and target files live | |||
| on separate machines with clocks being out of sync. <em>since Ant | |||
| 1.6</em>.</td> | |||
| </tr> | |||
| </table> | |||
| <h3>Parameters specified as nested elements</h3> | |||
| @@ -121,12 +121,14 @@ public class Copy extends Task { | |||
| private FileUtils fileUtils; | |||
| private String inputEncoding = null; | |||
| private String outputEncoding = null; | |||
| private long granularity = 0; | |||
| /** | |||
| * Copy task constructor. | |||
| */ | |||
| public Copy() { | |||
| fileUtils = FileUtils.newFileUtils(); | |||
| granularity = fileUtils.getFileTimestampGranularity(); | |||
| } | |||
| /** | |||
| @@ -370,6 +372,18 @@ public class Copy extends Task { | |||
| return outputEncoding; | |||
| } | |||
| /** | |||
| * The number of milliseconds leeway to give before deciding a | |||
| * target is out of date. | |||
| * | |||
| * <p>Default is 0 milliseconds, or 2 seconds on DOS systems.</p> | |||
| * | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void setGranularity(long granularity) { | |||
| this.granularity = granularity; | |||
| } | |||
| /** | |||
| * Performs the copy operation. | |||
| * @exception BuildException if an error occurs | |||
| @@ -397,7 +411,8 @@ public class Copy extends Task { | |||
| } | |||
| if (forceOverwrite || !destFile.exists() | |||
| || (file.lastModified() > destFile.lastModified())) { | |||
| || (file.lastModified() - granularity | |||
| > destFile.lastModified())) { | |||
| fileCopyMap.put(file.getAbsolutePath(), | |||
| new String[] {destFile.getAbsolutePath()}); | |||
| } else { | |||
| @@ -583,7 +598,7 @@ public class Copy extends Task { | |||
| v.copyInto(toCopy); | |||
| } else { | |||
| SourceFileScanner ds = new SourceFileScanner(this); | |||
| toCopy = ds.restrict(names, fromDir, toDir, mapper); | |||
| toCopy = ds.restrict(names, fromDir, toDir, mapper, granularity); | |||
| } | |||
| for (int i = 0; i < toCopy.length; i++) { | |||
| @@ -322,6 +322,18 @@ public class Sync extends Task { | |||
| _copy.addFileset(set); | |||
| } | |||
| /** | |||
| * The number of milliseconds leeway to give before deciding a | |||
| * target is out of date. | |||
| * | |||
| * <p>Default is 0 milliseconds, or 2 seconds on DOS systems.</p> | |||
| * | |||
| * @since Ant 1.6 | |||
| */ | |||
| public void setGranularity(long granularity) { | |||
| _copy.setGranularity(granularity); | |||
| } | |||
| /** | |||
| * Subclass Copy in order to access it's file/dir maps. | |||
| */ | |||
| @@ -58,6 +58,7 @@ import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||
| import org.apache.tools.ant.types.Resource; | |||
| import org.apache.tools.ant.types.ResourceFactory; | |||
| import org.apache.tools.ant.types.selectors.SelectorUtils; | |||
| import java.io.File; | |||
| import java.util.Vector; | |||
| @@ -70,7 +71,7 @@ import java.util.Vector; | |||
| */ | |||
| public class ResourceUtils { | |||
| /** { | |||
| /** | |||
| * tells which source files should be reprocessed based on the | |||
| * last modification date of target files | |||
| * @param logTo where to send (more or less) interesting output | |||
| @@ -88,19 +89,34 @@ public class ResourceUtils { | |||
| Resource[] source, | |||
| FileNameMapper mapper, | |||
| ResourceFactory targets) { | |||
| long now = (new java.util.Date()).getTime(); | |||
| return selectOutOfDateSources(logTo, source, mapper, targets, | |||
| FileUtils.newFileUtils() | |||
| .getFileTimestampGranularity()); | |||
| } | |||
| /* | |||
| If we're on Windows, we have to munge the time up to 2 secs to | |||
| be able to check file modification times. | |||
| (Windows has a max resolution of two secs for modification times) | |||
| Actually this is a feature of the FAT file system, NTFS does | |||
| not have it, so if we could reliably passively test for an NTFS | |||
| file systems we could turn this off... | |||
| */ | |||
| if (Os.isFamily("windows")) { | |||
| now += 2000; | |||
| } | |||
| /** | |||
| * tells which source files should be reprocessed based on the | |||
| * last modification date of target files | |||
| * @param logTo where to send (more or less) interesting output | |||
| * @param source array of resources bearing relative path and last | |||
| * modification date | |||
| * @param mapper filename mapper indicating how to find the target | |||
| * files | |||
| * @param targets object able to map as a resource a relative path | |||
| * at <b>destination</b> | |||
| * @param granularity The number of milliseconds leeway to give | |||
| * before deciding a target is out of date. | |||
| * @return array containing the source files which need to be | |||
| * copied or processed, because the targets are out of date or do | |||
| * not exist | |||
| * @since Ant 1.6 | |||
| */ | |||
| public static Resource[] selectOutOfDateSources(ProjectComponent logTo, | |||
| Resource[] source, | |||
| FileNameMapper mapper, | |||
| ResourceFactory targets, | |||
| long granularity) { | |||
| long now = (new java.util.Date()).getTime() + granularity; | |||
| Vector vresult = new Vector(); | |||
| for (int counter = 0; counter < source.length; counter++) { | |||
| @@ -130,8 +146,10 @@ public class ResourceUtils { | |||
| + " doesn\'t exist.", Project.MSG_VERBOSE); | |||
| vresult.addElement(source[counter]); | |||
| added = true; | |||
| } else if (!atarget.isDirectory() && atarget.getLastModified() | |||
| < source[counter].getLastModified()) { | |||
| } else if (!atarget.isDirectory() && | |||
| SelectorUtils.isOutOfDate(source[counter], | |||
| atarget, | |||
| (int) granularity)) { | |||
| logTo.log(source[counter].getName() + " added as " | |||
| + atarget.getName() | |||
| + " is outdated.", Project.MSG_VERBOSE); | |||
| @@ -99,6 +99,27 @@ public class SourceFileScanner implements ResourceFactory { | |||
| */ | |||
| public String[] restrict(String[] files, File srcDir, File destDir, | |||
| FileNameMapper mapper) { | |||
| return restrict(files, srcDir, destDir, mapper, | |||
| fileUtils.getFileTimestampGranularity()); | |||
| } | |||
| /** | |||
| * Restrict the given set of files to those that are newer than | |||
| * their corresponding target files. | |||
| * | |||
| * @param files the original set of files | |||
| * @param srcDir all files are relative to this directory | |||
| * @param destDir target files live here. if null file names | |||
| * returned by the mapper are assumed to be absolute. | |||
| * @param mapper knows how to construct a target file names from | |||
| * source file names. | |||
| * @param granularity The number of milliseconds leeway to give | |||
| * before deciding a target is out of date. | |||
| * | |||
| * @since Ant 1.6 | |||
| */ | |||
| public String[] restrict(String[] files, File srcDir, File destDir, | |||
| FileNameMapper mapper, long granularity) { | |||
| // record destdir for later use in getResource | |||
| this.destDir = destDir; | |||
| Vector v = new Vector(); | |||
| @@ -114,7 +135,7 @@ public class SourceFileScanner implements ResourceFactory { | |||
| // respect to the target | |||
| Resource[] outofdate = | |||
| ResourceUtils.selectOutOfDateSources(task, sourceresources, | |||
| mapper, this); | |||
| mapper, this, granularity); | |||
| String[] result = new String[outofdate.length]; | |||
| for (int counter = 0; counter < outofdate.length; counter++) { | |||
| result[counter] = outofdate[counter].getName(); | |||
| @@ -129,7 +150,20 @@ public class SourceFileScanner implements ResourceFactory { | |||
| */ | |||
| public File[] restrictAsFiles(String[] files, File srcDir, File destDir, | |||
| FileNameMapper mapper) { | |||
| String[] res = restrict(files, srcDir, destDir, mapper); | |||
| return restrictAsFiles(files, srcDir, destDir, mapper, | |||
| fileUtils.getFileTimestampGranularity()); | |||
| } | |||
| /** | |||
| * Convinience layer on top of restrict that returns the source | |||
| * files as File objects (containing absolute paths if srcDir is | |||
| * absolute). | |||
| * | |||
| * @since Ant 1.6 | |||
| */ | |||
| public File[] restrictAsFiles(String[] files, File srcDir, File destDir, | |||
| FileNameMapper mapper, long granularity) { | |||
| String[] res = restrict(files, srcDir, destDir, mapper, granularity); | |||
| File[] result = new File[res.length]; | |||
| for (int i = 0; i < res.length; i++) { | |||
| result[i] = new File(srcDir, res[i]); | |||