Submitted by: Matthieu Bentot <mbentot@arantech.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270105 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -117,6 +117,10 @@ Other changes: | |||||
| * <apply> has a new attribute relative that allows users to pass the | * <apply> has a new attribute relative that allows users to pass the | ||||
| filenames as relative instead of absolute paths on the command line. | filenames as relative instead of absolute paths on the command line. | ||||
| * References will now be copied into the child build by <ant> and | |||||
| <antcall> 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 | Changes from Ant 1.4 to Ant 1.4.1 | ||||
| =========================================== | =========================================== | ||||
| @@ -24,6 +24,16 @@ are set in the new project (See also the <a href="property.html">property task</ | |||||
| <p>You can also set properties in the new project from the old project by | <p>You 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 | using nested property tags. These properties are always passed regardless of the | ||||
| setting of <i>inheritAll</i>. This allows you to parameterize your subprojects.</p> | setting of <i>inheritAll</i>. This allows you to parameterize your subprojects.</p> | ||||
| <p>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 | |||||
| <i>inheritall</i> attribute to <code>false</code> 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.</p> | |||||
| <h3>Parameters</h3> | <h3>Parameters</h3> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| <tr> | <tr> | ||||
| @@ -60,15 +70,41 @@ setting of <i>inheritAll</i>. This allows you to parameterize your subprojects. | |||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">inheritAll</td> | |||||
| <td valign="top">If <code>true</code>, pass all properties to the new Ant | |||||
| project. Defaults to <code>true</code>. | |||||
| <td valign="top">inheritAll</td> <td valign="top">If | |||||
| <code>true</code>, pass all properties and references to the new | |||||
| Ant project. Defaults to <code>true</code>. | |||||
| </td> | </td> | ||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| <h4>Basedir of the new project</h4> | |||||
| <h3>Parameters specified as nested elements</h3> | |||||
| <h4>property</h4> | |||||
| <p>See the description of the <a href="property.html">property task</a>.</p> | |||||
| <h4>reference</h4> | |||||
| <p>Used to chose references that shall be copied into the new project, | |||||
| optionally changing their id.</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">refid</td> | |||||
| <td valign="top">The id of the reference in the calling project.</td> | |||||
| <td valign="top" align="center">Yes</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">toid</td> | |||||
| <td valign="top">The id of the reference in the new project.</td> | |||||
| <td valign="top" align="center">No, defaults to the value of refid.</td> | |||||
| </tr> | |||||
| </table> | |||||
| <h3>Basedir of the new project</h3> | |||||
| <p>The basedir value of the new project is affected by the two | <p>The basedir value of the new project is affected by the two | ||||
| attributes dir and inheritall, see the following table for | attributes dir and inheritall, see the following table for | ||||
| @@ -119,6 +155,60 @@ details:</p> | |||||
| <property name="output.type" value="html"/> | <property name="output.type" value="html"/> | ||||
| </ant> | </ant> | ||||
| </pre> | </pre> | ||||
| <p>The build file of the calling project defines some | |||||
| <code><path></code> elements like this:</p> | |||||
| <pre> | |||||
| <path id="path1"> | |||||
| ... | |||||
| </> | |||||
| <path id="path2"> | |||||
| ... | |||||
| </> | |||||
| </pre> | |||||
| <p>and the called build file (<code>subbuild.xml</code>) also defines | |||||
| a <code><path></code> with the id <code>path1</code>, but | |||||
| <code>path2</code> is not defined:</p> | |||||
| <pre> | |||||
| <ant antfile="subbuild.xml" /> | |||||
| </pre> | |||||
| <p>will not override <code>subbuild</code>'s definition of | |||||
| <code>path1</code>, but make the parent's definition of | |||||
| <code>path2</code> available in the subbuild. As does:</p> | |||||
| <pre> | |||||
| <ant antfile="subbuild.xml" inheritall="true" /> | |||||
| </pre> | |||||
| <pre> | |||||
| <ant antfile="subbuild.xml" inheritall="false" /> | |||||
| </pre> | |||||
| <p>will neither override <code>path1</code> nor copy | |||||
| <code>path2</code>.</p> | |||||
| <pre> | |||||
| <ant antfile="subbuild.xml" inheritall="false" > | |||||
| <reference refid="path1" /> | |||||
| </ant> | |||||
| </pre> | |||||
| <p>will override <code>subbuild</code>'s definition of | |||||
| <code>path1</code>.</p> | |||||
| <pre> | |||||
| <ant antfile="subbuild.xml" inheritall="false" > | |||||
| <reference refid="path1" torefid="path2" /> | |||||
| </ant> | |||||
| </pre> | |||||
| <p>will copy the parent's definition of <code>path1</code> into the | |||||
| new project using the id <code>path2</code>.</p> | |||||
| <hr> | <hr> | ||||
| <p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | <p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -53,4 +53,18 @@ | |||||
| <ant antfile="ant/ant.xml" target="callback" inheritAll="false" /> | <ant antfile="ant/ant.xml" target="callback" inheritAll="false" /> | ||||
| </target> | </target> | ||||
| <target name="testInherit"> | |||||
| <ant antfile="ant/references.xml" inheritAll="true" target="dummy" /> | |||||
| </target> | |||||
| <target name="testNoInherit"> | |||||
| <ant antfile="ant/references.xml" inheritAll="false" target="dummy" /> | |||||
| </target> | |||||
| <target name="testRename"> | |||||
| <ant antfile="ant/references.xml" inheritAll="false" target="dummy"> | |||||
| <reference refid="path" torefid="newpath" /> | |||||
| </ant> | |||||
| </target> | |||||
| </project> | </project> | ||||
| @@ -0,0 +1,10 @@ | |||||
| <project name="test" default="def" basedir="."> | |||||
| <path id="no-override" /> | |||||
| <target name="def"> | |||||
| <fail>This build file should only be run from within the testcase</fail> | |||||
| </target> | |||||
| <target name="dummy" /> | |||||
| </project> | |||||
| @@ -108,6 +108,9 @@ public class Ant extends Task { | |||||
| /** the properties to pass to the new project */ | /** the properties to pass to the new project */ | ||||
| private Vector properties = new Vector(); | 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 */ | /** the temporary project created to run the build file */ | ||||
| private Project newProject; | private Project newProject; | ||||
| @@ -256,14 +259,8 @@ public class Ant extends Task { | |||||
| dir = project.getBaseDir(); | 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) { | if (antFile == null) { | ||||
| antFile = "build.xml"; | antFile = "build.xml"; | ||||
| } | } | ||||
| @@ -278,6 +275,8 @@ public class Ant extends Task { | |||||
| target = newProject.getDefaultTarget(); | target = newProject.getDefaultTarget(); | ||||
| } | } | ||||
| addReferences(); | |||||
| // Are we trying to call the target in which we are defined? | // Are we trying to call the target in which we are defined? | ||||
| if (newProject.getBaseDir().equals(project.getBaseDir()) && | if (newProject.getBaseDir().equals(project.getBaseDir()) && | ||||
| newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) && | 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 ); | properties.addElement( p ); | ||||
| return 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; } | |||||
| } | |||||
| } | } | ||||
| @@ -125,6 +125,14 @@ public class CallTarget extends Task { | |||||
| return callee.createProperty(); | 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) { | public void setTarget(String target) { | ||||
| subTarget = target; | subTarget = target; | ||||
| } | } | ||||
| @@ -59,9 +59,10 @@ import java.io.File; | |||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import org.apache.tools.ant.BuildEvent; | import org.apache.tools.ant.BuildEvent; | ||||
| import org.apache.tools.ant.BuildFileTest; | |||||
| import org.apache.tools.ant.BuildListener; | import org.apache.tools.ant.BuildListener; | ||||
| import org.apache.tools.ant.types.Path; | |||||
| import org.apache.tools.ant.BuildFileTest; | |||||
| /** | /** | ||||
| * @author Nico Seessle <nico@seessle.de> | * @author Nico Seessle <nico@seessle.de> | ||||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
| @@ -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 class BasedirChecker implements BuildListener { | ||||
| private String[] expectedBasedirs; | private String[] expectedBasedirs; | ||||
| private int calls = 0; | 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; | |||||
| } | |||||
| } | |||||
| } | } | ||||