diff --git a/docs/manual/CoreTasks/copy.html b/docs/manual/CoreTasks/copy.html index e49ca8882..33d47ff70 100644 --- a/docs/manual/CoreTasks/copy.html +++ b/docs/manual/CoreTasks/copy.html @@ -135,6 +135,16 @@ operation as filtersets since Ant 1.6.
Default is 0 milliseconds, or 2 seconds on DOS systems.
+ * + * @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++) { diff --git a/src/main/org/apache/tools/ant/taskdefs/Sync.java b/src/main/org/apache/tools/ant/taskdefs/Sync.java index 0440afaec..0ac7a3bc3 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Sync.java +++ b/src/main/org/apache/tools/ant/taskdefs/Sync.java @@ -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. + * + *Default is 0 milliseconds, or 2 seconds on DOS systems.
+ * + * @since Ant 1.6 + */ + public void setGranularity(long granularity) { + _copy.setGranularity(granularity); + } + /** * Subclass Copy in order to access it's file/dir maps. */ diff --git a/src/main/org/apache/tools/ant/util/ResourceUtils.java b/src/main/org/apache/tools/ant/util/ResourceUtils.java index 35394b7ef..d95c540e6 100644 --- a/src/main/org/apache/tools/ant/util/ResourceUtils.java +++ b/src/main/org/apache/tools/ant/util/ResourceUtils.java @@ -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 destination + * @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); diff --git a/src/main/org/apache/tools/ant/util/SourceFileScanner.java b/src/main/org/apache/tools/ant/util/SourceFileScanner.java index 2bb158759..4996351e6 100644 --- a/src/main/org/apache/tools/ant/util/SourceFileScanner.java +++ b/src/main/org/apache/tools/ant/util/SourceFileScanner.java @@ -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]);