new maxparallel attribute. Submitted by: Frank A. Hunleth <fhunleth at cs dot wustl dot edu> used in build.xml to fix PR: 17640 With the new addsourcefile attribute, you can make <apply> ommit the source file names from the command line. PR: 13654 <apply> and <chmod> now support nested <filelist>s as well. PR: 15929 <apply> and <chmod> will display a summary if you set the new verbose attribute to true. PR: 19883 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274587 13f79535-47bb-0310-9956-ffa450edef68master
@@ -346,6 +346,18 @@ Other changes: | |||||
that can be used to turn of Microsoft extensions while using the jvc | that can be used to turn of Microsoft extensions while using the jvc | ||||
compiler. Bugzilla Report 19826. | compiler. Bugzilla Report 19826. | ||||
* You can now limit the parallelism of <apply> and <chmod> by using the new | |||||
maxparallel attribute. | |||||
* With the new addsourcefile attribute, you can make <apply> ommit the | |||||
source file names from the command line. Bugzilla Report 13654. | |||||
* <apply> and <chmod> now support nested <filelist>s as well. | |||||
Bugzilla Report 15929. | |||||
* <apply> and <chmod> will display a summary if you set the new | |||||
verbose attribute to true. Bugzilla Report 19883. | |||||
Changes from Ant 1.5.2 to Ant 1.5.3 | Changes from Ant 1.5.2 to Ant 1.5.3 | ||||
=================================== | =================================== | ||||
@@ -26,6 +26,7 @@ | |||||
<property name="debug" value="true"/> | <property name="debug" value="true"/> | ||||
<property name="chmod.fail" value="true"/> | <property name="chmod.fail" value="true"/> | ||||
<property name="chmod.maxparallel" value="250"/> | |||||
<property name="deprecation" value="false"/> | <property name="deprecation" value="false"/> | ||||
<property name="optimize" value="true"/> | <property name="optimize" value="true"/> | ||||
<property name="javac.target" value="1.1"/> | <property name="javac.target" value="1.1"/> | ||||
@@ -963,7 +964,7 @@ | |||||
<chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | ||||
failonerror="${chmod.fail}"/> | failonerror="${chmod.fail}"/> | ||||
<chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**" | <chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**" | ||||
failonerror="${chmod.fail}"/> | |||||
failonerror="${chmod.fail}" maxparallel="${chmod.maxparallel}"/> | |||||
<chmod perm="ugo+x" type="file" failonerror="${chmod.fail}"> | <chmod perm="ugo+x" type="file" failonerror="${chmod.fail}"> | ||||
<fileset dir="${dist.bin}"> | <fileset dir="${dist.bin}"> | ||||
<include name="**/ant"/> | <include name="**/ant"/> | ||||
@@ -1037,7 +1038,7 @@ | |||||
<chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | ||||
failonerror="${chmod.fail}"/> | failonerror="${chmod.fail}"/> | ||||
<chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**" | <chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**" | ||||
failonerror="${chmod.fail}"/> | |||||
failonerror="${chmod.fail}" maxparallel="${chmod.maxparallel}"/> | |||||
<chmod perm="ugo+x" type="file" failonerror="${chmod.fail}"> | <chmod perm="ugo+x" type="file" failonerror="${chmod.fail}"> | ||||
<fileset dir="${dist.bin}"> | <fileset dir="${dist.bin}"> | ||||
<include name="**/ant"/> | <include name="**/ant"/> | ||||
@@ -15,14 +15,15 @@ compatibility.</i></p> | |||||
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 <a | <p>The files and/or directories of a number of <a | ||||
href="../CoreTypes/fileset.html">FileSet</a>s are passed as arguments | |||||
href="../CoreTypes/fileset.html">FileSet</a>s or <a | |||||
href="../CoreTypes/filelist.html">FileList</a>s are passed as arguments | |||||
to the system command.</p> | to the system command.</p> | ||||
<p>If you specify a nested <a | <p>If you specify a nested <a | ||||
href="../CoreTypes/mapper.html">mapper</a> and the <i>dest</i> attribute, | href="../CoreTypes/mapper.html">mapper</a> and the <i>dest</i> attribute, | ||||
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 | ||||
target file which is defined by the nested mapper element and searched | target file which is defined by the nested mapper element and searched | ||||
for in the given dest.</p> | for in the given dest.</p> | ||||
<p>At least one fileset is required, and you must not specify more than | |||||
<p>At least one fileset or filelist is required, and you must not specify more than | |||||
one mapper.</p> | one mapper.</p> | ||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
<table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
@@ -53,7 +54,7 @@ one mapper.</p> | |||||
<td valign="top">relative</td> | <td valign="top">relative</td> | ||||
<td valign="top">whether the filenames should be passed on the | <td valign="top">whether the filenames should be passed on the | ||||
command line as absolute or relative pathnames (relative to the | command line as absolute or relative pathnames (relative to the | ||||
base directory of the corresponding fileset for source files or | |||||
base directory of the corresponding fileset/list for source files or | |||||
the <i>dest</i> attribute for target files).</td> | the <i>dest</i> attribute for target files).</td> | ||||
<td align="center" valign="top">No, default is <i>false</i></td> | <td align="center" valign="top">No, default is <i>false</i></td> | ||||
</tr> | </tr> | ||||
@@ -120,7 +121,8 @@ one mapper.</p> | |||||
<td valign="top">skipemptyfilesets</td> | <td valign="top">skipemptyfilesets</td> | ||||
<td valign="top">Don't run the command, if no source files have | <td valign="top">Don't run the command, if no source files have | ||||
been found or are newer than their corresponding target | been found or are newer than their corresponding target | ||||
files.</td> | |||||
files. Despite its name, this attribute applies to filelists as | |||||
well.</td> | |||||
<td align="center" valign="top">No, default is <i>false</i></td> | <td align="center" valign="top">No, default is <i>false</i></td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -158,19 +160,45 @@ one mapper.</p> | |||||
false as well.</td> | false as well.</td> | ||||
<td align="center" valign="top">No, default is <i>true</i></td> | <td align="center" valign="top">No, default is <i>true</i></td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">maxparallel</td> | |||||
<td valign="top">Limit the amount of parallelism by passing at | |||||
most this many sourcefiles at once. Set it to <= 0 for | |||||
unlimited. Defaults to unlimited. <em>Since Ant 1.6.</em></td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">addsourcefile</td> | |||||
<td valign="top">Whether source file names should be added to the | |||||
command automatically. Defaults to <code>true</code>. | |||||
<em>Since Ant 1.6.</em></td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">verbose</td> | |||||
<td valign="top">Whether to print a summary after execution or not. | |||||
Defaults to <code>false</code>. <em>Since Ant 1.6.</em></td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
</table> | </table> | ||||
<h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
<h4>fileset</h4> | <h4>fileset</h4> | ||||
<p>You can use any number of nested <code><fileset></code> | <p>You can use any number of nested <code><fileset></code> | ||||
elements to define the files for this task and refer to | elements to define the files for this task and refer to | ||||
<code><fileset></code>s defined elsewhere.</p> | <code><fileset></code>s defined elsewhere.</p> | ||||
<h4>filelist</h4> | |||||
<p><em>Since Ant 1.6</em></p> | |||||
<p>You can use any number of nested <code><filelist></code> | |||||
elements to define the files for this task and refer to | |||||
<code><filelist></code>s defined elsewhere.</p> | |||||
<h4>arg</h4> | <h4>arg</h4> | ||||
<p>Command line arguments should be specified as nested | <p>Command line arguments should be specified as nested | ||||
<code><arg></code> elements. See <a | <code><arg></code> elements. See <a | ||||
href="../using.html#arg">Command line arguments</a>.</p> | href="../using.html#arg">Command line arguments</a>.</p> | ||||
<h4>srcfile</h4> | <h4>srcfile</h4> | ||||
<p>By default the file names of the source files will be added to the | <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, | |||||
end of the command line (unless you set addsourcefile to | |||||
<code>false</code>). If you need to place it somewhere different, | |||||
use a nested <code><srcfile></code> element between your | use a nested <code><srcfile></code> element between your | ||||
<code><arg></code> elements to mark the insertion point.</p> | <code><arg></code> elements to mark the insertion point.</p> | ||||
<h4>targetfile</h4> | <h4>targetfile</h4> | ||||
@@ -19,6 +19,10 @@ write patterns.</p> | |||||
supports all of FileSet's attributes and nested elements | supports all of FileSet's attributes and nested elements | ||||
directly. More FileSets can be specified using nested | directly. More FileSets can be specified using nested | ||||
<code><fileset></code> elements.</p> | <code><fileset></code> elements.</p> | ||||
<p>Starting with Ant 1.6, this task also supports nested <a | |||||
href="../CoreTypes/filelist.html">filelist</a>s.</p> | |||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
<table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
<tr> | <tr> | ||||
@@ -74,6 +78,19 @@ directly. More FileSets can be specified using nested | |||||
the directories are considered.</td> | the directories are considered.</td> | ||||
<td align="center" valign="top">No, default is <i>file</i></td> | <td align="center" valign="top">No, default is <i>file</i></td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">maxparallel</td> | |||||
<td valign="top">Limit the amount of parallelism by passing at | |||||
most this many sourcefiles at once. Set it to <= 0 for | |||||
unlimited. Defaults to unlimited. <em>Since Ant 1.6.</em></td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">verbose</td> | |||||
<td valign="top">Whether to print a summary after execution or not. | |||||
Defaults to <code>false</code>. <em>Since Ant 1.6.</em></td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
</table> | </table> | ||||
<h3>Examples</h3> | <h3>Examples</h3> | ||||
<blockquote> | <blockquote> | ||||
@@ -254,6 +254,14 @@ public class Chmod extends ExecuteOn { | |||||
+ " doesn\'t support the skipemptyfileset attribute", getLocation()); | + " doesn\'t support the skipemptyfileset attribute", getLocation()); | ||||
} | } | ||||
/** | |||||
* @ant.attribute ignore="true" | |||||
*/ | |||||
public void setAddsourcefile(boolean b) { | |||||
throw new BuildException(getTaskType() | |||||
+ " doesn\'t support the addsourcefile attribute", getLocation()); | |||||
} | |||||
protected boolean isValidOs() { | protected boolean isValidOs() { | ||||
return (Os.isFamily("unix") || Os.isFamily("tandem")) | return (Os.isFamily("unix") || Os.isFamily("tandem")) | ||||
&& super.isValidOs(); | && super.isValidOs(); | ||||
@@ -63,6 +63,7 @@ import org.apache.tools.ant.DirectoryScanner; | |||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.types.Commandline; | import org.apache.tools.ant.types.Commandline; | ||||
import org.apache.tools.ant.types.EnumeratedAttribute; | 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.FileSet; | ||||
import org.apache.tools.ant.types.Mapper; | import org.apache.tools.ant.types.Mapper; | ||||
import org.apache.tools.ant.util.FileNameMapper; | import org.apache.tools.ant.util.FileNameMapper; | ||||
@@ -81,6 +82,7 @@ import org.apache.tools.ant.util.SourceFileScanner; | |||||
public class ExecuteOn extends ExecTask { | public class ExecuteOn extends ExecTask { | ||||
protected Vector filesets = new Vector(); | protected Vector filesets = new Vector(); | ||||
private Vector filelists = new Vector(); | |||||
private boolean relative = false; | private boolean relative = false; | ||||
private boolean parallel = false; | private boolean parallel = false; | ||||
private boolean forwardSlash = false; | private boolean forwardSlash = false; | ||||
@@ -91,6 +93,9 @@ public class ExecuteOn extends ExecTask { | |||||
protected Mapper mapperElement = null; | protected Mapper mapperElement = null; | ||||
protected FileNameMapper mapper = null; | protected FileNameMapper mapper = null; | ||||
protected File destDir = null; | protected File destDir = null; | ||||
private int maxParallel = -1; | |||||
private boolean addSourceFile = true; | |||||
private boolean verbose = false; | |||||
/** | /** | ||||
* Has <srcfile> been specified before <targetfile> | * Has <srcfile> been specified before <targetfile> | ||||
@@ -104,6 +109,13 @@ public class ExecuteOn extends ExecTask { | |||||
filesets.addElement(set); | filesets.addElement(set); | ||||
} | } | ||||
/** | |||||
* Source files to operate upon. | |||||
*/ | |||||
public void addFilelist(FileList list) { | |||||
filelists.addElement(list); | |||||
} | |||||
/** | /** | ||||
* Whether the filenames should be passed on the command line as | * Whether the filenames should be passed on the command line as | ||||
* absolute or relative pathnames. Paths are relative to the base | * absolute or relative pathnames. Paths are relative to the base | ||||
@@ -153,6 +165,38 @@ public class ExecuteOn extends ExecTask { | |||||
this.forwardSlash = forwardSlash; | this.forwardSlash = forwardSlash; | ||||
} | } | ||||
/** | |||||
* Limit the command line length by passing at maximum this many | |||||
* sourcefiles at once to the command. | |||||
* | |||||
* <p>Set to <= 0 for unlimited - this is the default.</p> | |||||
* | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public void setMaxParallel(int max) { | |||||
maxParallel = max; | |||||
} | |||||
/** | |||||
* Whether to send the source file name on the command line. | |||||
* | |||||
* <p>Defaults to <code>true</code>. | |||||
* | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public void setAddsourcefile(boolean b) { | |||||
addSourceFile = b; | |||||
} | |||||
/** | |||||
* Whether to print a verbose summary after execution. | |||||
* | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public void setVerbose(boolean b) { | |||||
verbose = b; | |||||
} | |||||
/** | /** | ||||
* Marker that indicates where the name of the source file should | * Marker that indicates where the name of the source file should | ||||
* be put on the command line. | * be put on the command line. | ||||
@@ -202,8 +246,9 @@ public class ExecuteOn extends ExecTask { | |||||
} | } | ||||
super.checkConfiguration(); | super.checkConfiguration(); | ||||
if (filesets.size() == 0) { | |||||
throw new BuildException("no filesets specified", getLocation()); | |||||
if (filesets.size() == 0 && filelists.size() == 0) { | |||||
throw new BuildException("no filesets and no filelists specified", | |||||
getLocation()); | |||||
} | } | ||||
if (targetFilePos != null || mapperElement != null | if (targetFilePos != null || mapperElement != null | ||||
@@ -221,6 +266,9 @@ public class ExecuteOn extends ExecTask { | |||||
} | } | ||||
protected void runExec(Execute exe) throws BuildException { | protected void runExec(Execute exe) throws BuildException { | ||||
int totalFiles = 0; | |||||
int totalDirs = 0; | |||||
boolean haveExecuted = false; | |||||
try { | try { | ||||
Vector fileNames = new Vector(); | Vector fileNames = new Vector(); | ||||
@@ -233,6 +281,7 @@ public class ExecuteOn extends ExecTask { | |||||
if (!"dir".equals(type)) { | if (!"dir".equals(type)) { | ||||
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++; | |||||
fileNames.addElement(s[j]); | fileNames.addElement(s[j]); | ||||
baseDirs.addElement(base); | baseDirs.addElement(base); | ||||
} | } | ||||
@@ -241,6 +290,7 @@ public class ExecuteOn extends ExecTask { | |||||
if (!"file".equals(type)) { | if (!"file".equals(type)) { | ||||
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++; | |||||
fileNames.addElement(s[j]); | fileNames.addElement(s[j]); | ||||
baseDirs.addElement(base); | baseDirs.addElement(base); | ||||
} | } | ||||
@@ -261,6 +311,50 @@ public class ExecuteOn extends ExecTask { | |||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
exe.setCommandline(command); | exe.setCommandline(command); | ||||
runExecute(exe); | runExecute(exe); | ||||
haveExecuted = true; | |||||
} | |||||
fileNames.removeAllElements(); | |||||
baseDirs.removeAllElements(); | |||||
} | |||||
} | |||||
for (int i = 0; i < filelists.size(); i++) { | |||||
FileList list = (FileList) filelists.elementAt(i); | |||||
File base = list.getDir(getProject()); | |||||
String[] names = list.getFiles(getProject()); | |||||
for (int j = 0; j < names.length; j++) { | |||||
File f = new File(base, names[j]); | |||||
if ((f.isFile() && !"dir".equals(type)) | |||||
|| (f.isDirectory() && !"file".equals(type))) { | |||||
if (f.isFile()) { | |||||
totalFiles++; | |||||
} else { | |||||
totalDirs++; | |||||
} | |||||
fileNames.addElement(names[j]); | |||||
baseDirs.addElement(base); | |||||
} | |||||
} | |||||
if (fileNames.size() == 0 && skipEmpty) { | |||||
log("Skipping filelist for directory " | |||||
+ base + ". It is 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); | |||||
runExecute(exe); | |||||
haveExecuted = true; | |||||
} | } | ||||
fileNames.removeAllElements(); | fileNames.removeAllElements(); | ||||
baseDirs.removeAllElements(); | baseDirs.removeAllElements(); | ||||
@@ -268,14 +362,17 @@ public class ExecuteOn extends ExecTask { | |||||
} | } | ||||
if (parallel && (fileNames.size() > 0 || !skipEmpty)) { | if (parallel && (fileNames.size() > 0 || !skipEmpty)) { | ||||
String[] s = new String[fileNames.size()]; | |||||
fileNames.copyInto(s); | |||||
File[] b = new File[baseDirs.size()]; | |||||
baseDirs.copyInto(b); | |||||
String[] command = getCommandline(s, b); | |||||
log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | |||||
exe.setCommandline(command); | |||||
runExecute(exe); | |||||
runParallel(exe, fileNames, baseDirs); | |||||
haveExecuted = true; | |||||
} | |||||
if (haveExecuted) { | |||||
log("Applied " + cmdl.getExecutable() + " to " | |||||
+ totalFiles + " file" | |||||
+ (totalFiles != 1 ? "s" : "") + " and " | |||||
+ totalDirs + " director" | |||||
+ (totalDirs != 1 ? "ies" : "y") + ".", | |||||
verbose ? Project.MSG_INFO : Project.MSG_VERBOSE); | |||||
} | } | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
@@ -321,6 +418,10 @@ public class ExecuteOn extends ExecTask { | |||||
String[] targetFiles = new String[targets.size()]; | String[] targetFiles = new String[targets.size()]; | ||||
targets.copyInto(targetFiles); | targets.copyInto(targetFiles); | ||||
if (!addSourceFile) { | |||||
srcFiles = new String[0]; | |||||
} | |||||
String[] orig = cmdl.getCommandline(); | String[] orig = cmdl.getCommandline(); | ||||
String[] result | String[] result | ||||
= new String[orig.length + srcFiles.length + targetFiles.length]; | = new String[orig.length + srcFiles.length + targetFiles.length]; | ||||
@@ -439,6 +540,46 @@ public class ExecuteOn extends ExecTask { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* Runs the command in "parallel" mode, making sure that at most | |||||
* maxParallel sourcefiles get passed on the command line. | |||||
* | |||||
* @since Ant 1.6 | |||||
*/ | |||||
protected void runParallel(Execute exe, Vector fileNames, | |||||
Vector baseDirs) | |||||
throws IOException, BuildException { | |||||
String[] s = new String[fileNames.size()]; | |||||
fileNames.copyInto(s); | |||||
File[] b = new File[baseDirs.size()]; | |||||
baseDirs.copyInto(b); | |||||
if (maxParallel <= 0 | |||||
|| s.length == 0 /* this is skipEmpty == false */) { | |||||
String[] command = getCommandline(s, b); | |||||
log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | |||||
exe.setCommandline(command); | |||||
runExecute(exe); | |||||
} else { | |||||
int stillToDo = fileNames.size(); | |||||
int currentOffset = 0; | |||||
while (stillToDo > 0) { | |||||
int currentAmount = Math.min(stillToDo, maxParallel); | |||||
String[] cs = new String[currentAmount]; | |||||
System.arraycopy(s, currentOffset, cs, 0, currentAmount); | |||||
File[] cb = new File[currentAmount]; | |||||
System.arraycopy(b, currentOffset, cb, 0, currentAmount); | |||||
String[] command = getCommandline(cs, cb); | |||||
log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | |||||
exe.setCommandline(command); | |||||
runExecute(exe); | |||||
stillToDo -= currentAmount; | |||||
currentOffset += currentAmount; | |||||
} | |||||
} | |||||
} | |||||
/** | /** | ||||
* Enumerated attribute with the values "file", "dir" and "both" | * Enumerated attribute with the values "file", "dir" and "both" | ||||
* for the type attribute. | * for the type attribute. | ||||