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]