PR: 1763 Merge <apply> and <execon> into a single task (and keep Transform as an empty class for backwards compatibility at the source level). git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269330 13f79535-47bb-0310-9956-ffa450edef68master
@@ -108,6 +108,8 @@ Other changes: | |||
* New update attribute for <zip> and friends - update an existing | |||
archive instead of creating a new one. | |||
* <apply> and <execon> have been merged into a single task. | |||
Fixed bugs: | |||
----------- | |||
@@ -175,6 +177,9 @@ Fixed bugs: | |||
* <junit> tries to include all necessary classes for the task itself | |||
to the classpath when running in fork mode - doesn't work for JDK 1.1 | |||
* <apply> and <execon> do now execute the command only once, if you | |||
specify the parallel attribute - instead of once per fileset. | |||
Changes from Ant 1.2 to Ant 1.3 | |||
=========================================== | |||
@@ -7,17 +7,23 @@ | |||
<body> | |||
<h2><a name="apply">Apply</a></h2> | |||
<h2><a name="apply">Apply/<i>ExecOn</i></a></h2> | |||
<p><i>The name execon is deprecated and only kept for backwards | |||
compatibilty.</i></p> | |||
<h3>Description</h3> | |||
<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 | |||
systems.</p> | |||
<p>The files and/or directories of a number of <a | |||
href="../CoreTypes/fileset.html">FileSet</a>s are passed as arguments to the system | |||
command. The timestamp of each source file is compared to the | |||
timestamp of a target file which is defined by a nested <a | |||
href="../CoreTypes/mapper.html">mapper</a> element. At least one fileset and exactly | |||
one mapper element are required.</p> | |||
href="../CoreTypes/fileset.html">FileSet</a>s are passed as arguments | |||
to the system command.</p> | |||
<p>If you specify a nested <a | |||
href="../CoreTypes/mapper.html">mapper</a> and the destdir attribute, | |||
the timestamp of each source file is compared to the timestamp of a | |||
target file which is defined by the nested mapper element and searched | |||
for in the given destdir.</p> | |||
<p>At least one fileset is required, you must not specify more than | |||
one mapper.</p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
@@ -36,7 +42,7 @@ one mapper element are required.</p> | |||
<td valign="top">the directory where the <apply> expects the target files will be placed by the | |||
command, when it is executed. | |||
</td> | |||
<td align="center" valign="top">Yes</td> | |||
<td align="center" valign="top">Yes, if you specify a nested mapper</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">dir</td> | |||
@@ -67,12 +73,6 @@ one mapper element are required.</p> | |||
returncode other than 0.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">newenvironment</td> | |||
<td valign="top">Do not propagate old environment when new environment | |||
variables are specified.</td> | |||
<td align="center" valign="top">No, default is <i>false</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">skipemptyfilesets</td> | |||
<td valign="top">Don't run the command, if no source files have | |||
@@ -95,6 +95,23 @@ one mapper element are required.</p> | |||
the names of directories are considered.</td> | |||
<td align="center" valign="top">No, default is <i>file</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">newenvironment</td> | |||
<td valign="top">Do not propagate old environment when new environment | |||
variables are specified.</td> | |||
<td align="center" valign="top">No, default is <i>false</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">vmlauncher</td> | |||
<td valign="top">Run command using the Java VM's execution facilities | |||
where available. If set to false the underlying OS's shell, | |||
either directly or through the antRun scripts, will be used. | |||
Under some operating systems, this gives access to facilities | |||
not normally available through the VM including, under Windows, | |||
being able to execute scripts, rather than their associated | |||
interpreter.</td> | |||
<td align="center" valign="top">No, default is <i>true</i></td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>fileset</h4> | |||
@@ -114,7 +131,9 @@ use a nested <code><srcfile></code> element between your | |||
<p><code><targetfile></code> is similar to | |||
<code><srcfile></code> and marks the position of the target | |||
filename on the command line. If omitted, the target filenames will | |||
not be added to the command line at all.</p> | |||
not be added to the command line at all. This element can only be | |||
specified, if you also define a nested mapper and the destdir | |||
attribute.</p> | |||
<h4>env</h4> | |||
<p>It is possible to specify environment variables to pass to the | |||
system command via nested <code><env></code> elements. See the | |||
@@ -124,6 +143,34 @@ description in the section about <a href="exec.html#env">exec</a></p> | |||
<code><env></code>.</p> | |||
<h3>Examples</h3> | |||
<blockquote><pre> | |||
<apply executable="ls" > | |||
<arg value="-l"/> | |||
<fileset dir="/tmp"> | |||
<patternset> | |||
<exclude name="**/*.txt"/> | |||
</patternset> | |||
</fileset> | |||
<fileset refid="other.files"/> | |||
</apply> | |||
</pre></blockquote> | |||
<p>invokes <code>ls -l</code>, adding the absolute filenames of all | |||
files below <code>/tmp</code> not ending in <code>.txt</code> and all | |||
files of the FileSet with <code>id</code> <code>other.files</code> to | |||
the command line.</p> | |||
<blockquote><pre> | |||
<apply executable="somecommand" parallel="false" > | |||
<arg value="arg1"/> | |||
<srfile/> | |||
<arg value="arg2"/> | |||
<fileset dir="/tmp"/> | |||
</apply> | |||
</pre></blockquote> | |||
<p>invokes <code>somecommand arg1 SOURCEFILENAME arg2</code> for each | |||
file in <code>/tmp</code> replacing SOURCEFILENAME with the absolute | |||
filename of each file in turn. If <code>parallel</code> had been set | |||
to true, SOURCEFILENAME would be replaced with the absolute filenames | |||
of all files separated by spaces.</p> | |||
<blockquote><pre> | |||
<apply executable="cc" dest="src/C" parallel="false"> | |||
<arg value="-c"/> | |||
<arg value="-o"/> | |||
@@ -1,156 +0,0 @@ | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"> | |||
<title>Ant User Manual</title> | |||
</head> | |||
<body> | |||
<h2><a name="execon">ExecOn</a></h2> | |||
<h3>Description</h3> | |||
<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 | |||
systems.</p> | |||
<p>The files and/or directories of a number of <a | |||
href="../CoreTypes/fileset.html">FileSet</a>s are passed as arguments to the system | |||
command. At least one nested <code><fileset></code> is required.</p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">executable</td> | |||
<td valign="top">the command to execute without any command line | |||
arguments.</td> | |||
<td align="center" valign="top">Yes</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">dir</td> | |||
<td valign="top">the directory in which the command should be executed.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">os</td> | |||
<td valign="top">list of Operating Systems on which the command may be | |||
executed. If the current OS's name is contained in this list, the command will | |||
be executed. The OS's name is determined by the Java Virtual machine and is set | |||
in the "os.name" system property.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">output</td> | |||
<td valign="top">the file to which the output of the command should be | |||
redirected.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">timeout</td> | |||
<td valign="top">Stop the command if it doesn't finish within the | |||
specified time (given in milliseconds).</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">failonerror</td> | |||
<td valign="top">Stop the buildprocess if the command exits with a | |||
returncode other than 0.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">newenvironment</td> | |||
<td valign="top">Do not propagate old environment when new environment | |||
variables are specified.</td> | |||
<td align="center" valign="top">No, default is <i>false</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">vmlauncher</td> | |||
<td valign="top">Run command using the Java VM's execution facilities | |||
where available. If set to false the underlying OS's shell, | |||
either directly or through the antRun scripts, will be used. | |||
Under some operating systems, this gives access to facilities | |||
not nomrally available through the VM including, under Windows, | |||
being able to execute scripts, rather than their associated | |||
interpreter.</td> | |||
<td align="center" valign="top">No, default is <i>true</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">skipemptyfilesets</td> | |||
<td valign="top">Don't run the command, if no source files have | |||
been found.</td> | |||
<td align="center" valign="top">No, default is <i>false</i></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">parallel</td> | |||
<td valign="top">Run the command only once, appending all files as | |||
arguments. If false, command will be executed once for every file. | |||
Defaults to false. </td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">type</td> | |||
<td valign="top">One of <i>file</i>, <i>dir</i> or | |||
<i>both</i>. If set to <i>file</i>, only the names of plain | |||
files will be sent to the command. If set to <i>dir</i>, only | |||
the names of directories are considered.</td> | |||
<td align="center" valign="top">No, default is <i>file</i></td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>fileset</h4> | |||
<p>You can use any number of nested <code><fileset></code> | |||
elements to define the files for this task and refer to | |||
<code><fileset></code>s defined elsewhere.</p> | |||
<h4>arg</h4> | |||
<p>Command line arguments should be specified as nested | |||
<code><arg></code> elements. See <a | |||
href="../using.html#arg">Command line arguments</a>.</p> | |||
<h4>srcfile</h4> | |||
<p>By default the file names of the source files will be added to the | |||
end of the command line. If you need to place it somewhere different, | |||
use a nested <code><srcfile></code> element between your | |||
<code><arg></code> elements to mark the insertion point.</p> | |||
<h4>env</h4> | |||
<p>It is possible to specify environment variables to pass to the | |||
system command via nested <code><env></code> elements. See the | |||
description in the section about <a href="exec.html#env">exec</a></p> | |||
<p>Please note that the environment of the current Ant process is | |||
<b>not</b> passed to the system command if you specify variables using | |||
<code><env></code>.</p> | |||
<h3>Examples</h3> | |||
<blockquote><pre> | |||
<execon executable="ls" > | |||
<arg value="-l"/> | |||
<fileset dir="/tmp"> | |||
<patternset> | |||
<exclude name="**/*.txt"/> | |||
</patternset> | |||
</fileset> | |||
<fileset refid="other.files"/> | |||
</execon> | |||
</pre></blockquote> | |||
<p>invokes <code>ls -l</code>, adding the absolute filenames of all | |||
files below <code>/tmp</code> not ending in <code>.txt</code> and all | |||
files of the FileSet with <code>id</code> <code>other.files</code> to | |||
the command line.</p> | |||
<blockquote><pre> | |||
<execon executable="somecommand" parallel="false" > | |||
<arg value="arg1"/> | |||
<srfile/> | |||
<arg value="arg2"/> | |||
<fileset dir="/tmp"/> | |||
</execon> | |||
</pre></blockquote> | |||
<p>invokes <code>somecommand arg1 SOURCEFILENAME arg2</code> for each | |||
file in <code>/tmp</code> replacing SOURCEFILENAME with the absolute | |||
filename of each file in turn. If <code>parallel</code> had been set | |||
to true, SOURCEFILENAME would be replaced with the absolute filenames | |||
of all files separated by spaces.</p> | |||
<hr> | |||
<p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | |||
Reserved.</p> | |||
</body> | |||
</html> | |||
@@ -23,7 +23,7 @@ | |||
<a href="CoreTasks/ant.html">Ant</a><br> | |||
<a href="CoreTasks/antcall.html">AntCall</a><br> | |||
<a href="CoreTasks/antstructure.html">AntStructure</a><br> | |||
<a href="CoreTasks/apply.html">Apply</a><br> | |||
<a href="CoreTasks/apply.html">Apply/<i>ExecOn</i></a><br> | |||
<a href="CoreTasks/available.html">Available</a><br> | |||
<a href="CoreTasks/chmod.html">Chmod</a><br> | |||
<a href="CoreTasks/copy.html">Copy</a><br> | |||
@@ -36,7 +36,6 @@ | |||
<a href="CoreTasks/ear.html">Ear</a><br> | |||
<a href="CoreTasks/echo.html">Echo</a><br> | |||
<a href="CoreTasks/exec.html">Exec</a><br> | |||
<a href="CoreTasks/execon.html">ExecOn</a><br> | |||
<a href="CoreTasks/fail.html">Fail</a><br> | |||
<a href="CoreTasks/filter.html">Filter</a><br> | |||
<a href="CoreTasks/fixcrlf.html">FixCRLF</a><br> | |||
@@ -56,7 +56,9 @@ package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.*; | |||
import org.apache.tools.ant.util.*; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -74,6 +76,15 @@ public class ExecuteOn extends ExecTask { | |||
protected String type = "file"; | |||
protected Commandline.Marker srcFilePos = null; | |||
private boolean skipEmpty = false; | |||
protected Commandline.Marker targetFilePos = null; | |||
protected Mapper mapperElement = null; | |||
protected FileNameMapper mapper = null; | |||
protected File destDir = null; | |||
/** | |||
* Has <srcfile> been specified before <targetfile> | |||
*/ | |||
protected boolean srcIsFirst = true; | |||
/** | |||
* Adds a set of files (nested fileset attribute). | |||
@@ -103,6 +114,13 @@ public class ExecuteOn extends ExecTask { | |||
skipEmpty = skip; | |||
} | |||
/** | |||
* Set the destination directory. | |||
*/ | |||
public void setDest(File destDir) { | |||
this.destDir = destDir; | |||
} | |||
/** | |||
* Marker that indicates where the name of the source file should | |||
* be put on the command line. | |||
@@ -116,18 +134,62 @@ public class ExecuteOn extends ExecTask { | |||
return srcFilePos; | |||
} | |||
/** | |||
* Marker that indicates where the name of the target file should | |||
* be put on the command line. | |||
*/ | |||
public Commandline.Marker createTargetfile() { | |||
if (targetFilePos != null) { | |||
throw new BuildException(taskType + " doesn\'t support multiple targetfile elements.", | |||
location); | |||
} | |||
targetFilePos = cmdl.createMarker(); | |||
srcIsFirst = (srcFilePos != null); | |||
return targetFilePos; | |||
} | |||
/** | |||
* Defines the FileNameMapper to use (nested mapper element). | |||
*/ | |||
public Mapper createMapper() throws BuildException { | |||
if (mapperElement != null) { | |||
throw new BuildException("Cannot define more than one mapper", | |||
location); | |||
} | |||
mapperElement = new Mapper(project); | |||
return mapperElement; | |||
} | |||
protected void checkConfiguration() { | |||
if ("execon".equals(taskName)) { | |||
log("!! execon is deprecated. Use apply instead. !!"); | |||
} | |||
super.checkConfiguration(); | |||
if (filesets.size() == 0) { | |||
throw new BuildException("no filesets specified", location); | |||
} | |||
if (targetFilePos != null || mapperElement != null | |||
|| destDir != null) { | |||
if (mapperElement == null) { | |||
throw new BuildException("no mapper specified", location); | |||
} | |||
if (mapperElement == null) { | |||
throw new BuildException("no dest attribute specified", | |||
location); | |||
} | |||
mapper = mapperElement.getImplementation(); | |||
} | |||
} | |||
protected void runExec(Execute exe) throws BuildException { | |||
try { | |||
Vector fileNames = new Vector(); | |||
Vector baseDirs = new Vector(); | |||
for (int i=0; i<filesets.size(); i++) { | |||
Vector v = new Vector(); | |||
FileSet fs = (FileSet) filesets.elementAt(i); | |||
File base = fs.getDir(project); | |||
DirectoryScanner ds = fs.getDirectoryScanner(project); | |||
@@ -135,36 +197,28 @@ public class ExecuteOn extends ExecTask { | |||
if (!"dir".equals(type)) { | |||
String[] s = getFiles(base, ds); | |||
for (int j=0; j<s.length; j++) { | |||
v.addElement(s[j]); | |||
fileNames.addElement(s[j]); | |||
baseDirs.addElement(base); | |||
} | |||
} | |||
if (!"file".equals(type)) { | |||
String[] s = getDirs(base, ds);; | |||
for (int j=0; j<s.length; j++) { | |||
v.addElement(s[j]); | |||
fileNames.addElement(s[j]); | |||
baseDirs.addElement(base); | |||
} | |||
} | |||
if (v.size() == 0 && skipEmpty) { | |||
if (fileNames.size() == 0 && skipEmpty) { | |||
log("Skipping fileset for directory " | |||
+ base + ". It is empty.", Project.MSG_INFO); | |||
continue; | |||
} | |||
String[] s = new String[v.size()]; | |||
v.copyInto(s); | |||
int err = -1; | |||
if (parallel) { | |||
String[] command = getCommandline(s, base); | |||
log("Executing " + Commandline.toString(command), | |||
Project.MSG_VERBOSE); | |||
exe.setCommandline(command); | |||
runExecute(exe); | |||
} else { | |||
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("Executing " + Commandline.toString(command), | |||
@@ -172,9 +226,23 @@ public class ExecuteOn extends ExecTask { | |||
exe.setCommandline(command); | |||
runExecute(exe); | |||
} | |||
fileNames.removeAllElements(); | |||
baseDirs.removeAllElements(); | |||
} | |||
} | |||
if (parallel) { | |||
String[] s = new String[fileNames.size()]; | |||
fileNames.copyInto(s); | |||
File[] b = new File[baseDirs.size()]; | |||
baseDirs.copyInto(b); | |||
String[] command = getCommandline(s, b); | |||
log("Executing " + Commandline.toString(command), | |||
Project.MSG_VERBOSE); | |||
exe.setCommandline(command); | |||
runExecute(exe); | |||
} | |||
} catch (IOException e) { | |||
throw new BuildException("Execute failed: " + e, e, location); | |||
} finally { | |||
@@ -189,22 +257,87 @@ public class ExecuteOn extends ExecTask { | |||
* @param srcFiles The filenames to add to the commandline | |||
* @param baseDir filenames are relative to this dir | |||
*/ | |||
protected String[] getCommandline(String[] srcFiles, File baseDir) { | |||
protected String[] getCommandline(String[] srcFiles, File[] baseDirs) { | |||
Vector targets = new Vector(); | |||
if (targetFilePos != null) { | |||
Hashtable addedFiles = new Hashtable(); | |||
for (int i=0; i<srcFiles.length; i++) { | |||
String[] subTargets = mapper.mapFileName(srcFiles[i]); | |||
if (subTargets != null) { | |||
for (int j=0; j<subTargets.length; j++) { | |||
String name = (new File(destDir, subTargets[j])).getAbsolutePath(); | |||
if (!addedFiles.contains(name)) { | |||
targets.addElement(name); | |||
addedFiles.put(name, name); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
String[] targetFiles = new String[targets.size()]; | |||
targets.copyInto(targetFiles); | |||
String[] orig = cmdl.getCommandline(); | |||
String[] result = new String[orig.length+srcFiles.length]; | |||
String[] result = new String[orig.length+srcFiles.length+targetFiles.length]; | |||
int index = orig.length; | |||
int srcIndex = orig.length; | |||
if (srcFilePos != null) { | |||
index = srcFilePos.getPosition(); | |||
srcIndex = srcFilePos.getPosition(); | |||
} | |||
System.arraycopy(orig, 0, result, 0, index); | |||
if (targetFilePos != null) { | |||
int targetIndex = targetFilePos.getPosition(); | |||
if (srcIndex < targetIndex | |||
|| (srcIndex == targetIndex && srcIsFirst)) { | |||
// 0 --> srcIndex | |||
System.arraycopy(orig, 0, result, 0, srcIndex); | |||
// srcIndex --> targetIndex | |||
System.arraycopy(orig, srcIndex, result, | |||
srcIndex + srcFiles.length, | |||
targetIndex - srcIndex); | |||
// targets are already absolute file names | |||
System.arraycopy(targetFiles, 0, result, | |||
targetIndex + srcFiles.length, | |||
targetFiles.length); | |||
// targetIndex --> end | |||
System.arraycopy(orig, targetIndex, result, | |||
targetIndex + srcFiles.length + targetFiles.length, | |||
orig.length - targetIndex); | |||
} else { | |||
// 0 --> targetIndex | |||
System.arraycopy(orig, 0, result, 0, targetIndex); | |||
// targets are already absolute file names | |||
System.arraycopy(targetFiles, 0, result, | |||
targetIndex, | |||
targetFiles.length); | |||
// targetIndex --> srcIndex | |||
System.arraycopy(orig, targetIndex, result, | |||
targetIndex + targetFiles.length, | |||
srcIndex - targetIndex); | |||
// srcIndex --> end | |||
System.arraycopy(orig, srcIndex, result, | |||
srcIndex + srcFiles.length + targetFiles.length, | |||
orig.length - srcIndex); | |||
srcIndex += targetFiles.length; | |||
} | |||
} else { // no targetFilePos | |||
System.arraycopy(orig, 0, result, 0, srcIndex); | |||
} | |||
// fill in source file names | |||
for (int i=0; i < srcFiles.length; i++) { | |||
result[index+i] = (new File(baseDir, srcFiles[i])).getAbsolutePath(); | |||
result[srcIndex+i] = | |||
(new File(baseDirs[i], srcFiles[i])).getAbsolutePath(); | |||
} | |||
System.arraycopy(orig, index, result, index+srcFiles.length, | |||
orig.length-index); | |||
return result; | |||
} | |||
@@ -215,23 +348,35 @@ public class ExecuteOn extends ExecTask { | |||
* @param baseDir filename is relative to this dir | |||
*/ | |||
protected String[] getCommandline(String srcFile, File baseDir) { | |||
return getCommandline(new String[] {srcFile}, baseDir); | |||
return getCommandline(new String[] {srcFile}, new File[] {baseDir}); | |||
} | |||
/** | |||
* Return the list of files from this DirectoryScanner that should | |||
* be included on the command line. | |||
*/ | |||
protected String[] getFiles(File basedir, DirectoryScanner ds) { | |||
return ds.getIncludedFiles(); | |||
protected String[] getFiles(File baseDir, DirectoryScanner ds) { | |||
if (mapper != null) { | |||
SourceFileScanner sfs = new SourceFileScanner(this); | |||
return sfs.restrict(ds.getIncludedFiles(), baseDir, destDir, | |||
mapper); | |||
} else { | |||
return ds.getIncludedFiles(); | |||
} | |||
} | |||
/** | |||
* Return the list of Directories from this DirectoryScanner that | |||
* should be included on the command line. | |||
*/ | |||
protected String[] getDirs(File basedir, DirectoryScanner ds) { | |||
return ds.getIncludedDirectories(); | |||
protected String[] getDirs(File baseDir, DirectoryScanner ds) { | |||
if (mapper != null) { | |||
SourceFileScanner sfs = new SourceFileScanner(this); | |||
return sfs.restrict(ds.getIncludedDirectories(), baseDir, destDir, | |||
mapper); | |||
} else { | |||
return ds.getIncludedDirectories(); | |||
} | |||
} | |||
/** | |||
@@ -54,193 +54,9 @@ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.*; | |||
import org.apache.tools.ant.util.*; | |||
/** | |||
* Executes a given command, supplying a set of files as arguments. | |||
* | |||
* <p>Only those files that are newer than their corresponding target | |||
* files will be handeled, the rest will be ignored.</p> | |||
* Has been merged into ExecuteOn, empty class for backwards compatibility. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class Transform extends ExecuteOn { | |||
protected Commandline.Marker targetFilePos = null; | |||
protected Mapper mapperElement = null; | |||
protected FileNameMapper mapper = null; | |||
protected File destDir = null; | |||
/** | |||
* Has <srcfile> been specified before <targetfile> | |||
*/ | |||
protected boolean srcIsFirst = true; | |||
/** | |||
* Set the destination directory. | |||
*/ | |||
public void setDest(File destDir) { | |||
this.destDir = destDir; | |||
} | |||
/** | |||
* Marker that indicates where the name of the target file should | |||
* be put on the command line. | |||
*/ | |||
public Commandline.Marker createTargetfile() { | |||
if (targetFilePos != null) { | |||
throw new BuildException(taskType + " doesn\'t support multiple targetfile elements.", | |||
location); | |||
} | |||
targetFilePos = cmdl.createMarker(); | |||
srcIsFirst = (srcFilePos != null); | |||
return targetFilePos; | |||
} | |||
/** | |||
* Defines the FileNameMapper to use (nested mapper element). | |||
*/ | |||
public Mapper createMapper() throws BuildException { | |||
if (mapperElement != null) { | |||
throw new BuildException("Cannot define more than one mapper", | |||
location); | |||
} | |||
mapperElement = new Mapper(project); | |||
return mapperElement; | |||
} | |||
protected void checkConfiguration() { | |||
super.checkConfiguration(); | |||
if (mapperElement == null) { | |||
throw new BuildException("no mapper specified", location); | |||
} | |||
if (destDir == null) { | |||
throw new BuildException("no dest attribute specified", location); | |||
} | |||
mapper = mapperElement.getImplementation(); | |||
} | |||
/** | |||
* Return the list of files from this DirectoryScanner that should | |||
* be included on the command line - i.e. only those that are | |||
* newer than the corresponding target files. | |||
*/ | |||
protected String[] getFiles(File baseDir, DirectoryScanner ds) { | |||
SourceFileScanner sfs = new SourceFileScanner(this); | |||
return sfs.restrict(ds.getIncludedFiles(), baseDir, destDir, mapper); | |||
} | |||
/** | |||
* Return the list of Directories from this DirectoryScanner that | |||
* should be included on the command line - i.e. only those that | |||
* are newer than the corresponding target files. | |||
*/ | |||
protected String[] getDirs(File baseDir, DirectoryScanner ds) { | |||
SourceFileScanner sfs = new SourceFileScanner(this); | |||
return sfs.restrict(ds.getIncludedDirectories(), baseDir, destDir, | |||
mapper); | |||
} | |||
/** | |||
* Construct the command line for parallel execution. | |||
* | |||
* @param srcFiles The filenames to add to the commandline | |||
* @param baseDir filenames are relative to this dir | |||
*/ | |||
protected String[] getCommandline(String[] srcFiles, File baseDir) { | |||
if (targetFilePos == null) { | |||
return super.getCommandline(srcFiles, baseDir); | |||
} | |||
Vector targets = new Vector(); | |||
Hashtable addedFiles = new Hashtable(); | |||
for (int i=0; i<srcFiles.length; i++) { | |||
String[] subTargets = mapper.mapFileName(srcFiles[i]); | |||
if (subTargets != null) { | |||
for (int j=0; j<subTargets.length; j++) { | |||
String name = (new File(destDir, subTargets[j])).getAbsolutePath(); | |||
if (!addedFiles.contains(name)) { | |||
targets.addElement(name); | |||
addedFiles.put(name, name); | |||
} | |||
} | |||
} | |||
} | |||
String[] targetFiles = new String[targets.size()]; | |||
targets.copyInto(targetFiles); | |||
String[] orig = cmdl.getCommandline(); | |||
String[] result = new String[orig.length+srcFiles.length+targetFiles.length]; | |||
int srcIndex = orig.length; | |||
if (srcFilePos != null) { | |||
srcIndex = srcFilePos.getPosition(); | |||
} | |||
int targetIndex = targetFilePos.getPosition(); | |||
if (srcIndex < targetIndex || (srcIndex == targetIndex && srcIsFirst)) { | |||
// 0 --> srcIndex | |||
System.arraycopy(orig, 0, result, 0, srcIndex); | |||
// srcIndex --> targetIndex | |||
System.arraycopy(orig, srcIndex, result, | |||
srcIndex + srcFiles.length, | |||
targetIndex - srcIndex); | |||
// targets are already absolute file names | |||
System.arraycopy(targetFiles, 0, result, | |||
targetIndex + srcFiles.length, | |||
targetFiles.length); | |||
// targetIndex --> end | |||
System.arraycopy(orig, targetIndex, result, | |||
targetIndex + srcFiles.length + targetFiles.length, | |||
orig.length - targetIndex); | |||
} else { | |||
// 0 --> targetIndex | |||
System.arraycopy(orig, 0, result, 0, targetIndex); | |||
// targets are already absolute file names | |||
System.arraycopy(targetFiles, 0, result, | |||
targetIndex, | |||
targetFiles.length); | |||
// targetIndex --> srcIndex | |||
System.arraycopy(orig, targetIndex, result, | |||
targetIndex + targetFiles.length, | |||
srcIndex - targetIndex); | |||
// srcIndex --> end | |||
System.arraycopy(orig, srcIndex, result, | |||
srcIndex + srcFiles.length + targetFiles.length, | |||
orig.length - srcIndex); | |||
srcIndex += targetFiles.length; | |||
} | |||
for (int i=0; i < srcFiles.length; i++) { | |||
result[srcIndex+i] = | |||
(new File(baseDir, srcFiles[i])).getAbsolutePath(); | |||
} | |||
return result; | |||
} | |||
/** | |||
* Construct the command line for serial execution. | |||
* | |||
* @param srcFile The filename to add to the commandline | |||
* @param baseDir filename is relative to this dir | |||
*/ | |||
protected String[] getCommandline(String srcFile, File baseDir) { | |||
return getCommandline(new String[] {srcFile}, baseDir); | |||
} | |||
} | |||
public class Transform extends ExecuteOn {} |