git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@292251 13f79535-47bb-0310-9956-ffa450edef68master
@@ -16,12 +16,16 @@ compatibility.</i></p> | |||||
<p>Executes a system command. When the <i>os</i> attribute is specified, then | <p>Executes a system command. When the <i>os</i> attribute is specified, then | ||||
the command is only executed when Ant is run on one of the specified operating | the command is only executed when Ant is run on one of the specified operating | ||||
systems.</p> | systems.</p> | ||||
<p>The files and/or directories of a number of | |||||
<p>The files and/or directories of a number of <a | |||||
href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
– including but not restricted to | |||||
<a href="../CoreTypes/fileset.html">FileSet</a>s, | <a href="../CoreTypes/fileset.html">FileSet</a>s, | ||||
<a href="../CoreTypes/dirset.html">DirSet</a>s | <a href="../CoreTypes/dirset.html">DirSet</a>s | ||||
(<em>since Ant 1.6</em>) or | (<em>since Ant 1.6</em>) or | ||||
<a href="../CoreTypes/filelist.html">FileList</a>s | <a href="../CoreTypes/filelist.html">FileList</a>s | ||||
(<em>since Ant 1.6</em>) | (<em>since Ant 1.6</em>) | ||||
– | |||||
are passed as arguments to the system command.</p> | are passed as arguments to the system command.</p> | ||||
<p>If you specify a nested <a href="../CoreTypes/mapper.html">mapper</a>, | <p>If you specify a nested <a href="../CoreTypes/mapper.html">mapper</a>, | ||||
the timestamp of each source file is compared to the timestamp of a | 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 | |||||
<p>You can use any number of nested <code><dirset></code> | <p>You can use any number of nested <code><dirset></code> | ||||
elements to define the directories for this task and refer to | elements to define the directories for this task and refer to | ||||
<code><dirset></code>s defined elsewhere.</p> | <code><dirset></code>s defined elsewhere.</p> | ||||
<h4>Any other <a href="../CoreTypes/resources.html#collection">Resource | |||||
Collection</a></h4> | |||||
<p><em>since Ant 1.7</em></p> | |||||
<p>You can use any number of nested resource collections.</p> | |||||
<h4>mapper</h4> | <h4>mapper</h4> | ||||
<p>A single <code><mapper></code> specifies the target files relative | <p>A single <code><mapper></code> specifies the target files relative | ||||
to the <code>dest</code> attribute for dependency checking. If the | to the <code>dest</code> attribute for dependency checking. If the | ||||
@@ -385,6 +395,17 @@ task. A reference to <code>out</code> is then used as an | |||||
<code><outputmapper></code> nested in a <code><redirector></code>, which in turn is | <code><outputmapper></code> nested in a <code><redirector></code>, which in turn is | ||||
nested beneath this <code><apply></code> instance. This allows us to perform | nested beneath this <code><apply></code> instance. This allows us to perform | ||||
dependency checking against output files--the target files in this case. | dependency checking against output files--the target files in this case. | ||||
<blockquote><pre> | |||||
<apply executable="ls" parallel="true" | |||||
force="true" dest="${basedir}" append="true" type="both"> | |||||
<path> | |||||
<pathelement path="${env.PATH}"/> | |||||
</path> | |||||
<identitymapper/> | |||||
</apply> | |||||
</pre></blockquote> | |||||
Applies the "ls" executable to all directories in the PATH, effectively | |||||
listing all executables that are available on the PATH. | |||||
<hr><p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | <hr><p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | ||||
Reserved.</p> | Reserved.</p> | ||||
@@ -26,6 +26,10 @@ specified using nested <code><fileset></code> or | |||||
<p>Starting with Ant 1.6, this task also supports nested <a | <p>Starting with Ant 1.6, this task also supports nested <a | ||||
href="../CoreTypes/filelist.html">filelist</a>s.</p> | href="../CoreTypes/filelist.html">filelist</a>s.</p> | ||||
<p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
as nested elements.</p> | |||||
<p>By default this task will use a single invocation of the underlying | <p>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 | 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. | result in a command line that is too long for your operating system. | ||||
@@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
<code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
<p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
as nested elements.</p> | |||||
<p>By default this task will use a single invocation of the underlying | <p>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 | 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 | may result in a command line that is too long for your operating | ||||
@@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
<code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
<p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
as nested elements.</p> | |||||
<p>By default this task will use a single invocation of the underlying | <p>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 | 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. | result in a command line that is too long for your operating system. | ||||
@@ -23,6 +23,9 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
<code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
<p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
as nested elements.</p> | |||||
<p>By default this task will use a single invocation of the underlying | <p>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 | chown command. If you are working on a large number of files this may | ||||
@@ -31,6 +31,17 @@ | |||||
<isset property="echo.exe.executable"/> | <isset property="echo.exe.executable"/> | ||||
</or> | </or> | ||||
</condition> | </condition> | ||||
<!-- UNIX --> | |||||
<available file="ls" filepath="${env.PATH}" property="ls.executable"/> | |||||
<!-- CYGWIN --> | |||||
<available file="ls.exe" filepath="${env.PATH}" property="ls.exe.executable"/> | |||||
<condition property="ls.can.run"> | |||||
<or> | |||||
<isset property="ls.executable"/> | |||||
<isset property="ls.exe.executable"/> | |||||
</or> | |||||
</condition> | |||||
</target> | </target> | ||||
<target name="xyz"> | <target name="xyz"> | ||||
@@ -394,6 +405,7 @@ | |||||
<ekko outputproperty="foo" /> | <ekko outputproperty="foo" /> | ||||
<ekko outputproperty="bar" force="true" /> | <ekko outputproperty="bar" force="true" /> | ||||
<fail> | <fail> | ||||
<condition> | <condition> | ||||
<not> | <not> | ||||
@@ -428,6 +440,26 @@ | |||||
</fail> | </fail> | ||||
</target> | </target> | ||||
<target name="lsPath" depends="init" if="ls.can.run"> | |||||
<apply executable="ls" parallel="false" outputproperty="foo" | |||||
force="true" dest="${basedir}" append="true" type="both"> | |||||
<path> | |||||
<pathelement path="${env.PATH}"/> | |||||
</path> | |||||
<identitymapper/> | |||||
</apply> | |||||
</target> | |||||
<target name="lsPathParallel" depends="init" if="ls.can.run"> | |||||
<apply executable="ls" parallel="true" outputproperty="foo" | |||||
force="true" dest="${basedir}" append="true" type="both"> | |||||
<path> | |||||
<pathelement path="${env.PATH}"/> | |||||
</path> | |||||
<identitymapper/> | |||||
</apply> | |||||
</target> | |||||
<target name="cleanup"> | <target name="cleanup"> | ||||
<delete> | <delete> | ||||
<fileset refid="xyz" /> | <fileset refid="xyz" /> | ||||
@@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.Hashtable; | import java.util.Hashtable; | ||||
import java.util.Iterator; | |||||
import java.util.Vector; | import java.util.Vector; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.DirectoryScanner; | 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.FileList; | ||||
import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
import org.apache.tools.ant.types.Mapper; | 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.FileNameMapper; | ||||
import org.apache.tools.ant.util.SourceFileScanner; | import org.apache.tools.ant.util.SourceFileScanner; | ||||
@@ -43,13 +48,20 @@ import org.apache.tools.ant.util.SourceFileScanner; | |||||
*/ | */ | ||||
public class ExecuteOn extends ExecTask { | 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 | protected Vector filesets = new Vector(); // contains AbstractFileSet | ||||
// (both DirSet and FileSet) | // (both DirSet and FileSet) | ||||
private Vector filelists = new Vector(); | |||||
private Union resources = new Union(); | |||||
private boolean relative = false; | private boolean relative = false; | ||||
private boolean parallel = false; | private boolean parallel = false; | ||||
private boolean forwardSlash = false; | private boolean forwardSlash = false; | ||||
protected String type = "file"; | |||||
protected String type = FileDirBoth.FILE; | |||||
protected Commandline.Marker srcFilePos = null; | protected Commandline.Marker srcFilePos = null; | ||||
private boolean skipEmpty = false; | private boolean skipEmpty = false; | ||||
protected Commandline.Marker targetFilePos = null; | protected Commandline.Marker targetFilePos = null; | ||||
@@ -91,7 +103,18 @@ public class ExecuteOn extends ExecTask { | |||||
* @param list the FileList to add. | * @param list the FileList to add. | ||||
*/ | */ | ||||
public void addFilelist(FileList list) { | 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. !!"); | log("!! execon is deprecated. Use apply instead. !!"); | ||||
} | } | ||||
super.checkConfiguration(); | 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()); | getLocation()); | ||||
} | } | ||||
if (targetFilePos != null && mapperElement == null) { | if (targetFilePos != null && mapperElement == null) { | ||||
@@ -326,19 +349,19 @@ public class ExecuteOn extends ExecTask { | |||||
String currentType = type; | String currentType = type; | ||||
AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i); | AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i); | ||||
if (fs instanceof DirSet) { | if (fs instanceof DirSet) { | ||||
if (!"dir".equals(type)) { | |||||
if (!FileDirBoth.DIR.equals(type)) { | |||||
log("Found a nested dirset but type is " + type + ". " | log("Found a nested dirset but type is " + type + ". " | ||||
+ "Temporarily switching to type=\"dir\" on the" | + "Temporarily switching to type=\"dir\" on the" | ||||
+ " assumption that you really did mean" | + " assumption that you really did mean" | ||||
+ " <dirset> not <fileset>.", Project.MSG_DEBUG); | + " <dirset> not <fileset>.", Project.MSG_DEBUG); | ||||
currentType = "dir"; | |||||
currentType = FileDirBoth.DIR; | |||||
} | } | ||||
} | } | ||||
File base = fs.getDir(getProject()); | File base = fs.getDir(getProject()); | ||||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | ||||
if (!"dir".equals(currentType)) { | |||||
if (!FileDirBoth.DIR.equals(currentType)) { | |||||
String[] s = getFiles(base, ds); | String[] s = getFiles(base, ds); | ||||
for (int j = 0; j < s.length; j++) { | for (int j = 0; j < s.length; j++) { | ||||
totalFiles++; | totalFiles++; | ||||
@@ -346,7 +369,7 @@ public class ExecuteOn extends ExecTask { | |||||
baseDirs.addElement(base); | baseDirs.addElement(base); | ||||
} | } | ||||
} | } | ||||
if (!"file".equals(currentType)) { | |||||
if (!FileDirBoth.FILE.equals(currentType)) { | |||||
String[] s = getDirs(base, ds); | String[] s = getDirs(base, ds); | ||||
for (int j = 0; j < s.length; j++) { | for (int j = 0; j < s.length; j++) { | ||||
totalDirs++; | totalDirs++; | ||||
@@ -356,9 +379,9 @@ public class ExecuteOn extends ExecTask { | |||||
} | } | ||||
if (fileNames.size() == 0 && skipEmpty) { | if (fileNames.size() == 0 && skipEmpty) { | ||||
int includedCount | int includedCount | ||||
= ((!"dir".equals(currentType)) | |||||
= ((!FileDirBoth.DIR.equals(currentType)) | |||||
? ds.getIncludedFilesCount() : 0) | ? ds.getIncludedFilesCount() : 0) | ||||
+ ((!"file".equals(currentType)) | |||||
+ ((!FileDirBoth.FILE.equals(currentType)) | |||||
? ds.getIncludedDirsCount() : 0); | ? ds.getIncludedDirsCount() : 0); | ||||
log("Skipping fileset for directory " + base + ". It is " | log("Skipping fileset for directory " + base + ". It is " | ||||
@@ -392,68 +415,67 @@ public class ExecuteOn extends ExecTask { | |||||
baseDirs.removeAllElements(); | 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) { | 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)) { | if (parallel && (fileNames.size() > 0 || !skipEmpty)) { | ||||
runParallel(exe, fileNames, baseDirs); | runParallel(exe, fileNames, baseDirs); | ||||
haveExecuted = true; | haveExecuted = true; | ||||
} | |||||
} | |||||
if (haveExecuted) { | if (haveExecuted) { | ||||
log("Applied " + cmdl.getExecutable() + " to " | log("Applied " + cmdl.getExecutable() + " to " | ||||
+ totalFiles + " file" | + totalFiles + " file" | ||||
@@ -697,11 +719,13 @@ public class ExecuteOn extends ExecTask { | |||||
* for the type attribute. | * for the type attribute. | ||||
*/ | */ | ||||
public static class FileDirBoth extends EnumeratedAttribute { | public static class FileDirBoth extends EnumeratedAttribute { | ||||
public static final String FILE = "file"; | |||||
public static final String DIR = "dir"; | |||||
/** | /** | ||||
* @see EnumeratedAttribute#getValues | * @see EnumeratedAttribute#getValues | ||||
*/ | */ | ||||
public String[] getValues() { | public String[] getValues() { | ||||
return new String[] {"file", "dir", "both"}; | |||||
return new String[] {FILE, DIR, "both"}; | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -31,6 +31,7 @@ import java.io.OutputStream; | |||||
public class ExecuteOnTest extends BuildFileTest { | public class ExecuteOnTest extends BuildFileTest { | ||||
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | 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 BUILD_FILE = BUILD_PATH + "apply.xml"; | ||||
private static final String LINE_SEP = System.getProperty("line.separator"); | |||||
public ExecuteOnTest(String name) { | public ExecuteOnTest(String name) { | ||||
super(name); | super(name); | ||||
@@ -562,6 +563,26 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
executeTarget("testNoDest"); | 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 | //borrowed from TokenFilterTest | ||||
private String getFileString(String filename) throws IOException { | private String getFileString(String filename) throws IOException { | ||||
String result = null; | String result = null; | ||||