Browse Source

dependset + resource collection support

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@289262 13f79535-47bb-0310-9956-ffa450edef68
master
Matthew Jason Benson 20 years ago
parent
commit
d8a41c88be
4 changed files with 226 additions and 199 deletions
  1. +39
    -26
      docs/manual/CoreTasks/dependset.html
  2. +57
    -1
      src/etc/testcases/taskdefs/dependset.xml
  3. +121
    -172
      src/main/org/apache/tools/ant/taskdefs/DependSet.java
  4. +9
    -0
      src/testcases/org/apache/tools/ant/taskdefs/DependSetTest.java

+ 39
- 26
docs/manual/CoreTasks/dependset.html View File

@@ -10,21 +10,20 @@


<h2>DependSet</h2> <h2>DependSet</h2>


A task to manage arbitrary dependencies between files.
A task to manage arbitrary dependencies between resources.


<h3>Description</h3> <h3>Description</h3>


<p> <p>
The dependset task compares a set of source files with a set of target
files. If any of the source files is more recent than any of
the target files, all of the target files are removed.
The dependset task compares a set of sources with a set of target
files. If any of the sources has been modified more recently than
any of the target files, all of the target files are removed.
</p> </p>
<p> <p>
Source files and target files are specified via nested <a
href="../CoreTypes/fileset.html">FileSets</a> and/or nested <a
href="../CoreTypes/filelist.html">FileLists</a>. Arbitrarily many
source and target filesets/filelists may be specified, but at
least one filelist/fileset is required for both sources and targets.
Sources and target files are specified via nested
<a href="../CoreTypes/resources.html#collection">Resource Collection</a>s;
sources can be resources of any type, while targets are restricted to files
only. At least one set of sources and one set of targets is required.
</p> </p>
<p> <p>
Use a FileSet when you want to use wildcard include or exclude Use a FileSet when you want to use wildcard include or exclude
@@ -50,50 +49,64 @@ well as other stylesheets imported by the main stylesheet.


<h3>Parameters Specified as Nested Elements</h3> <h3>Parameters Specified as Nested Elements</h3>


<h4>sources</h4>

<p>The <code>&lt;sources&gt;</code> element is a
<a href="../CoreTypes/resources.html#union">Union</a> into which
arbitrary resource collections can be nested. <b>Since Ant 1.7</b>
</p>

<h4>srcfileset</h4> <h4>srcfileset</h4>


<p> <p>
The nested <code>srcfileset</code> element specifies a <a
The nested <code>&lt;srcfileset&gt;</code> element specifies a <a
href="../CoreTypes/fileset.html">FileSet</a>. All files included in href="../CoreTypes/fileset.html">FileSet</a>. All files included in
this fileset will be compared against all files included in all of the this fileset will be compared against all files included in all of the
<code>targetfileset</code> filesets and <code>targetfilelist</code>
filelists. Multiple <code>srcfileset</code> filesets may be specified.
<code>&lt;targetfileset&gt;</code> filesets and <code>&lt;targetfilelist&gt;</code>
filelists. Multiple <code>&lt;srcfileset&gt;</code> filesets may be specified.
</p> </p>


<h4>srcfilelist</h4> <h4>srcfilelist</h4>


<p> <p>
The nested <code>srcfilelist</code> element specifies a <a
The nested <code>&lt;srcfilelist&gt;</code> element specifies a <a
href="../CoreTypes/filelist.html">FileList</a>. All files included in href="../CoreTypes/filelist.html">FileList</a>. All files included in
this filelist will be compared against all files included in all of the this filelist will be compared against all files included in all of the
<code>targetfileset</code> filesets and <code>targetfilelist</code>
filelists. Multiple <code>srcfilelist</code> filelists may be specified.
<code>&lt;targetfileset&gt;</code> filesets and <code>&lt;targetfilelist&gt;</code>
filelists. Multiple <code>&lt;srcfilelist&gt;</code> filelists may be specified.
</p>

<h4>targets</h4>

<p>The <code>&lt;targets&gt;</code> element is a
<a href="../using.html#path">Path</a> and thus can
include any filesystem-based resource. <b>Since Ant 1.7</b>
</p> </p>


<h4>targetfileset</h4> <h4>targetfileset</h4>


