diff --git a/docs/manual/CoreTasks/apply.html b/docs/manual/CoreTasks/apply.html
index 4ce2dcf2c..80c403c01 100644
--- a/docs/manual/CoreTasks/apply.html
+++ b/docs/manual/CoreTasks/apply.html
@@ -16,12 +16,16 @@ compatibility.
Executes a system command. When the os attribute is specified, then
the command is only executed when Ant is run on one of the specified operating
systems.
-The files and/or directories of a number of
+
+
The files and/or directories of a number of Resource Collections
+– including but not restricted to
FileSets,
DirSets
(since Ant 1.6) or
FileLists
(since Ant 1.6)
+–
are passed as arguments to the system command.
If you specify a nested mapper,
the timestamp of each source file is compared to the timestamp of a
@@ -283,6 +287,12 @@ elements to define the files for this task and refer to
You can use any number of nested <dirset>
elements to define the directories for this task and refer to
<dirset>
s defined elsewhere.
+
+
+since Ant 1.7
+You can use any number of nested resource collections.
+
mapper
A single <mapper>
specifies the target files relative
to the dest
attribute for dependency checking. If the
@@ -385,6 +395,17 @@ task. A reference to out
is then used as an
<outputmapper>
nested in a <redirector>
, which in turn is
nested beneath this <apply>
instance. This allows us to perform
dependency checking against output files--the target files in this case.
+
+<apply executable="ls" parallel="true"
+ force="true" dest="${basedir}" append="true" type="both">
+ <path>
+ <pathelement path="${env.PATH}"/>
+ </path>
+ <identitymapper/>
+</apply>
+
+Applies the "ls" executable to all directories in the PATH, effectively
+listing all executables that are available on the PATH.
Copyright © 2000-2005 The Apache Software Foundation. All rights
Reserved.
diff --git a/docs/manual/CoreTasks/chmod.html b/docs/manual/CoreTasks/chmod.html
index 449588a49..c929e7590 100644
--- a/docs/manual/CoreTasks/chmod.html
+++ b/docs/manual/CoreTasks/chmod.html
@@ -26,6 +26,10 @@ specified using nested <fileset>
or
Starting with Ant 1.6, this task also supports nested filelists.
+Starting with Ant 1.7, this task supports arbitrary Resource Collections
+as nested elements.
+
By default this task will use a single invocation of the underlying
chmod command. If you are working on a large number of files this may
result in a command line that is too long for your operating system.
diff --git a/docs/manual/OptionalTasks/attrib.html b/docs/manual/OptionalTasks/attrib.html
index 9537913bb..c5e187c10 100644
--- a/docs/manual/OptionalTasks/attrib.html
+++ b/docs/manual/OptionalTasks/attrib.html
@@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileLists can be specified using
nested <fileset>
, <dirset>
and
<filelist>
elements.
+Starting with Ant 1.7, this task supports arbitrary Resource Collections
+as nested elements.
+
By default this task will use a single invocation of the underlying
attrib command. If you are working on a large number of files this
may result in a command line that is too long for your operating
diff --git a/docs/manual/OptionalTasks/chgrp.html b/docs/manual/OptionalTasks/chgrp.html
index 0cfa5c984..9ce0d28c5 100644
--- a/docs/manual/OptionalTasks/chgrp.html
+++ b/docs/manual/OptionalTasks/chgrp.html
@@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileLists can be specified using
nested <fileset>
, <dirset>
and
<filelist>
elements.
+Starting with Ant 1.7, this task supports arbitrary Resource Collections
+as nested elements.
+
By default this task will use a single invocation of the underlying
chgrp command. If you are working on a large number of files this may
result in a command line that is too long for your operating system.
diff --git a/docs/manual/OptionalTasks/chown.html b/docs/manual/OptionalTasks/chown.html
index 6f20098df..af014f408 100644
--- a/docs/manual/OptionalTasks/chown.html
+++ b/docs/manual/OptionalTasks/chown.html
@@ -23,6 +23,9 @@ href="../CoreTypes/filelist.html">FileLists can be specified using
nested <fileset>
, <dirset>
and
<filelist>
elements.
+Starting with Ant 1.7, this task supports arbitrary Resource Collections
+as nested elements.
By default this task will use a single invocation of the underlying
chown command. If you are working on a large number of files this may
diff --git a/src/etc/testcases/taskdefs/exec/apply.xml b/src/etc/testcases/taskdefs/exec/apply.xml
index 019a57ce5..c67cad683 100755
--- a/src/etc/testcases/taskdefs/exec/apply.xml
+++ b/src/etc/testcases/taskdefs/exec/apply.xml
@@ -31,6 +31,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -394,6 +405,7 @@
+
@@ -428,6 +440,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java b/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
index 0444079da..e66ecc657 100644
--- a/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
+++ b/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
@@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
@@ -31,6 +32,10 @@ import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileList;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.SourceFileScanner;
@@ -43,13 +48,20 @@ import org.apache.tools.ant.util.SourceFileScanner;
*/
public class ExecuteOn extends ExecTask {
+ // filesets has been protected so we need to keep that even after
+ // switching to resource collections. In fact, they will still
+ // get a different treatment form the other resource collections
+ // even in execute since we have some subtle special features like
+ // switching type to "dir" when we encounter a DirSet that would
+ // be more difficult to achieve otherwise.
+
protected Vector filesets = new Vector(); // contains AbstractFileSet
// (both DirSet and FileSet)
- private Vector filelists = new Vector();
+ private Union resources = new Union();
private boolean relative = false;
private boolean parallel = false;
private boolean forwardSlash = false;
- protected String type = "file";
+ protected String type = FileDirBoth.FILE;
protected Commandline.Marker srcFilePos = null;
private boolean skipEmpty = false;
protected Commandline.Marker targetFilePos = null;
@@ -91,7 +103,18 @@ public class ExecuteOn extends ExecTask {
* @param list the FileList to add.
*/
public void addFilelist(FileList list) {
- filelists.addElement(list);
+ add(list);
+ }
+
+ /**
+ * Add a collection of resources upon which to operate.
+ * @param rc resource collection to add.
+ * @since Ant 1.7
+ */
+ public void add(ResourceCollection rc) {
+ if (rc instanceof FileSet)
+ throw new BuildException("Huh?");
+ resources.add(rc);
}
/**
@@ -273,8 +296,8 @@ public class ExecuteOn extends ExecTask {
log("!! execon is deprecated. Use apply instead. !!");
}
super.checkConfiguration();
- if (filesets.size() == 0 && filelists.size() == 0) {
- throw new BuildException("no filesets and no filelists specified",
+ if (filesets.size() == 0 && resources.size() == 0) {
+ throw new BuildException("no resources specified",
getLocation());
}
if (targetFilePos != null && mapperElement == null) {
@@ -326,19 +349,19 @@ public class ExecuteOn extends ExecTask {
String currentType = type;
AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i);
if (fs instanceof DirSet) {
- if (!"dir".equals(type)) {
+ if (!FileDirBoth.DIR.equals(type)) {
log("Found a nested dirset but type is " + type + ". "
+ "Temporarily switching to type=\"dir\" on the"
+ " assumption that you really did mean"
+ " not .", Project.MSG_DEBUG);
- currentType = "dir";
+ currentType = FileDirBoth.DIR;
}
}
File base = fs.getDir(getProject());
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
- if (!"dir".equals(currentType)) {
+ if (!FileDirBoth.DIR.equals(currentType)) {
String[] s = getFiles(base, ds);
for (int j = 0; j < s.length; j++) {
totalFiles++;
@@ -346,7 +369,7 @@ public class ExecuteOn extends ExecTask {
baseDirs.addElement(base);
}
}
- if (!"file".equals(currentType)) {
+ if (!FileDirBoth.FILE.equals(currentType)) {
String[] s = getDirs(base, ds);
for (int j = 0; j < s.length; j++) {
totalDirs++;
@@ -356,9 +379,9 @@ public class ExecuteOn extends ExecTask {
}
if (fileNames.size() == 0 && skipEmpty) {
int includedCount
- = ((!"dir".equals(currentType))
+ = ((!FileDirBoth.DIR.equals(currentType))
? ds.getIncludedFilesCount() : 0)
- + ((!"file".equals(currentType))
+ + ((!FileDirBoth.FILE.equals(currentType))
? ds.getIncludedDirsCount() : 0);
log("Skipping fileset for directory " + base + ". It is "
@@ -392,68 +415,67 @@ public class ExecuteOn extends ExecTask {
baseDirs.removeAllElements();
}
}
- for (int i = 0; i < filelists.size(); i++) {
- FileList list = (FileList) filelists.elementAt(i);
- File base = list.getDir(getProject());
- String[] names = getFilesAndDirs(list);
-
- for (int j = 0; j < names.length; j++) {
- File f = new File(base, names[j]);
- if ((!ignoreMissing) || (f.isFile() && !"dir".equals(type))
- || (f.isDirectory() && !"file".equals(type))) {
-
- if (ignoreMissing || f.isFile()) {
- totalFiles++;
- } else {
- totalDirs++;
- }
- fileNames.addElement(names[j]);
- baseDirs.addElement(base);
- }
- }
- if (fileNames.size() == 0 && skipEmpty) {
- DirectoryScanner ds = new DirectoryScanner();
- ds.setBasedir(base);
- ds.setIncludes(list.getFiles(getProject()));
- ds.scan();
- int includedCount
- = ds.getIncludedFilesCount() + ds.getIncludedDirsCount();
+
+ Iterator iter = resources.iterator();
+ while (iter.hasNext()) {
+ Resource res = (Resource) iter.next();
+
+ if (!res.isExists() && ignoreMissing) {
+ continue;
+ }
+
+ File base = null;
+ String name = res.getName();
+ if (res instanceof FileResource) {
+ FileResource fr = (FileResource) res;
+ base = fr.getBaseDir();
+ if (base == null) {
+ name = fr.getFile().getAbsolutePath();
+ }
+ }
+
+ if (restrict(new String[] {name}, base).length == 0) {
+ continue;
+ }
+
+ if ((!res.isDirectory() || !res.isExists())
+ && !FileDirBoth.DIR.equals(type)) {
+ totalFiles++;
+ } else if (res.isDirectory() && !FileDirBoth.FILE.equals(type)) {
+ totalDirs++;
+ } else {
+ continue;
+ }
+
+ baseDirs.add(base);
+ fileNames.add(name);
- log("Skipping filelist for directory " + base + ". It is "
- + ((includedCount > 0) ? "up to date." : "empty."),
- Project.MSG_INFO);
- continue;
- }
if (!parallel) {
- String[] s = new String[fileNames.size()];
- fileNames.copyInto(s);
- for (int j = 0; j < s.length; j++) {
- String[] command = getCommandline(s[j], base);
- log(Commandline.describeCommand(command),
- Project.MSG_VERBOSE);
- exe.setCommandline(command);
-
- if (redirectorElement != null) {
- setupRedirector();
- redirectorElement.configure(redirector, s[j]);
- }
- if (redirectorElement != null || haveExecuted) {
- // need to reset the stream handler to restart
- // reading of pipes;
- // go ahead and do it always w/ nested redirectors
- exe.setStreamHandler(redirector.createHandler());
- }
- runExecute(exe);
- haveExecuted = true;
- }
- fileNames.removeAllElements();
- baseDirs.removeAllElements();
- }
+ String[] command = getCommandline(name, base);
+ log(Commandline.describeCommand(command),
+ Project.MSG_VERBOSE);
+ exe.setCommandline(command);
+
+ if (redirectorElement != null) {
+ setupRedirector();
+ redirectorElement.configure(redirector, name);
+ }
+ if (redirectorElement != null || haveExecuted) {
+ // need to reset the stream handler to restart
+ // reading of pipes;
+ // go ahead and do it always w/ nested redirectors
+ exe.setStreamHandler(redirector.createHandler());
+ }
+ runExecute(exe);
+ haveExecuted = true;
+ fileNames.removeAllElements();
+ baseDirs.removeAllElements();
+ }
}
if (parallel && (fileNames.size() > 0 || !skipEmpty)) {
runParallel(exe, fileNames, baseDirs);
haveExecuted = true;
- }
+ }
if (haveExecuted) {
log("Applied " + cmdl.getExecutable() + " to "
+ totalFiles + " file"
@@ -697,11 +719,13 @@ public class ExecuteOn extends ExecTask {
* for the type attribute.
*/
public static class FileDirBoth extends EnumeratedAttribute {
+ public static final String FILE = "file";
+ public static final String DIR = "dir";
/**
* @see EnumeratedAttribute#getValues
*/
public String[] getValues() {
- return new String[] {"file", "dir", "both"};
+ return new String[] {FILE, DIR, "both"};
}
}
}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java b/src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java
index 30cc7f6bf..2f560e7ad 100755
--- a/src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java
@@ -31,6 +31,7 @@ import java.io.OutputStream;
public class ExecuteOnTest extends BuildFileTest {
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/";
private static final String BUILD_FILE = BUILD_PATH + "apply.xml";
+ private static final String LINE_SEP = System.getProperty("line.separator");
public ExecuteOnTest(String name) {
super(name);
@@ -562,6 +563,26 @@ public class ExecuteOnTest extends BuildFileTest {
executeTarget("testNoDest");
}
+ public void testLsPath() {
+ testLsPath("lsPath");
+ }
+
+ public void testLsPathParallel() {
+ testLsPath("lsPathParallel");
+ }
+
+ private void testLsPath(String target) {
+ executeTarget(target);
+ if (getProject().getProperty("ls.can.run") == null) {
+ return;
+ }
+ String foo = getProject().getProperty("foo");
+ assertNotNull(foo);
+ int indNoExt = foo.indexOf("ls" + LINE_SEP);
+ int indExe = foo.indexOf("ls.exe" + LINE_SEP);
+ assertTrue(indNoExt >= 0 || indExe >= 0);
+ }
+
//borrowed from TokenFilterTest
private String getFileString(String filename) throws IOException {
String result = null;