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 | |||
| 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 | |||
| =================================== | |||
| @@ -26,6 +26,7 @@ | |||
| <property name="debug" value="true"/> | |||
| <property name="chmod.fail" value="true"/> | |||
| <property name="chmod.maxparallel" value="250"/> | |||
| <property name="deprecation" value="false"/> | |||
| <property name="optimize" value="true"/> | |||
| <property name="javac.target" value="1.1"/> | |||
| @@ -963,7 +964,7 @@ | |||
| <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | |||
| failonerror="${chmod.fail}"/> | |||
| <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}"> | |||
| <fileset dir="${dist.bin}"> | |||
| <include name="**/ant"/> | |||
| @@ -1037,7 +1038,7 @@ | |||
| <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**" | |||
| failonerror="${chmod.fail}"/> | |||
| <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}"> | |||
| <fileset dir="${dist.bin}"> | |||
| <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 | |||
| systems.</p> | |||
| <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> | |||
| <p>If you specify a nested <a | |||
| 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 | |||
| target file which is defined by the nested mapper element and searched | |||
| 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> | |||
| <h3>Parameters</h3> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| @@ -53,7 +54,7 @@ one mapper.</p> | |||
| <td valign="top">relative</td> | |||
| <td valign="top">whether the filenames should be passed on 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> | |||
| <td align="center" valign="top">No, default is <i>false</i></td> | |||
| </tr> | |||
| @@ -120,7 +121,8 @@ one mapper.</p> | |||
| <td valign="top">skipemptyfilesets</td> | |||
| <td valign="top">Don't run the command, if no source files have | |||
| 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> | |||
| </tr> | |||
| <tr> | |||
| @@ -158,19 +160,45 @@ one mapper.</p> | |||
| false as well.</td> | |||
| <td align="center" valign="top">No, default is <i>true</i></td> | |||
| </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> | |||
| <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>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> | |||
| <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, | |||
| 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 | |||
| <code><arg></code> elements to mark the insertion point.</p> | |||
| <h4>targetfile</h4> | |||
| @@ -19,6 +19,10 @@ write patterns.</p> | |||
| supports all of FileSet's attributes and nested elements | |||
| directly. More FileSets can be specified using nested | |||
| <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> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| @@ -74,6 +78,19 @@ directly. More FileSets can be specified using nested | |||
| the directories are considered.</td> | |||
| <td align="center" valign="top">No, default is <i>file</i></td> | |||
| </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> | |||
| <h3>Examples</h3> | |||
| <blockquote> | |||
| @@ -254,6 +254,14 @@ public class Chmod extends ExecuteOn { | |||
| + " 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() { | |||
| return (Os.isFamily("unix") || Os.isFamily("tandem")) | |||
| && super.isValidOs(); | |||
| @@ -63,6 +63,7 @@ import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| 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.util.FileNameMapper; | |||
| @@ -81,6 +82,7 @@ import org.apache.tools.ant.util.SourceFileScanner; | |||
| public class ExecuteOn extends ExecTask { | |||
| protected Vector filesets = new Vector(); | |||
| private Vector filelists = new Vector(); | |||
| private boolean relative = false; | |||
| private boolean parallel = false; | |||
| private boolean forwardSlash = false; | |||
| @@ -91,6 +93,9 @@ public class ExecuteOn extends ExecTask { | |||
| protected Mapper mapperElement = null; | |||
| protected FileNameMapper mapper = null; | |||
| protected File destDir = null; | |||
| private int maxParallel = -1; | |||
| private boolean addSourceFile = true; | |||
| private boolean verbose = false; | |||
| /** | |||
| * Has <srcfile> been specified before <targetfile> | |||
| @@ -104,6 +109,13 @@ public class ExecuteOn extends ExecTask { | |||
| 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 | |||
| * absolute or relative pathnames. Paths are relative to the base | |||
| @@ -153,6 +165,38 @@ public class ExecuteOn extends ExecTask { | |||
| 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 | |||
| * be put on the command line. | |||
| @@ -202,8 +246,9 @@ public class ExecuteOn extends ExecTask { | |||
| } | |||
| 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 | |||
| @@ -221,6 +266,9 @@ public class ExecuteOn extends ExecTask { | |||
| } | |||
| protected void runExec(Execute exe) throws BuildException { | |||
| int totalFiles = 0; | |||
| int totalDirs = 0; | |||
| boolean haveExecuted = false; | |||
| try { | |||
| Vector fileNames = new Vector(); | |||
| @@ -233,6 +281,7 @@ public class ExecuteOn extends ExecTask { | |||
| if (!"dir".equals(type)) { | |||
| String[] s = getFiles(base, ds); | |||
| for (int j = 0; j < s.length; j++) { | |||
| totalFiles++; | |||
| fileNames.addElement(s[j]); | |||
| baseDirs.addElement(base); | |||
| } | |||
| @@ -241,6 +290,7 @@ public class ExecuteOn extends ExecTask { | |||
| if (!"file".equals(type)) { | |||
| String[] s = getDirs(base, ds);; | |||
| for (int j = 0; j < s.length; j++) { | |||
| totalDirs++; | |||
| fileNames.addElement(s[j]); | |||
| baseDirs.addElement(base); | |||
| } | |||
| @@ -261,6 +311,50 @@ public class ExecuteOn extends ExecTask { | |||
| Project.MSG_VERBOSE); | |||
| exe.setCommandline(command); | |||
| 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(); | |||
| baseDirs.removeAllElements(); | |||
| @@ -268,14 +362,17 @@ public class ExecuteOn extends ExecTask { | |||
| } | |||
| 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) { | |||
| @@ -321,6 +418,10 @@ public class ExecuteOn extends ExecTask { | |||
| String[] targetFiles = new String[targets.size()]; | |||
| targets.copyInto(targetFiles); | |||
| if (!addSourceFile) { | |||
| srcFiles = new String[0]; | |||
| } | |||
| String[] orig = cmdl.getCommandline(); | |||
| String[] result | |||
| = 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" | |||
| * for the type attribute. | |||