<p> <p>
The nested <code>targetfileset</code> element specifies a <a
The nested <code>&lt;targetfileset&gt;</code> element specifies a <a
href="../CoreTypes/fileset.html">FileSet</a>. All files included in href="../CoreTypes/fileset.html">FileSet</a>. All files included in
this fileset will be compared against all files included in all of the this fileset will be compared against all files included in all of the
<code>srcfileset</code> filesets and <code>sourcefilelist</code>
<code>&lt;srcfileset&gt;</code> filesets and <code>&lt;sourcefilelist&gt;</code>
filelists, and if any are older, they are all deleted. filelists, and if any are older, they are all deleted.
Multiple <code>targetfileset</code> filesets may be specified.
Multiple <code>&lt;targetfileset&gt;</code> filesets may be specified.
</p> </p>


<h4>targetfilelist</h4> <h4>targetfilelist</h4>


<p> <p>
The nested <code>targetfilelist</code> element specifies a <a
The nested <code>&lt;targetfilelist&gt;</code> element specifies a <a
href="../CoreTypes/filelist.html">FileList</a>. All files included in href="../CoreTypes/filelist.html">FileList</a>. All files included in
this filelist will be compared against all files included in all of the this filelist will be compared against all files included in all of the
<code>srcfileset</code> filesets and <code>sourcefilelist</code>
<code>&lt;srcfileset&gt;</code> filesets and <code>&lt;sourcefilelist&gt;</code>
filelists, and if any are older, they are all deleted. filelists, and if any are older, they are all deleted.
Multiple <code>targetfilelist</code> filelists may be specified.
Multiple <code>&lt;targetfilelist&gt;</code> filelists may be specified.
</p> </p>


<h3>Examples</h3> <h3>Examples</h3>
<blockquote> <pre>
<blockquote> <pre>
&lt;dependset&gt; &lt;dependset&gt;
&lt;srcfilelist &lt;srcfilelist
dir = &quot;${dtd.dir}&quot; dir = &quot;${dtd.dir}&quot;
@@ -121,13 +134,13 @@ will be removed if any are out-of-date with respect to:</p>
</ol> </ol>


<p> <p>
If any of the source files in the above example does not exist, all
target files will also be removed. To ignore missing source files instead,
use filesets instead of filelists for the source files.
If any of the sources in the above example does not exist, all
target files will also be removed. To ignore missing sources instead,
use filesets instead of filelists for the sources.
</p> </p>


<hr> <hr>
<p align="center">Copyright &copy; 2001,2004-2005 The Apache Software Foundation.
<p align="center">Copyright &copy; 2001, 2004-2005 The Apache Software Foundation.
All rights All rights
Reserved.</p> Reserved.</p>




+ 57
- 1
src/etc/testcases/taskdefs/dependset.xml View File

@@ -40,7 +40,63 @@
</condition> </condition>
</fail> </fail>
</target> </target>

<target name="test6">
<touch file="older.tmp"/>
<sleep seconds="3" />
<touch file="newer.tmp"/>
<dependset>
<sources>
<file file="newer.tmp" />
</sources>
<targets>
<filelist dir="." files="older.tmp" />
</targets>
</dependset>
<fail>
<condition>
<available file="older.tmp" />
</condition>
</fail>
</target>

<target name="test7">
<touch file="older.tmp"/>
<dependset>
<sources>
<propertyresource name="thereisnosuchproperty" />
</sources>
<targets>
<filelist dir="." files="older.tmp" />
</targets>
</dependset>
<fail>
<condition>
<available file="older.tmp" />
</condition>
</fail>
</target>

<target name="test8">
<touch file="older.tmp" />
<property name="foo" value="bar" />
<dependset>
<sources>
<propertyresource name="foo" />
</sources>
<targets>
<filelist dir="." files="older.tmp" />
</targets>
</dependset>
<fail>
<condition>
<not>
<available file="older.tmp" />
</not>
</condition>
</fail>
</target>

<target name="cleanup"> <target name="cleanup">
<delete file="test4.tmp"/> <delete file="test4.tmp"/>
<delete file="older.tmp"/> <delete file="older.tmp"/>


+ 121
- 172
src/main/org/apache/tools/ant/taskdefs/DependSet.java View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2005 The Apache Software Foundation
* Copyright 2001-2005 The Apache Software Foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,15 +17,24 @@


package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import java.io.File;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Iterator;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileList;
import org.apache.tools.ant.types.Path;
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.types.Resource;
import org.apache.tools.ant.types.TimeComparison;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Sort;
import org.apache.tools.ant.types.resources.Union;
import org.apache.tools.ant.types.resources.Restrict;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.types.resources.selectors.Not;
import org.apache.tools.ant.types.resources.selectors.Exists;
import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
import org.apache.tools.ant.types.resources.comparators.Reverse;
import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;


