mbenson 2004/06/24 12:30:03 Modified: . WHATSNEW docs/manual/CoreTasks ant.html antcall.html src/etc/testcases/taskdefs ant.xml calltarget.xml src/main/org/apache/tools/ant Project.java src/main/org/apache/tools/ant/taskdefs Ant.java CallTarget.java src/testcases/org/apache/tools/ant/taskdefs AntTest.java CallTargetTest.java Log: Added multiple targets to <ant> and <antcall> using nested <target> elements. PR: 5270, 8148, 17071, 6368, 29623 Revision Changes Path 1.631 +4 -0 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.630 retrieving revision 1.631 diff -u -r1.630 -r1.631 --- WHATSNEW 23 Jun 2004 19:41:27 -0000 1.630 +++ WHATSNEW 24 Jun 2004 19:30:03 -0000 1.631 @@ -21,6 +21,10 @@ * A new base class DispatchTask has been added to facilitate elegant creation of tasks with multiple actions. +* Added <target> nested elements to <ant> and <antcall> to allow + specification of multiple sub-build targets, which are executed + with a single dependency analysis. + Changes from Ant 1.6.1 to current Ant 1.6 CVS version ===================================================== 1.25 +20 -0 ant/docs/manual/CoreTasks/ant.html Index: ant.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTasks/ant.html,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- ant.html 3 Mar 2004 15:03:22 -0000 1.24 +++ ant.html 24 Jun 2004 19:30:03 -0000 1.25 @@ -135,6 +135,26 @@ <p><em>since Ant 1.6</em>.</p> +<h4>target</h4> + +<p>You can specify multiple targets using nested <target> 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.2</em>.</p> + <h3>Basedir of the new project</h3> <p>The basedir value of the new project is affected by the two 1.25 +20 -0 ant/docs/manual/CoreTasks/antcall.html Index: antcall.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTasks/antcall.html,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- antcall.html 3 Mar 2004 15:03:22 -0000 1.24 +++ antcall.html 24 Jun 2004 19:30:03 -0000 1.25 @@ -120,6 +120,26 @@ <p><em>since Ant 1.6</em>.</p> +<h4>target</h4> + +<p>You can specify multiple targets using nested <target> 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.2</em>.</p> + <h3>Examples</h3> <pre> <target name="default"> 1.14 +22 -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.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- ant.xml 10 Oct 2003 13:17:34 -0000 1.13 +++ ant.xml 24 Jun 2004 19:30:03 -0000 1.14 @@ -192,4 +192,26 @@ </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="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.4 +24 -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.4 diff -u -r1.3 -r1.4 --- calltarget.xml 5 Aug 2003 13:56:26 -0000 1.3 +++ calltarget.xml 24 Jun 2004 19:30:03 -0000 1.4 @@ -50,4 +50,27 @@ <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="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.170 +41 -8 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.169 retrieving revision 1.170 diff -u -r1.169 -r1.170 --- Project.java 24 Jun 2004 11:16:40 -0000 1.169 +++ Project.java 24 Jun 2004 19:30:03 -0000 1.170 @@ -1187,7 +1187,16 @@ // exist, and if there is any cycle in the dependency // graph. Vector sortedTargets = topoSort(targetName, targets); + sortedTargets.setSize(sortedTargets.indexOf(targets.get(targetName)) + 1); + executeSortedTargets(sortedTargets); + } + /** + * 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(); @@ -1245,9 +1254,6 @@ } } } - if (curtarget.getName().equals(targetName)) { // old exit condition - break; - } } if (buildException != null) { throw buildException; @@ -1565,20 +1571,47 @@ */ public final Vector topoSort(String root, Hashtable targets) throws BuildException { + return topoSort(new String[] {root}, targets); + } + + /** + * 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 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). + * Must not be <code>null</code>. + * @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. + */ + public final Vector topoSort(String[] root, Hashtable targets) + 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++) { + tsort(root[i], targets, state, visiting, ret); + } + 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); + for (Enumeration en = targets.keys(); en.hasMoreElements();) { String curTarget = (String) en.nextElement(); String st = (String) state.get(curTarget); 1.104 +83 -16 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.103 retrieving revision 1.104 diff -u -r1.103 -r1.104 --- Ant.java 24 Jun 2004 11:56:20 -0000 1.103 +++ Ant.java 24 Jun 2004 19:30:03 -0000 1.104 @@ -71,9 +71,6 @@ */ private String antFile = null; - /** the target to call if any */ - private String target = null; - /** the output */ private String output = null; @@ -98,6 +95,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. @@ -285,7 +288,7 @@ public void execute() throws BuildException { File savedDir = dir; String savedAntFile = antFile; - String savedTarget = target; + Vector locals = new Vector(targets); try { if (newProject == null) { reinit(); @@ -317,8 +320,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"); @@ -348,8 +352,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") @@ -358,13 +365,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" @@ -377,12 +389,20 @@ 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); + String[] nameArray = + (String[])(locals.toArray(new String[locals.size()])); + + Hashtable targets = newProject.getTargets(); + Vector sortedTargets = newProject.topoSort(nameArray, targets); + + sortedTargets.setSize(sortedTargets.indexOf(targets.get( + locals.lastElement())) + 1); + newProject.executeSortedTargets(sortedTargets); } catch (BuildException ex) { t = ProjectHelper .addLocationToBuildException(ex, getLocation()); @@ -410,7 +430,6 @@ } dir = savedDir; antFile = savedAntFile; - target = savedTarget; } } @@ -601,7 +620,8 @@ throw new BuildException("target attribute must not be empty"); } - this.target = s; + targets.add(s); + targetAttributeSet = true; } /** @@ -641,6 +661,23 @@ } /** + * Add a target to this Ant invocation. + * @param target the <CODE>TargetElement</CODE> to add. + * @since Ant 1.7 + */ + 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); + } + + /** * Set of properties to pass to the new project. * * @param ps property set to add @@ -689,6 +726,36 @@ */ public String getToRefid() { return targetid; + } + } + + /** + * Helper class that implements the nested <target> + * element of <ant> and <antcall>. + * @since Ant 1.7 + */ + 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.41 +24 -6 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.40 retrieving revision 1.41 diff -u -r1.40 -r1.41 --- CallTarget.java 9 Mar 2004 16:48:04 -0000 1.40 +++ CallTarget.java 24 Jun 2004 19:30:03 -0000 1.41 @@ -48,12 +48,13 @@ 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. @@ -93,13 +94,13 @@ 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(); @@ -143,7 +144,24 @@ * Target to execute, required. */ public void setTarget(String target) { - subTarget = target; + if (callee == null) { + init(); + } + callee.setTarget(target); + targetSet = true; + } + + /** + * Target element identifying a data type to carry + * over to the invoked target. + * @since Ant 1.6.2 + */ + public void addConfiguredTarget(Ant.TargetElement t) { + if (callee == null) { + init(); + } + callee.addConfiguredTarget(t); + targetSet = true; } /** 1.26 +9 -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.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- AntTest.java 9 Mar 2004 16:48:56 -0000 1.25 +++ AntTest.java 24 Jun 2004 19:30:03 -0000 1.26 @@ -295,6 +295,14 @@ project.removeBuildListener(pcFoo); } + public void testBlankTarget() { + expectBuildException("blank-target", "target name must not be empty"); + } + + public void testMultipleTargets() { + expectLog("multiple-targets", "tadadctbdbtc"); + } + private class BasedirChecker implements BuildListener { private String[] expectedBasedirs; private int calls = 0; 1.8 +8 -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.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- CallTargetTest.java 9 Mar 2004 16:48:57 -0000 1.7 +++ CallTargetTest.java 24 Jun 2004 19:30:03 -0000 1.8 @@ -55,6 +55,14 @@ 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 tearDown() { project.executeTarget("cleanup"); }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]