mbenson 2004/12/14 15:48:02 Modified: . Tag: ANT_16_BRANCH WHATSNEW src/etc/testcases/taskdefs Tag: ANT_16_BRANCH ant.xml calltarget.xml src/main/org/apache/tools/ant Tag: ANT_16_BRANCH Project.java Target.java src/main/org/apache/tools/ant/taskdefs Tag: ANT_16_BRANCH Ant.java CallTarget.java src/testcases/org/apache/tools/ant/taskdefs Tag: ANT_16_BRANCH AntTest.java CallTargetTest.java docs/manual/CoreTasks Tag: ANT_16_BRANCH ant.html antcall.html Added: src/etc/testcases/taskdefs Tag: ANT_16_BRANCH bar.properties foo.properties src/main/org/apache/tools/ant Tag: ANT_16_BRANCH Executor.java src/main/org/apache/tools/ant/helper Tag: ANT_16_BRANCH DefaultExecutor.java KeepGoingExecutor.java SingleCheckExecutor.java Log: Merge Executor stuff and nested target elements for ant & antcall Revision Changes Path No revision No revision 1.503.2.149 +7 -0 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.503.2.148 retrieving revision 1.503.2.149 diff -u -r1.503.2.148 -r1.503.2.149 --- WHATSNEW 13 Dec 2004 18:52:17 -0000 1.503.2.148 +++ WHATSNEW 14 Dec 2004 23:48:00 -0000 1.503.2.149 @@ -22,6 +22,13 @@ * New attribute alwayslog for <redirector> type. +* Added <target> nested elements to <ant> and <antcall> to allow + specification of multiple sub-build targets, which are executed + with a single dependency analysis. + +* Refactored Target invocation into org.apache.tools.ant.Executor + implementations. Bugzilla Reports 21421, 29248. + Fixed bugs: ----------- No revision No revision 1.12.2.1 +36 -0 ant/src/etc/testcases/taskdefs/ant.xml Index: ant.xml =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/ant.xml,v retrieving revision 1.12 retrieving revision 1.12.2.1 diff -u -r1.12 -r1.12.2.1 --- ant.xml 10 Sep 2003 13:57:19 -0000 1.12 +++ ant.xml 14 Dec 2004 23:48:00 -0000 1.12.2.1 @@ -185,4 +185,40 @@ <ant antfile="ant.topleveltest.xml"/> </target> + <target name="multiple-property-file-children"> + <ant target="dummy" antfile="ant.xml"> + <property file="foo.properties"/> + <property file="bar.properties"/> + </ant> + </target> + + <target name="blank-target"> + <ant antfile="ant.topleveltest.xml"> + <target name="" /> + </ant> + </target> + + <target name="multiple-targets"> + <ant antfile="ant.xml"> + <target name="ta" /> + <target name="tb" /> + <target name="tc" /> + </ant> + </target> + + <target name="multiple-targets-2"> + <ant antfile="ant.xml"> + <target name="tb" /> + <target name="da" /> + </ant> + </target> + + <target name="ta"><echo>ta</echo></target> + <target name="tb" depends="da,dc"><echo>tb</echo></target> + <target name="tc" depends="db,dc"><echo>tc</echo></target> + + <target name="da"><echo>da</echo></target> + <target name="db"><echo>db</echo></target> + <target name="dc"><echo>dc</echo></target> + </project> 1.3.2.1 +31 -1 ant/src/etc/testcases/taskdefs/calltarget.xml Index: calltarget.xml =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/calltarget.xml,v retrieving revision 1.3 retrieving revision 1.3.2.1 diff -u -r1.3 -r1.3.2.1 --- calltarget.xml 5 Aug 2003 13:56:26 -0000 1.3 +++ calltarget.xml 14 Dec 2004 23:48:00 -0000 1.3.2.1 @@ -50,4 +50,34 @@ <param name="multi" value="SET"/> </antcall> </target> -</project> \ No newline at end of file + + <target name="blank-target"> + <antcall> + <target name="" /> + </antcall> + </target> + + <target name="multiple-targets"> + <antcall> + <target name="ta" /> + <target name="tb" /> + <target name="tc" /> + </antcall> + </target> + + <target name="multiple-targets-2"> + <ant antfile="ant.xml"> + <target name="tb" /> + <target name="da" /> + </ant> + </target> + + <target name="ta"><echo>ta</echo></target> + <target name="tb" depends="da,dc"><echo>tb</echo></target> + <target name="tc" depends="db,dc"><echo>tc</echo></target> + + <target name="da"><echo>da</echo></target> + <target name="db"><echo>db</echo></target> + <target name="dc"><echo>dc</echo></target> + +</project> No revision Index: calltarget.xml =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/calltarget.xml,v retrieving revision 1.3 retrieving revision 1.3.2.1 diff -u -r1.3 -r1.3.2.1 --- calltarget.xml 5 Aug 2003 13:56:26 -0000 1.3 +++ calltarget.xml 14 Dec 2004 23:48:00 -0000 1.3.2.1 @@ -50,4 +50,34 @@ <param name="multi" value="SET"/> </antcall> </target> -</project> \ No newline at end of file + + <target name="blank-target"> + <antcall> + <target name="" /> + </antcall> + </target> + + <target name="multiple-targets"> + <antcall> + <target name="ta" /> + <target name="tb" /> + <target name="tc" /> + </antcall> + </target> + + <target name="multiple-targets-2"> + <ant antfile="ant.xml"> + <target name="tb" /> + <target name="da" /> + </ant> + </target> + + <target name="ta"><echo>ta</echo></target> + <target name="tb" depends="da,dc"><echo>tb</echo></target> + <target name="tc" depends="db,dc"><echo>tc</echo></target> + + <target name="da"><echo>da</echo></target> + <target name="db"><echo>db</echo></target> + <target name="dc"><echo>dc</echo></target> + +</project> No revision Index: calltarget.xml =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/calltarget.xml,v retrieving revision 1.3 retrieving revision 1.3.2.1 diff -u -r1.3 -r1.3.2.1 --- calltarget.xml 5 Aug 2003 13:56:26 -0000 1.3 +++ calltarget.xml 14 Dec 2004 23:48:00 -0000 1.3.2.1 @@ -50,4 +50,34 @@ <param name="multi" value="SET"/> </antcall> </target> -</project> \ No newline at end of file + + <target name="blank-target"> + <antcall> + <target name="" /> + </antcall> + </target> + + <target name="multiple-targets"> + <antcall> + <target name="ta" /> + <target name="tb" /> + <target name="tc" /> + </antcall> + </target> + + <target name="multiple-targets-2"> + <ant antfile="ant.xml"> + <target name="tb" /> + <target name="da" /> + </ant> + </target> + + <target name="ta"><echo>ta</echo></target> + <target name="tb" depends="da,dc"><echo>tb</echo></target> + <target name="tc" depends="db,dc"><echo>tc</echo></target> + + <target name="da"><echo>da</echo></target> + <target name="db"><echo>db</echo></target> + <target name="dc"><echo>dc</echo></target> + +</project> 1.1.2.1 +0 -0 ant/src/etc/testcases/taskdefs/bar.properties Index: bar.properties =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/bar.properties,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -u -r1.1 -r1.1.2.1 1.1.2.1 +0 -0 ant/src/etc/testcases/taskdefs/foo.properties Index: foo.properties =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/foo.properties,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -u -r1.1 -r1.1.2.1 No revision No revision 1.154.2.14 +124 -42 ant/src/main/org/apache/tools/ant/Project.java Index: Project.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Project.java,v retrieving revision 1.154.2.13 retrieving revision 1.154.2.14 diff -u -r1.154.2.13 -r1.154.2.14 --- Project.java 28 Oct 2004 09:17:48 -0000 1.154.2.13 +++ Project.java 14 Dec 2004 23:48:00 -0000 1.154.2.14 @@ -33,6 +33,8 @@ import java.util.HashSet; import org.apache.tools.ant.input.DefaultInputHandler; import org.apache.tools.ant.input.InputHandler; +import org.apache.tools.ant.helper.DefaultExecutor; +import org.apache.tools.ant.helper.KeepGoingExecutor; import org.apache.tools.ant.types.FilterSet; import org.apache.tools.ant.types.FilterSetCollection; import org.apache.tools.ant.types.Description; @@ -274,16 +276,14 @@ */ private AntClassLoader createClassLoader() { AntClassLoader loader = null; - if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { - try { - // 1.2+ - create advanced helper dynamically - Class loaderClass + try { + // 1.2+ - create advanced helper dynamically + Class loaderClass = Class.forName(ANTCLASSLOADER_JDK12); - loader = (AntClassLoader) loaderClass.newInstance(); - } catch (Exception e) { - log("Unable to create Class Loader: " - + e.getMessage(), Project.MSG_DEBUG); - } + loader = (AntClassLoader) loaderClass.newInstance(); + } catch (Exception e) { + log("Unable to create Class Loader: " + + e.getMessage(), Project.MSG_DEBUG); } if (loader == null) { @@ -766,7 +766,9 @@ /** * Sets "keep-going" mode. In this mode ANT will try to execute * as many targets as possible. All targets that do not depend - * on failed target(s) will be executed. + * on failed target(s) will be executed. If the keepGoing settor/getter + * methods are used in conjunction with the <code>ant.executor.class</code> + * property, they will have no effect. * @param keepGoingMode "keep-going" mode * @since Ant 1.6 */ @@ -775,7 +777,9 @@ } /** - * Returns the keep-going mode. + * Returns the keep-going mode. If the keepGoing settor/getter + * methods are used in conjunction with the <code>ant.executor.class</code> + * property, they will have no effect. * @return "keep-going" mode * @since Ant 1.6 */ @@ -1056,19 +1060,38 @@ */ public void executeTargets(Vector targetNames) throws BuildException { - BuildException thrownException = null; - for (int i = 0; i < targetNames.size(); i++) { + Object o = getReference("ant.executor"); + if (o == null) { + String classname = getProperty("ant.executor.class"); + if (classname == null) { + classname = (keepGoingMode) + ? KeepGoingExecutor.class.getName() + : DefaultExecutor.class.getName(); + } + log("Attempting to create object of type " + classname, MSG_DEBUG); try { - executeTarget((String) targetNames.elementAt(i)); - } catch (BuildException ex) { - if (!(keepGoingMode)) { - throw ex; // Throw further + o = Class.forName(classname, true, coreLoader).newInstance(); + } catch (ClassNotFoundException seaEnEfEx) { + //try the current classloader + try { + o = Class.forName(classname).newInstance(); + } catch (Exception ex) { + log(ex.toString(), MSG_ERR); } - thrownException = ex; + } catch (Exception ex) { + log(ex.toString(), MSG_ERR); + } + if (o != null) { + addReference("ant.executor", o); } } - if (thrownException != null) { - throw thrownException; + + if (o == null) { + throw new BuildException("Unable to obtain a Target Executor instance."); + } else { + String[] targetNameArray = (String[])(targetNames.toArray( + new String[targetNames.size()])); + ((Executor)o).executeTargets(this, targetNameArray); } } @@ -1183,13 +1206,19 @@ throw new BuildException(msg); } - // Sort the dependency tree, and run everything from the - // beginning until we hit our targetName. + // Sort and run the dependency tree. // Sorting checks if all the targets (and dependencies) // exist, and if there is any cycle in the dependency // graph. - Vector sortedTargets = topoSort(targetName, targets); + executeSortedTargets(topoSort(targetName, targets, false)); + } + /** + * Executes a <code>Vector</code> of sorted targets. + * @param sortedTargets the aforementioned <code>Vector</code>. + */ + public void executeSortedTargets(Vector sortedTargets) + throws BuildException { Set succeededTargets = new HashSet(); BuildException buildException = null; // first build exception for (Enumeration iter = sortedTargets.elements(); @@ -1247,9 +1276,6 @@ } } } - if (curtarget.getName().equals(targetName)) { // old exit condition - break; - } } if (buildException != null) { throw buildException; @@ -1531,11 +1557,6 @@ */ public void setFileLastModified(File file, long time) throws BuildException { - if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { - log("Cannot change the modification time of " + file - + " in JDK 1.1", Project.MSG_WARN); - return; - } fileUtils.setFileLastModified(file, time); log("Setting modification time for " + file, MSG_VERBOSE); } @@ -1558,45 +1579,106 @@ } /** - * Topologically sorts a set of targets. + * Topologically sorts a set of targets. Equivalent to calling + * <code>topoSort(new String[] {root}, targets, true)</code>. * * @param root The name of the root target. The sort is created in such * a way that the sequence of Targets up to the root * target is the minimum possible such sequence. * Must not be <code>null</code>. - * @param targets A map of names to targets (String to Target). + * @param targets A Hashtable mapping names to Targets. * Must not be <code>null</code>. - * @return a vector of Target objects in sorted order. + * @return a Vector of ALL Target objects in sorted order. * @exception BuildException if there is a cyclic dependency among the * targets, or if a named target does not exist. */ public final Vector topoSort(String root, Hashtable targets) throws BuildException { + return topoSort(new String[] {root}, targets, true); + } + + /** + * Topologically sorts a set of targets. Equivalent to calling + * <code>topoSort(new String[] {root}, targets, returnAll)</code>. + * + * @param root The name of the root target. The sort is created in such + * a way that the sequence of Targets up to the root + * target is the minimum possible such sequence. + * Must not be <code>null</code>. + * @param targets A Hashtable mapping names to Targets. + * Must not be <code>null</code>. + * @param returnAll <code>boolean</code> indicating whether to return all + * targets, or the execution sequence only. + * @return a Vector of Target objects in sorted order. + * @exception BuildException if there is a cyclic dependency among the + * targets, or if a named target does not exist. + * @since Ant 1.6.3 + */ + public final Vector topoSort(String root, Hashtable targets, + boolean returnAll) throws BuildException { + return topoSort(new String[] {root}, targets, returnAll); + } + + /** + * Topologically sorts a set of targets. + * + * @param root <code>String[]</code> containing the names of the root targets. + * The sort is created in such a way that the ordered sequence of + * Targets is the minimum possible such sequence to the specified + * root targets. + * Must not be <code>null</code>. + * @param targets A map of names to targets (String to Target). + * Must not be <code>null</code>. + * @param returnAll <code>boolean</code> indicating whether to return all + * targets, or the execution sequence only. + * @return a Vector of Target objects in sorted order. + * @exception BuildException if there is a cyclic dependency among the + * targets, or if a named target does not exist. + * @since Ant 1.6.3 + */ + public final Vector topoSort(String[] root, Hashtable targets, + boolean returnAll) throws BuildException { Vector ret = new Vector(); Hashtable state = new Hashtable(); Stack visiting = new Stack(); - // We first run a DFS based sort using the root as the starting node. - // This creates the minimum sequence of Targets to the root node. + // We first run a DFS based sort using each root as a starting node. + // This creates the minimum sequence of Targets to the root node(s). // We then do a sort on any remaining unVISITED targets. // This is unnecessary for doing our build, but it catches // circular dependencies or missing Targets on the entire // dependency tree, not just on the Targets that depend on the // build Target. - tsort(root, targets, state, visiting, ret); - log("Build sequence for target `" + root + "' is " + ret, MSG_VERBOSE); + for (int i = 0; i < root.length; i++) { + String st = (String)(state.get(root[i])); + if (st == null) { + tsort(root[i], targets, state, visiting, ret); + } else if (st == VISITING) { + throw new RuntimeException("Unexpected node in visiting state: " + + root[i]); + } + } + StringBuffer buf = new StringBuffer("Build sequence for target(s)"); + + for (int j = 0; j < root.length; j++) { + buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\''); + } + buf.append(" is " + ret); + log(buf.toString(), MSG_VERBOSE); + + Vector complete = (returnAll) ? ret : new Vector(ret); for (Enumeration en = targets.keys(); en.hasMoreElements();) { String curTarget = (String) en.nextElement(); String st = (String) state.get(curTarget); if (st == null) { - tsort(curTarget, targets, state, visiting, ret); + tsort(curTarget, targets, state, visiting, complete); } else if (st == VISITING) { throw new RuntimeException("Unexpected node in visiting state: " + curTarget); } } - log("Complete build sequence is " + ret, MSG_VERBOSE); + log("Complete build sequence is " + complete, MSG_VERBOSE); return ret; } @@ -2064,7 +2146,7 @@ */ public Object get(Object key) { //System.out.println("AntRefTable.get " + key); - Object o = super.get(key); + Object o = getReal(key); if (o instanceof UnknownElement) { // Make sure that UnknownElement ue = (UnknownElement) o; 1.46.2.9 +4 -8 ant/src/main/org/apache/tools/ant/Target.java Index: Target.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Target.java,v retrieving revision 1.46.2.8 retrieving revision 1.46.2.9 diff -u -r1.46.2.8 -r1.46.2.9 --- Target.java 13 Aug 2004 09:28:47 -0000 1.46.2.8 +++ Target.java 14 Dec 2004 23:48:01 -0000 1.46.2.9 @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; @@ -221,14 +222,9 @@ * @since Ant 1.6 */ public boolean dependsOn(String other) { - if (getProject() != null) { - List l = getProject().topoSort(getName(), - getProject().getTargets()); - int myIdx = l.indexOf(this); - int otherIdx = l.indexOf(getProject().getTargets().get(other)); - return myIdx >= otherIdx; - } - return false; + Project p = getProject(); + Hashtable t = (p == null) ? null : p.getTargets(); + return (p != null && p.topoSort(getName(), t, false).contains(t.get(other))); } /** No revision Index: Target.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Target.java,v retrieving revision 1.46.2.8 retrieving revision 1.46.2.9 diff -u -r1.46.2.8 -r1.46.2.9 --- Target.java 13 Aug 2004 09:28:47 -0000 1.46.2.8 +++ Target.java 14 Dec 2004 23:48:01 -0000 1.46.2.9 @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; @@ -221,14 +222,9 @@ * @since Ant 1.6 */ public boolean dependsOn(String other) { - if (getProject() != null) { - List l = getProject().topoSort(getName(), - getProject().getTargets()); - int myIdx = l.indexOf(this); - int otherIdx = l.indexOf(getProject().getTargets().get(other)); - return myIdx >= otherIdx; - } - return false; + Project p = getProject(); + Hashtable t = (p == null) ? null : p.getTargets(); + return (p != null && p.topoSort(getName(), t, false).contains(t.get(other))); } /** No revision Index: Target.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Target.java,v retrieving revision 1.46.2.8 retrieving revision 1.46.2.9 diff -u -r1.46.2.8 -r1.46.2.9 --- Target.java 13 Aug 2004 09:28:47 -0000 1.46.2.8 +++ Target.java 14 Dec 2004 23:48:01 -0000 1.46.2.9 @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; @@ -221,14 +222,9 @@ * @since Ant 1.6 */ public boolean dependsOn(String other) { - if (getProject() != null) { - List l = getProject().topoSort(getName(), - getProject().getTargets()); - int myIdx = l.indexOf(this); - int otherIdx = l.indexOf(getProject().getTargets().get(other)); - return myIdx >= otherIdx; - } - return false; + Project p = getProject(); + Hashtable t = (p == null) ? null : p.getTargets(); + return (p != null && p.topoSort(getName(), t, false).contains(t.get(other))); } /** 1.2.2.1 +0 -0 ant/src/main/org/apache/tools/ant/Executor.java Index: Executor.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Executor.java,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -u -r1.2 -r1.2.2.1 No revision No revision 1.3.2.1 +0 -0 ant/src/main/org/apache/tools/ant/helper/DefaultExecutor.java Index: DefaultExecutor.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/helper/DefaultExecutor.java,v retrieving revision 1.3 retrieving revision 1.3.2.1 diff -u -r1.3 -r1.3.2.1 1.2.2.1 +0 -0 ant/src/main/org/apache/tools/ant/helper/KeepGoingExecutor.java Index: KeepGoingExecutor.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/helper/KeepGoingExecutor.java,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -u -r1.2 -r1.2.2.1 1.2.2.1 +0 -0 ant/src/main/org/apache/tools/ant/helper/SingleCheckExecutor.java Index: SingleCheckExecutor.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/helper/SingleCheckExecutor.java,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -u -r1.2 -r1.2.2.1 No revision No revision 1.92.2.10 +114 -67 ant/src/main/org/apache/tools/ant/taskdefs/Ant.java Index: Ant.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Ant.java,v retrieving revision 1.92.2.9 retrieving revision 1.92.2.10 diff -u -r1.92.2.9 -r1.92.2.10 --- Ant.java 12 Nov 2004 11:08:00 -0000 1.92.2.9 +++ Ant.java 14 Dec 2004 23:48:01 -0000 1.92.2.10 @@ -31,11 +31,13 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.DefaultLogger; +import org.apache.tools.ant.Executor; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.Target; import org.apache.tools.ant.Task; +import org.apache.tools.ant.helper.SingleCheckExecutor; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.util.FileUtils; @@ -47,8 +49,8 @@ * <ant antfile="build.xml" target="bar" > * <property name="property1" value="aaaaa" /> * <property name="foo" value="baz" /> - * </ant></SPAN> - * </target></SPAN> + * </ant></span> + * </target></span> * * <target name="bar" depends="init"> * <echo message="prop is ${property1} ${foo}" /> @@ -56,13 +58,15 @@ * </pre> * * - * * @since Ant 1.1 * * @ant.task category="control" */ public class Ant extends Task { + /** Target Executor */ + private static final Executor EXECUTOR = new SingleCheckExecutor(); + /** the basedir where is executed the build file */ private File dir = null; @@ -72,9 +76,6 @@ */ private String antFile = null; - /** the target to call if any */ - private String target = null; - /** the output */ private String output = null; @@ -99,6 +100,12 @@ /** the sets of properties to pass to the new project */ private Vector propertySets = new Vector(); + /** the targets to call on the new project */ + private Vector targets = new Vector(); + + /** whether the target attribute was specified **/ + private boolean targetAttributeSet = false; + /** * If true, pass all properties to the new Ant project. * Defaults to true. @@ -196,9 +203,8 @@ } /** - * Pass output sent to System.out to the new project. + * @see Task#handleOutput(String) * - * @param output a line of output * @since Ant 1.5 */ public void handleOutput(String output) { @@ -210,16 +216,6 @@ } /** - * Process input into the ant task - * - * @param buffer the buffer into which data is to be read. - * @param offset the offset into the buffer at which data is stored. - * @param length the amount of data to read - * - * @return the number of bytes read - * - * @exception IOException if the data cannot be read - * * @see Task#handleInput(byte[], int, int) * * @since Ant 1.6 @@ -234,9 +230,7 @@ } /** - * Pass output sent to System.out to the new project. - * - * @param output The output to log. Should not be <code>null</code>. + * @see Task#handleFlush(String) * * @since Ant 1.5.2 */ @@ -249,9 +243,7 @@ } /** - * Pass output sent to System.err to the new project. - * - * @param output The error output to log. Should not be <code>null</code>. + * @see Task#handleErrorOutput(String) * * @since Ant 1.5 */ @@ -264,9 +256,7 @@ } /** - * Pass output sent to System.err to the new project. - * - * @param output The error output to log. Should not be <code>null</code>. + * @see Task#handleErrorFlush(String) * * @since Ant 1.5.2 */ @@ -280,13 +270,13 @@ /** * Do the execution. - * @throws BuildException if a target tries to call itself - * probably also if a BuildException is thrown by the new project + * @throws BuildException if a target tries to call itself; + * probably also if a BuildException is thrown by the new project. */ public void execute() throws BuildException { File savedDir = dir; String savedAntFile = antFile; - String savedTarget = target; + Vector locals = new Vector(targets); try { if (newProject == null) { reinit(); @@ -318,8 +308,9 @@ File file = FileUtils.newFileUtils().resolveFile(dir, antFile); antFile = file.getAbsolutePath(); - log("calling target " + (target != null ? target : "[default]") - + " in build file " + antFile, Project.MSG_VERBOSE); + log("calling target(s) " + + ((locals.size() == 0) ? locals.toString() : "[default]") + + " in build file " + antFile, Project.MSG_VERBOSE); newProject.setUserProperty("ant.file" , antFile); String thisAntFile = getProject().getProperty("ant.file"); @@ -349,8 +340,11 @@ ex, getLocation()); } - if (target == null) { - target = newProject.getDefaultTarget(); + if (locals.size() == 0) { + String defaultTarget = newProject.getDefaultTarget(); + if (defaultTarget != null) { + locals.add(defaultTarget); + } } if (newProject.getProperty("ant.file") @@ -359,13 +353,18 @@ String owningTargetName = getOwningTarget().getName(); - if (owningTargetName.equals(target)) { + if (locals.contains(owningTargetName)) { throw new BuildException(getTaskName() + " task calling " + "its own parent target."); } else { - Target other = - (Target) getProject().getTargets().get(target); - if (other != null && other.dependsOn(owningTargetName)) { + boolean circular = false; + for (Iterator it = locals.iterator(); !circular && it.hasNext();) { + Target other = (Target) (getProject().getTargets().get( + (String) (it.next()))); + circular |= (other != null + && other.dependsOn(owningTargetName)); + } + if (circular) { throw new BuildException(getTaskName() + " task calling a target" + " that depends on" @@ -378,12 +377,14 @@ addReferences(); - if (target != null && !"".equals(target)) { + if (locals.size() > 0 && !(locals.size() == 1 && locals.get(0) == "")) { Throwable t = null; try { log("Entering " + antFile + "...", Project.MSG_VERBOSE); newProject.fireSubBuildStarted(); - newProject.executeTarget(target); + EXECUTOR.executeTargets(newProject, + (String[]) (locals.toArray(new String[locals.size()]))); + } catch (BuildException ex) { t = ProjectHelper .addLocationToBuildException(ex, getLocation()); @@ -411,14 +412,13 @@ } dir = savedDir; antFile = savedAntFile; - target = savedTarget; } } /** * Override the properties in the new project with the one * explicitly defined as nested elements here. - * @throws BuildException under unknown circumstances + * @throws BuildException under unknown circumstances. */ private void overrideProperties() throws BuildException { // remove duplicate properties - last property wins @@ -448,7 +448,7 @@ * new project. Also copy over all references that don't override * existing references in the new project if inheritrefs has been * requested. - * @throws BuildException if a reference does not have a refid + * @throws BuildException if a reference does not have a refid. */ private void addReferences() throws BuildException { Hashtable thisReferences @@ -494,11 +494,12 @@ /** * Try to clone and reconfigure the object referenced by oldkey in - * the parent project and add it to the new project with the key - * newkey. + * the parent project and add it to the new project with the key newkey. * * <p>If we cannot clone it, copy the referenced object itself and * keep our fingers crossed.</p> + * @param oldKey the reference id in the current project. + * @param newKey the reference id in the new project. */ private void copyReference(String oldKey, String newKey) { Object orig = getProject().getReference(oldKey); @@ -547,7 +548,7 @@ * Copies all properties from the given table to the new project - * omitting those that have already been set in the new project as * well as properties named basedir or ant.file. - * @param props properties to copy to the new project + * @param props properties <code>Hashtable</code> to copy to the new project. * @since Ant 1.6 */ private void addAlmostAll(Hashtable props) { @@ -573,17 +574,16 @@ * Defaults to the current project's basedir, unless inheritall * has been set to false, in which case it doesn't have a default * value. This will override the basedir setting of the called project. - * @param d new directory + * @param d new directory as <code>File</code>. */ public void setDir(File d) { this.dir = d; } /** - * The build file to use. - * Defaults to "build.xml". This file is expected to be a filename relative - * to the dir attribute given. - * @param s build file to use + * The build file to use. Defaults to "build.xml". This file is expected + * to be a filename relative to the dir attribute given. + * @param s the <code>String</code> build file name. */ public void setAntfile(String s) { // @note: it is a string and not a file to handle relative/absolute @@ -595,22 +595,21 @@ /** * The target of the new Ant project to execute. * Defaults to the new project's default target. - * @param s target to invoke + * @param s the name of the target to invoke. */ public void setTarget(String s) { if (s.equals("")) { throw new BuildException("target attribute must not be empty"); } - - this.target = s; + targets.add(s); + targetAttributeSet = true; } /** - * Filename to write the output to. - * This is relative to the value of the dir attribute - * if it has been set or to the base directory of the + * Set the filename to write the output to. This is relative to the value + * of the dir attribute if it has been set or to the base directory of the * current project otherwise. - * @param s file to which the output should go to + * @param s the name of the file to which the output should go. */ public void setOutput(String s) { this.output = s; @@ -618,8 +617,8 @@ /** * Property to pass to the new project. - * The property is passed as a 'user property' - * @return new property created + * The property is passed as a 'user property'. + * @return the created <code>Property</code> object. */ public Property createProperty() { if (newProject == null) { @@ -633,18 +632,35 @@ } /** - * Reference element identifying a data type to carry + * Add a Reference element identifying a data type to carry * over to the new project. - * @param r reference to add + * @param r <code>Reference</code> to add. */ public void addReference(Reference r) { references.addElement(r); } /** - * Set of properties to pass to the new project. + * Add a target to this Ant invocation. + * @param t the <CODE>TargetElement</CODE> to add. + * @since Ant 1.6.3 + */ + public void addConfiguredTarget(TargetElement t) { + if (targetAttributeSet) { + throw new BuildException( + "nested target is incompatible with the target attribute"); + } + String name = t.getName(); + if (name.equals("")) { + throw new BuildException("target name must not be empty"); + } + targets.add(name); + } + + /** + * Add a set of properties to pass to the new project. * - * @param ps property set to add + * @param ps <code>PropertySet</code> to add. * @since Ant 1.6 */ public void addPropertyset(PropertySet ps) { @@ -665,7 +681,7 @@ public static class Reference extends org.apache.tools.ant.types.Reference { - /** Creates a reference to be configured by Ant */ + /** Creates a reference to be configured by Ant. */ public Reference() { super(); } @@ -677,19 +693,50 @@ * new project. * * @param targetid the id under which this reference will be passed to - * the new project */ + * the new project. */ public void setToRefid(String targetid) { this.targetid = targetid; } /** * Get the id under which this reference will be stored in the new - * project + * project. * * @return the id of the reference in the new project. */ public String getToRefid() { return targetid; + } + } + + /** + * Helper class that implements the nested <target> + * element of <ant> and <antcall>. + * @since Ant 1.6.3 + */ + public static class TargetElement { + private String name; + + /** + * Default constructor. + */ + public TargetElement() { + } + + /** + * Set the name of this TargetElement. + * @param name the <CODE>String</CODE> target name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get the name of this TargetElement. + * @return <CODE>String</CODE>. + */ + public String getName() { + return name; } } } 1.36.2.5 +46 -25 ant/src/main/org/apache/tools/ant/taskdefs/CallTarget.java Index: CallTarget.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/CallTarget.java,v retrieving revision 1.36.2.4 retrieving revision 1.36.2.5 diff -u -r1.36.2.4 -r1.36.2.5 --- CallTarget.java 9 Mar 2004 17:01:33 -0000 1.36.2.4 +++ CallTarget.java 14 Dec 2004 23:48:01 -0000 1.36.2.5 @@ -17,10 +17,12 @@ package org.apache.tools.ant.taskdefs; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Task; import java.io.IOException; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.PropertySet; + /** * Call another target in the same project. * @@ -41,7 +43,6 @@ * defined in the project itself. * * - * * @since Ant 1.2 * * @ant.task name="antcall" category="control" @@ -49,15 +50,17 @@ public class CallTarget extends Task { private Ant callee; - private String subTarget; // must match the default value of Ant#inheritAll private boolean inheritAll = true; // must match the default value of Ant#inheritRefs private boolean inheritRefs = false; + private boolean targetSet = false; + /** * If true, pass all properties to the new Ant project. * Defaults to true. + * @param inherit <code>boolean</code> flag. */ public void setInheritAll(boolean inherit) { inheritAll = inherit; @@ -65,16 +68,16 @@ /** * If true, pass all references to the new Ant project. - * Defaults to false - * @param inheritRefs new value + * Defaults to false. + * @param inheritRefs <code>boolean</code> flag. */ public void setInheritRefs(boolean inheritRefs) { this.inheritRefs = inheritRefs; } /** - * init this task by creating new instance of the ant task and - * configuring it's by calling its own init method. + * Initialize this task by creating new instance of the ant task and + * configuring it by calling its own init method. */ public void init() { callee = (Ant) getProject().createTask("ant"); @@ -85,29 +88,28 @@ } /** - * hand off the work to the ant task of ours, after setting it up + * Delegate the work to the ant task instance, after setting it up. * @throws BuildException on validation failure or if the target didn't - * execute + * execute. */ public void execute() throws BuildException { if (callee == null) { init(); } - - if (subTarget == null) { - throw new BuildException("Attribute target is required.", - getLocation()); + if (!targetSet) { + throw new BuildException( + "Attribute target or at least one nested target is required.", + getLocation()); } - callee.setAntfile(getProject().getProperty("ant.file")); - callee.setTarget(subTarget); callee.setInheritAll(inheritAll); callee.setInheritRefs(inheritRefs); callee.execute(); } /** - * Property to pass to the invoked target. + * Create a new Property to pass to the invoked target(s). + * @return a <code>Property</code> object. */ public Property createParam() { if (callee == null) { @@ -119,6 +121,7 @@ /** * Reference element identifying a data type to carry * over to the invoked target. + * @param r the specified <code>Ant.Reference</code>. * @since Ant 1.5 */ public void addReference(Ant.Reference r) { @@ -130,10 +133,10 @@ /** * Set of properties to pass to the new project. - * + * @param ps the <code>PropertySet</code> to pass. * @since Ant 1.6 */ - public void addPropertyset(org.apache.tools.ant.types.PropertySet ps) { + public void addPropertyset(PropertySet ps) { if (callee == null) { init(); } @@ -141,14 +144,32 @@ } /** - * Target to execute, required. + * Set target to execute. + * @param target the name of the target to execute. */ public void setTarget(String target) { - subTarget = target; + if (callee == null) { + init(); + } + callee.setTarget(target); + targetSet = true; + } + + /** + * Add a target to the list of targets to invoke. + * @param t <code>Ant.TargetElement</code> representing the target. + * @since Ant 1.6.3 + */ + public void addConfiguredTarget(Ant.TargetElement t) { + if (callee == null) { + init(); + } + callee.addConfiguredTarget(t); + targetSet = true; } /** - * Pass output sent to System.out to the new project. + * @see Task#handleOutput(String) * * @since Ant 1.5 */ @@ -175,7 +196,7 @@ } /** - * Pass output sent to System.out to the new project. + * @see Task#handleFlush(String) * * @since Ant 1.5.2 */ @@ -188,7 +209,7 @@ } /** - * Pass output sent to System.err to the new project. + * @see Task#handleErrorOutput(String) * * @since Ant 1.5 */ @@ -201,7 +222,7 @@ } /** - * Pass output sent to System.err to the new project and flush stream. + * @see Task#handleErrorFlush(String) * * @since Ant 1.5.2 */ No revision No revision 1.19.2.5 +39 -1 ant/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java Index: AntTest.java =================================================================== RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java,v retrieving revision 1.19.2.4 retrieving revision 1.19.2.5 diff -u -r1.19.2.4 -r1.19.2.5 --- AntTest.java 9 Mar 2004 17:02:01 -0000 1.19.2.4 +++ AntTest.java 14 Dec 2004 23:48:01 -0000 1.19.2.5 @@ -275,6 +275,38 @@ expectLog("topleveltarget", "Hello world"); } + public void testMultiplePropertyFileChildren() { + PropertyChecker pcBar = new PropertyChecker("bar", + new String[] {null, "Bar"}); + PropertyChecker pcFoo = new PropertyChecker("foo", + new String[] {null, "Foo"}); + project.addBuildListener(pcBar); + project.addBuildListener(pcFoo); + executeTarget("multiple-property-file-children"); + AssertionFailedError aeBar = pcBar.getError(); + if (aeBar != null) { + throw aeBar; + } + AssertionFailedError aeFoo = pcFoo.getError(); + if (aeFoo != null) { + throw aeFoo; + } + project.removeBuildListener(pcBar); + project.removeBuildListener(pcFoo); + } + + public void testBlankTarget() { + expectBuildException("blank-target", "target name must not be empty"); + } + + public void testMultipleTargets() { + expectLog("multiple-targets", "tadadctbdbtc"); + } + + public void testMultipleTargets2() { + expectLog("multiple-targets-2", "dadctb"); + } + private class BasedirChecker implements BuildListener { private String[] expectedBasedirs; private int calls = 0; @@ -450,6 +482,12 @@ if (event.getTarget().getName().equals("")) { return; } + if (calls >= expectedValues.length) { + error = new AssertionFailedError("Unexpected invocation of" + + " target " + + event.getTarget().getName()); + } + if (error == null) { try { assertEquals(expectedValues[calls++], 1.3.2.5 +12 -0 ant/src/testcases/org/apache/tools/ant/taskdefs/CallTargetTest.java Index: CallTargetTest.java =================================================================== RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/CallTargetTest.java,v retrieving revision 1.3.2.4 retrieving revision 1.3.2.5 diff -u -r1.3.2.4 -r1.3.2.5 --- CallTargetTest.java 9 Mar 2004 17:02:01 -0000 1.3.2.4 +++ CallTargetTest.java 14 Dec 2004 23:48:01 -0000 1.3.2.5 @@ -55,6 +55,18 @@ assertLogContaining("multi is SETmulti is SET"); } + public void testBlankTarget() { + expectBuildException("blank-target", "target name must not be empty"); + } + + public void testMultipleTargets() { + expectLog("multiple-targets", "tadadctbdbtc"); + } + + public void testMultipleTargets2() { + expectLog("multiple-targets-2", "dadctb"); + } + public void tearDown() { project.executeTarget("cleanup"); } No revision No revision 1.18.2.8 +28 -3 ant/docs/manual/CoreTasks/ant.html Index: ant.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTasks/ant.html,v retrieving revision 1.18.2.7 retrieving revision 1.18.2.8 diff -u -r1.18.2.7 -r1.18.2.8 --- ant.html 19 Nov 2004 09:10:00 -0000 1.18.2.7 +++ ant.html 14 Dec 2004 23:48:01 -0000 1.18.2.8 @@ -13,7 +13,7 @@ <p>Runs Ant on a supplied buildfile. This can be used to build subprojects. <strong>This task must not be used outside of a -<code>target</code> if it invoces the same build file it is part +<code>target</code> if it invokes the same build file it is part of.</strong></p> <p>When the <i>antfile</i> attribute is omitted, the file "build.xml" @@ -34,7 +34,7 @@ to the new project and any project created in that project regardless of the setting of <i>inheritAll</i>. This allows you to parameterize your subprojects. Properties defined on the command line -can not be overridden by nested <code><property></code> elements.</p> +cannot be overridden by nested <code><property></code> elements.</p> <p>References to data types can also be passed to the new project, but by default they are not. If you set the inheritrefs attribute to @@ -103,7 +103,12 @@ <h4>property</h4> <p>See the description of the <a href="property.html">property -task</a>. Note that the <code>refid</code> attribute points to a +task</a>. <br/> +These properties become equivalent to properties you define on +the command line. These are special properties and they will always get passed +down, even through additional <code><*ant*></code> tasks with inheritall set to +false (see above). <br/> +Note that the <code>refid</code> attribute points to a reference in the calling project, not in the new one.</p> <h4><a name="reference">reference</a></h4> @@ -135,6 +140,26 @@ href="../CoreTypes/propertyset.html">propertyset</a>s.</p> <p><em>since Ant 1.6</em>.</p> + +<h4>target</h4> + +<p>You can specify multiple targets using nested <code><target></code> elements +instead of using the target attribute. These will be executed as if +Ant had been invoked with a single target whose dependencies are the +targets so specified, in the order specified.</p> +<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">name</td> + <td valign="top">The name of the called target.</td> + <td valign="top" align="center">Yes</td> + </tr> +</table> +<p><em>since Ant 1.6.3</em>.</p> <h3>Basedir of the new project</h3> 1.18.2.8 +30 -5 ant/docs/manual/CoreTasks/antcall.html Index: antcall.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTasks/antcall.html,v retrieving revision 1.18.2.7 retrieving revision 1.18.2.8 diff -u -r1.18.2.7 -r1.18.2.8 --- antcall.html 19 Nov 2004 09:10:00 -0000 1.18.2.7 +++ antcall.html 14 Dec 2004 23:48:01 -0000 1.18.2.8 @@ -11,9 +11,9 @@ <h2><a name="antcall">AntCall</a></h2> <h3>Description</h3> -<p>Call another target within the same build-file optionally -specifying some properties (param's in this context). <strong>This -task must no be used outside of a <code>target</code>.</strong></p> +<p>Call another target within the same buildfile optionally +specifying some properties (params in this context). <strong>This +task must not be used outside of a <code>target</code>.</strong></p> <p>By default, all of the properties of the current project will be available in the new project. Alternatively, you can @@ -42,7 +42,7 @@ the target "doSomethingElse" depended on the target "init", then the <i>antcall</i> of "doSomethingElse" will call "init" during the call. Of course, any properties defined in the antcall task or inherited from the calling target -will be fixed and not overridable in the init task -or indeed in the "doSomethingElse" task. +will be fixed and not overridable in the init task--or indeed in the "doSomethingElse" task. </p> <p>If the build file changes after you've started the build, the @@ -89,7 +89,12 @@ <h3>Parameters specified as nested elements</h3> <h4>param</h4> <p>Specifies the properties to set before running the specified target. See <a -href="property.html">property</a> for usage guidelines.</p> +href="property.html">property</a> for usage guidelines.<br/> +These properties become equivalent to properties you define on +the command line. These are special properties and they will always get passed +down, even through additional <code><*ant*></code> tasks with inheritall set to +false (see above). +</p> <h4><a name="reference">reference</a></h4> <p>Used to choose references that shall be copied into the new project, @@ -120,6 +125,26 @@ href="../CoreTypes/propertyset.html">propertyset</a>s.</p> <p><em>since Ant 1.6</em>.</p> + +<h4>target</h4> + +<p>You can specify multiple targets using nested <code><target></code> elements +instead of using the target attribute. These will be executed as if +Ant had been invoked with a single target whose dependencies are the +targets so specified, in the order specified.</p> +<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">name</td> + <td valign="top">The name of the called target.</td> + <td valign="top" align="center">Yes</td> + </tr> +</table> +<p><em>since Ant 1.6.3</em>.</p> <h3>Examples</h3> <pre>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]