/** /**
@@ -39,36 +48,32 @@ import org.apache.tools.ant.util.FileUtils;
* *
* nested arguments: * nested arguments:
* <ul> * <ul>
* <li>sources (resource union describing the source resources to examine)
* <li>srcfileset (fileset describing the source files to examine) * <li>srcfileset (fileset describing the source files to examine)
* <li>srcfilelist (filelist describing the source files to examine) * <li>srcfilelist (filelist describing the source files to examine)
* <li>targets (path describing the target files to examine)
* <li>targetfileset (fileset describing the target files to examine) * <li>targetfileset (fileset describing the target files to examine)
* <li>targetfilelist (filelist describing the target files to examine) * <li>targetfilelist (filelist describing the target files to examine)
* </ul> * </ul>
* At least one instance of either a fileset or filelist for both source and
* target are required.
* At least one of both source and target entities is required.
* <p> * <p>
* This task will examine each of the source files against each of the target
* files. If any target files are out of date with respect to any of the source
* files, all targets are removed. If any files named in a (src or target)
* filelist do not exist, all targets are removed.
* This task will examine each of the sources against each of the target files. If
* any target files are out of date with respect to any of the sources, all targets
* are removed. If any sources or targets do not exist, all targets are removed.
* Hint: If missing files should be ignored, specify them as include patterns * Hint: If missing files should be ignored, specify them as include patterns
* in filesets, rather than using filelists. * in filesets, rather than using filelists.
* </p><p> * </p><p>
* This task attempts to optimize speed of dependency checking. It will stop
* after the first out of date file is found and remove all targets, rather
* than exhaustively checking every source vs target combination unnecessarily.
* This task attempts to optimize speed of dependency checking
* by comparing only the dates of the oldest target file and the newest source.
* </p><p> * </p><p>
* Example uses: * Example uses:
* <ul><li> * <ul><li>
* Record the fact that an XML file must be up to date
* with respect to its XSD (Schema file), even though the XML file
* itself includes no reference to its XSD.
* Record the fact that an XML file must be up to date with respect to its XSD
* (Schema file), even though the XML file itself includes no reference to its XSD.
* </li><li> * </li><li>
* Record the fact that an XSL stylesheet includes other
* sub-stylesheets
* Record the fact that an XSL stylesheet includes other sub-stylesheets
* </li><li> * </li><li>
* Record the fact that java files must be recompiled if the ant build
* file changes
* Record the fact that java files must be recompiled if the ant build file changes
* </li></ul> * </li></ul>
* *
* @ant.task category="filesystem" * @ant.task category="filesystem"
@@ -76,25 +81,53 @@ import org.apache.tools.ant.util.FileUtils;
*/ */
public class DependSet extends MatchingTask { public class DependSet extends MatchingTask {


private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
private static final ResourceSelector NOT_EXISTS = new Not(new Exists());
private static final ResourceComparator DATE_ASC
= new org.apache.tools.ant.types.resources.comparators.Date();
private static final ResourceComparator DATE_DESC = new Reverse(DATE_ASC);

private static class NonExistent extends Restrict {
private NonExistent(ResourceCollection rc) {
super.add(rc);
super.add(NOT_EXISTS);
}
}
private static class Xest extends Sort {
private Xest(ResourceCollection rc, ResourceComparator c) {
super.add(c);
super.add(rc);
}
}
private static class Oldest extends Xest {
private Oldest(ResourceCollection rc) {
super(rc, DATE_ASC);
}
}
private static class Newest extends Xest {
private Newest(ResourceCollection rc) {
super(rc, DATE_DESC);
}
}


private Vector sourceFileSets = new Vector();
private Vector sourceFileLists = new Vector();
private Vector targetFileSets = new Vector();
private Vector targetFileLists = new Vector();
private Union sources = null;
private Path targets = null;


/** /**
* Creates a new DependSet Task.
**/
public DependSet() {
} //-- DependSet
* Create a nested sources element.
* @return a Union instance.
*/
public synchronized Union createSources() {
sources = (sources == null) ? new Union() : sources;
return sources;
}


/** /**
* Add a set of source files. * Add a set of source files.
* @param fs the FileSet to add. * @param fs the FileSet to add.
*/ */
public void addSrcfileset(FileSet fs) { public void addSrcfileset(FileSet fs) {
sourceFileSets.addElement(fs);
createSources().add(fs);
} }


/** /**
@@ -102,7 +135,16 @@ public class DependSet extends MatchingTask {
* @param fl the FileList to add. * @param fl the FileList to add.
*/ */
public void addSrcfilelist(FileList fl) { public void addSrcfilelist(FileList fl) {
sourceFileLists.addElement(fl);
createSources().add(fl);
}

/**
* Create a nested targets element.
* @return a Union instance.
*/
public synchronized Path createTargets() {
targets = (targets == null) ? new Path(getProject()) : targets;
return targets;
} }


/** /**
@@ -110,7 +152,7 @@ public class DependSet extends MatchingTask {
* @param fs the FileSet to add. * @param fs the FileSet to add.
*/ */
public void addTargetfileset(FileSet fs) { public void addTargetfileset(FileSet fs) {
targetFileSets.addElement(fs);
createTargets().add(fs);
} }


/** /**
@@ -118,158 +160,65 @@ public class DependSet extends MatchingTask {
* @param fl the FileList to add. * @param fl the FileList to add.
*/ */
public void addTargetfilelist(FileList fl) { public void addTargetfilelist(FileList fl) {
targetFileLists.addElement(fl);
createTargets().add(fl);
} }


/** /**
* Executes the task.
* Execute the task.
* @throws BuildException if errors occur. * @throws BuildException if errors occur.
*/ */
public void execute() throws BuildException { public void execute() throws BuildException {

if ((sourceFileSets.size() == 0) && (sourceFileLists.size() == 0)) {
throw new BuildException("At least one <srcfileset> or <srcfilelist>"
+ " element must be set");
if (sources == null) {
throw new BuildException(
"At least one set of source resources must be specified");
} }
if ((targetFileSets.size() == 0) && (targetFileLists.size() == 0)) {
throw new BuildException("At least one <targetfileset> or"
+ " <targetfilelist> element must be set");
if (targets == null) {
throw new BuildException(
"At least one set of target files must be specified");
} }
long now = (new Date()).getTime();
/*
We have to munge the time to allow for the filesystem time
granularity.
*/
now += FILE_UTILS.getFileTimestampGranularity();

// Grab all the target files specified via filesets:
Vector allTargets = new Vector();
long oldestTargetTime = 0;
File oldestTarget = null;
Enumeration enumTargetSets = targetFileSets.elements();
while (enumTargetSets.hasMoreElements()) {

FileSet targetFS = (FileSet) enumTargetSets.nextElement();
if (!targetFS.getDir(getProject()).exists()) {
// this is the same as if it was empty, no target files found
continue;
}
DirectoryScanner targetDS = targetFS.getDirectoryScanner(getProject());
String[] targetFiles = targetDS.getIncludedFiles();

for (int i = 0; i < targetFiles.length; i++) {

File dest = new File(targetFS.getDir(getProject()), targetFiles[i]);
allTargets.addElement(dest);

if (dest.lastModified() > now) {
log("Warning: " + targetFiles[i] + " modified in the future.",
Project.MSG_WARN);
}
if (oldestTarget == null
|| dest.lastModified() < oldestTargetTime) {
oldestTargetTime = dest.lastModified();
oldestTarget = dest;
}
}
//no sources = nothing to compare; no targets = nothing to delete:
if (sources.size() > 0 && targets.size() > 0 && !uptodate(sources, targets)) {
log("Deleting all target files.", Project.MSG_VERBOSE);
Delete delete = new Delete();
delete.bindToOwner(this);
delete.add(targets);
delete.perform();
} }
// Grab all the target files specified via filelists:
boolean upToDate = true;
Enumeration enumTargetLists = targetFileLists.elements();
while (enumTargetLists.hasMoreElements()) {

FileList targetFL = (FileList) enumTargetLists.nextElement();
String[] targetFiles = targetFL.getFiles(getProject());

for (int i = 0; i < targetFiles.length; i++) {
}


File dest = new File(targetFL.getDir(getProject()), targetFiles[i]);
if (!dest.exists()) {
log(targetFiles[i] + " does not exist.", Project.MSG_VERBOSE);
upToDate = false;
continue;
} else {
allTargets.addElement(dest);
}
if (dest.lastModified() > now) {
log("Warning: " + targetFiles[i] + " modified in the future.",
Project.MSG_WARN);
}
if (oldestTarget == null
|| dest.lastModified() < oldestTargetTime) {
oldestTargetTime = dest.lastModified();
oldestTarget = dest;
}
}
private boolean uptodate(ResourceCollection src, ResourceCollection target) {
org.apache.tools.ant.types.resources.selectors.Date datesel
= new org.apache.tools.ant.types.resources.selectors.Date();
datesel.setMillis(System.currentTimeMillis());
datesel.setWhen(TimeComparison.AFTER);
logFuture(targets, datesel);

int neTargets = new NonExistent(targets).size();
if (neTargets > 0) {
log(neTargets + " nonexistent targets", Project.MSG_VERBOSE);
return false;
} }
if (oldestTarget != null) {
log(oldestTarget + " is oldest target file", Project.MSG_VERBOSE);
} else {
// no target files, then we cannot remove any target files and
// skip the following tests right away
upToDate = false;
}
// Check targets vs source files specified via filelists:
if (upToDate) {
Enumeration enumSourceLists = sourceFileLists.elements();
while (upToDate && enumSourceLists.hasMoreElements()) {

FileList sourceFL = (FileList) enumSourceLists.nextElement();
String[] sourceFiles = sourceFL.getFiles(getProject());
FileResource oldestTarget = (FileResource) (new Oldest(targets).iterator().next());
log(oldestTarget + " is oldest target file", Project.MSG_VERBOSE);


for (int i = 0; upToDate && i < sourceFiles.length; i++) {
File src = new File(sourceFL.getDir(getProject()), sourceFiles[i]);
logFuture(sources, datesel);


if (src.lastModified() > now) {
log("Warning: " + sourceFiles[i]
+ " modified in the future.", Project.MSG_WARN);
}
if (!src.exists()) {
log(sourceFiles[i] + " does not exist.",
Project.MSG_VERBOSE);
upToDate = false;
break;
}
if (src.lastModified() > oldestTargetTime) {
upToDate = false;
log(oldestTarget + " is out of date with respect to "
+ sourceFiles[i], Project.MSG_VERBOSE);
}
}
}
int neSources = new NonExistent(sources).size();
if (neSources > 0) {
log(neSources + " nonexistent sources", Project.MSG_VERBOSE);
return false;
} }
// Check targets vs source files specified via filesets:
if (upToDate) {
Enumeration enumSourceSets = sourceFileSets.elements();
while (upToDate && enumSourceSets.hasMoreElements()) {

FileSet sourceFS = (FileSet) enumSourceSets.nextElement();
DirectoryScanner sourceDS = sourceFS.getDirectoryScanner(getProject());
String[] sourceFiles = sourceDS.getIncludedFiles();

for (int i = 0; upToDate && i < sourceFiles.length; i++) {
File src = new File(sourceFS.getDir(getProject()), sourceFiles[i]);
Resource newestSource = (Resource) (new Newest(sources).iterator().next());
log(newestSource.toLongString() + " is newest source", Project.MSG_VERBOSE);
return oldestTarget.getLastModified() >= newestSource.getLastModified();
}


if (src.lastModified() > now) {
log("Warning: " + sourceFiles[i]
+ " modified in the future.", Project.MSG_WARN);
}
if (src.lastModified() > oldestTargetTime) {
upToDate = false;
log(oldestTarget + " is out of date with respect to "
+ sourceFiles[i], Project.MSG_VERBOSE);
}
}
}
}
if (!upToDate) {
log("Deleting all target files. ", Project.MSG_VERBOSE);
for (Enumeration e = allTargets.elements(); e.hasMoreElements();) {
File fileToRemove = (File) e.nextElement();
log("Deleting file " + fileToRemove.getAbsolutePath(),
Project.MSG_VERBOSE);
fileToRemove.delete();
}
private void logFuture(ResourceCollection rc, ResourceSelector rsel) {
Restrict r = new Restrict();
r.add(rsel);
r.add(rc);
for (Iterator i = r.iterator(); i.hasNext();) {
log("Warning: " + i.next() + " modified in the future.", Project.MSG_WARN);
} }
} }
} }

+ 9
- 0
src/testcases/org/apache/tools/ant/taskdefs/DependSetTest.java View File

@@ -57,4 +57,13 @@ public class DependSetTest extends BuildFileTest {
executeTarget("test5"); executeTarget("test5");
} }


public void test6() {
executeTarget("test6");
}
public void test7() {
executeTarget("test7");
}
public void test8() {
executeTarget("test8");
}
} }

Loading…
Cancel
Save