From 05b5cb8f3d92ae5b438a0c03a5c2daa5e264270b Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Mon, 10 Dec 2001 10:10:35 +0000 Subject: [PATCH] Allow and to pass references to the subbuilds. Submitted by: Matthieu Bentot git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270105 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 4 + docs/manual/CoreTasks/ant.html | 98 ++++++++++++++++++- src/etc/testcases/taskdefs/ant.xml | 14 +++ src/etc/testcases/taskdefs/ant/references.xml | 10 ++ .../org/apache/tools/ant/taskdefs/Ant.java | 96 ++++++++++++++++-- .../apache/tools/ant/taskdefs/CallTarget.java | 8 ++ .../apache/tools/ant/taskdefs/AntTest.java | 94 +++++++++++++++++- 7 files changed, 311 insertions(+), 13 deletions(-) create mode 100644 src/etc/testcases/taskdefs/ant/references.xml diff --git a/WHATSNEW b/WHATSNEW index 81d4c0132..21a1c09c2 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -117,6 +117,10 @@ Other changes: * has a new attribute relative that allows users to pass the filenames as relative instead of absolute paths on the command line. +* References will now be copied into the child build by and + unless a reference of the same name already exists in the + subbuild or inheritall has been set to false. + Changes from Ant 1.4 to Ant 1.4.1 =========================================== diff --git a/docs/manual/CoreTasks/ant.html b/docs/manual/CoreTasks/ant.html index 6e835bc9d..7a9ed2685 100644 --- a/docs/manual/CoreTasks/ant.html +++ b/docs/manual/CoreTasks/ant.html @@ -24,6 +24,16 @@ are set in the new project (See also the property taskYou can also set properties in the new project from the old project by using nested property tags. These properties are always passed regardless of the setting of inheritAll. This allows you to parameterize your subprojects.

+ +

References to data types will also be passed to the new project by +default, but they will not override references defined in the new +project. You can limit the references you want to copy by setting the +inheritall attribute to false and using nested +reference elements. The nested elements can also be used to copy +references from the calling project to the new project under a +different id. References taken from nested elements will override +existing references in the new project.

+

Parameters

@@ -60,15 +70,41 @@ setting of inheritAll. This allows you to parameterize your subprojects. - -
No
inheritAllIf true, pass all properties to the new Ant - project. Defaults to true. + inheritAll If + true, pass all properties and references to the new + Ant project. Defaults to true. No
-

Basedir of the new project

+

Parameters specified as nested elements

+

property

+

See the description of the property task.

+ +

reference

+

Used to chose references that shall be copied into the new project, +optionally changing their id.

+ + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
refidThe id of the reference in the calling project.Yes
toidThe id of the reference in the new project.No, defaults to the value of refid.
+ +

Basedir of the new project

The basedir value of the new project is affected by the two attributes dir and inheritall, see the following table for @@ -119,6 +155,60 @@ details:

<property name="output.type" value="html"/> </ant> + +

The build file of the calling project defines some +<path> elements like this:

+ +
+  <path id="path1">
+    ...
+  </>
+  <path id="path2">
+    ...
+  </>
+
+ +

and the called build file (subbuild.xml) also defines +a <path> with the id path1, but +path2 is not defined:

+ +
+  <ant antfile="subbuild.xml" />
+
+ +

will not override subbuild's definition of +path1, but make the parent's definition of +path2 available in the subbuild. As does:

+ +
+  <ant antfile="subbuild.xml" inheritall="true" />
+
+ +
+  <ant antfile="subbuild.xml" inheritall="false" />
+
+ +

will neither override path1 nor copy +path2.

+ +
+  <ant antfile="subbuild.xml" inheritall="false" >
+    <reference refid="path1" />
+  </ant>
+
+ +

will override subbuild's definition of +path1.

+ +
+  <ant antfile="subbuild.xml" inheritall="false" >
+    <reference refid="path1" torefid="path2" />
+  </ant>
+
+ +

will copy the parent's definition of path1 into the +new project using the id path2.

+

Copyright © 2000,2001 Apache Software Foundation. All rights Reserved.

diff --git a/src/etc/testcases/taskdefs/ant.xml b/src/etc/testcases/taskdefs/ant.xml index d65b79b6a..19e86f618 100644 --- a/src/etc/testcases/taskdefs/ant.xml +++ b/src/etc/testcases/taskdefs/ant.xml @@ -53,4 +53,18 @@ + + + + + + + + + + + + + + diff --git a/src/etc/testcases/taskdefs/ant/references.xml b/src/etc/testcases/taskdefs/ant/references.xml new file mode 100644 index 000000000..937a0e590 --- /dev/null +++ b/src/etc/testcases/taskdefs/ant/references.xml @@ -0,0 +1,10 @@ + + + + + + This build file should only be run from within the testcase + + + + \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/taskdefs/Ant.java b/src/main/org/apache/tools/ant/taskdefs/Ant.java index 15c12d56e..bf28b09ec 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Ant.java +++ b/src/main/org/apache/tools/ant/taskdefs/Ant.java @@ -108,6 +108,9 @@ public class Ant extends Task { /** the properties to pass to the new project */ private Vector properties = new Vector(); + /** the references to pass to the new project */ + private Vector references = new Vector(); + /** the temporary project created to run the build file */ private Project newProject; @@ -256,14 +259,8 @@ public class Ant extends Task { dir = project.getBaseDir(); } - // Override with local-defined properties - Enumeration e = properties.elements(); - while (e.hasMoreElements()) { - Property p=(Property) e.nextElement(); - p.setProject(newProject); - p.execute(); - } - + overrideProperties(); + if (antFile == null) { antFile = "build.xml"; } @@ -278,6 +275,8 @@ public class Ant extends Task { target = newProject.getDefaultTarget(); } + addReferences(); + // Are we trying to call the target in which we are defined? if (newProject.getBaseDir().equals(project.getBaseDir()) && newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) && @@ -294,6 +293,65 @@ public class Ant extends Task { } } + /** + * Override the properties in the new project with the one + * explicitly defined as nested elements here. + */ + private void overrideProperties() throws BuildException { + Enumeration e = properties.elements(); + while (e.hasMoreElements()) { + Property p = (Property) e.nextElement(); + p.setProject(newProject); + p.execute(); + } + } + + /** + * Add the references explicitly defined as nested elements to the + * new project. Also copy over all references that don't override + * existing references in the new project if inheritall has been + * requested. + */ + private void addReferences() throws BuildException { + Hashtable thisReferences = (Hashtable) project.getReferences().clone(); + Hashtable newReferences = newProject.getReferences(); + Enumeration e; + if (references.size() > 0) { + for(e = references.elements(); e.hasMoreElements();) { + Reference ref = (Reference)e.nextElement(); + String refid = ref.getRefId(); + if (refid == null) { + throw new BuildException("the refid attribute is required for reference elements"); + } + if (!thisReferences.containsKey(refid)) { + log("Parent project doesn't contain any reference '" + + refid + "'", + Project.MSG_WARN); + continue; + } + + Object o = thisReferences.remove(refid); + String toRefid = ref.getToRefid(); + if (toRefid == null) { + toRefid = refid; + } + newProject.addReference(toRefid, o); + } + } + + // Now add all references that are not defined in the + // subproject, if inheritAll is true + if (inheritAll) { + for(e = thisReferences.keys(); e.hasMoreElements();) { + String key = (String)e.nextElement(); + if (newReferences.containsKey(key)) { + continue; + } + newProject.addReference(key, thisReferences.get(key)); + } + } + } + /** * ... */ @@ -336,4 +394,26 @@ public class Ant extends Task { properties.addElement( p ); return p; } + + /** + * create a reference element that identifies a data type that + * should be carried over to the new project. + */ + public void addReference(Reference r) { + references.addElement(r); + } + + /** + * Helper class that implements the nested <reference> + * element of <ant> and <antcall>. + */ + public static class Reference + extends org.apache.tools.ant.types.Reference { + + public Reference() {super();} + + private String targetid=null; + public void setToRefid(String targetid) { this.targetid=targetid; } + public String getToRefid() { return targetid; } + } } diff --git a/src/main/org/apache/tools/ant/taskdefs/CallTarget.java b/src/main/org/apache/tools/ant/taskdefs/CallTarget.java index 14c5eb0d4..1aac0412d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/CallTarget.java +++ b/src/main/org/apache/tools/ant/taskdefs/CallTarget.java @@ -125,6 +125,14 @@ public class CallTarget extends Task { return callee.createProperty(); } + /** + * create a reference element that identifies a data type that + * should be carried over to the new project. + */ + public void addReference(Ant.Reference r) { + callee.addReference(r); + } + public void setTarget(String target) { subTarget = target; } diff --git a/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java b/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java index 49ff33bce..08db39e92 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java @@ -59,9 +59,10 @@ import java.io.File; import junit.framework.AssertionFailedError; import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildFileTest; import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.BuildFileTest; /** * @author Nico Seessle * @author Stefan Bodewig @@ -156,6 +157,59 @@ public class AntTest extends BuildFileTest { } } + public void testReferenceInheritance() { + Path p = new Path(project); + project.addReference("path", p); + project.addReference("no-override", p); + testReference("testInherit", new String[] {"path", "path"}, + new boolean[] {true, true}, p); + testReference("testInherit", + new String[] {"no-override", "no-override"}, + new boolean[] {true, false}, p); + testReference("testInherit", + new String[] {"no-override", "no-override"}, + new boolean[] {false, false}, null); + } + + public void testReferenceNoInheritance() { + Path p = new Path(project); + project.addReference("path", p); + project.addReference("no-override", p); + testReference("testNoInherit", new String[] {"path", "path"}, + new boolean[] {true, false}, p); + testReference("testNoInherit", new String[] {"path", "path"}, + new boolean[] {false, true}, null); + testReference("testInherit", + new String[] {"no-override", "no-override"}, + new boolean[] {true, false}, p); + testReference("testInherit", + new String[] {"no-override", "no-override"}, + new boolean[] {false, false}, null); + } + + public void testReferenceRename() { + Path p = new Path(project); + project.addReference("path", p); + testReference("testRename", new String[] {"path", "path"}, + new boolean[] {true, false}, p); + testReference("testRename", new String[] {"path", "path"}, + new boolean[] {false, true}, null); + testReference("testRename", new String[] {"newpath", "newpath"}, + new boolean[] {false, true}, p); + } + + protected void testReference(String target, String[] keys, + boolean[] expect, Object value) { + ReferenceChecker rc = new ReferenceChecker(keys, expect, value); + project.addBuildListener(rc); + executeTarget(target); + AssertionFailedError ae = rc.getError(); + if (ae != null) { + throw ae; + } + project.removeBuildListener(rc); + } + private class BasedirChecker implements BuildListener { private String[] expectedBasedirs; private int calls = 0; @@ -189,4 +243,42 @@ public class AntTest extends BuildFileTest { } + private class ReferenceChecker implements BuildListener { + private String[] keys; + private boolean[] expectSame; + private Object value; + private int calls = 0; + private AssertionFailedError error; + + ReferenceChecker(String[] keys, boolean[] expectSame, Object value) { + this.keys = keys; + this.expectSame = expectSame; + this.value = value; + } + + public void buildStarted(BuildEvent event) {} + public void buildFinished(BuildEvent event) {} + public void targetFinished(BuildEvent event){} + public void taskStarted(BuildEvent event) {} + public void taskFinished(BuildEvent event) {} + public void messageLogged(BuildEvent event) {} + + public void targetStarted(BuildEvent event) { + if (error == null) { + try { + assertEquals("Call "+calls+" refid=\'"+keys[calls]+"\'", + expectSame[calls], + event.getProject().getReferences().get(keys[calls++]) == value); + } catch (AssertionFailedError e) { + error = e; + } + } + } + + AssertionFailedError getError() { + return error; + } + + } + }