that controls implicit copying of references - i.e. we don't copy anything by default. Try to copy a clone before copying the real object. inheritRefs="true" doesn't make any sense for <antcall> as all references of the calling project will be defined in the new project and wouldn't be overwritten. That's why <antcall> didn't even get this attribute. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270136 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -118,9 +118,9 @@ 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. | |||||
| * References can now be copied into the child build by <ant> and | |||||
| <antcall> using nested <reference> elements or the new inheritRefs | |||||
| attribute. | |||||
| * <fail> no supports builds to fail based on conditions via if and | * <fail> no supports builds to fail based on conditions via if and | ||||
| unless attributes. | unless attributes. | ||||
| @@ -25,14 +25,16 @@ are set in the new project (See also the <a href="property.html">property task</ | |||||
| 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> | |||||
| <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 | |||||
| true, all references will be copied, but they will not override | |||||
| references defined in the new project.</p> | |||||
| <p>Nested <a href="#reference"><i><reference></i></a> elements | |||||
| can also be used to copy references from the calling project to the | |||||
| new project, optionally 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"> | ||||
| @@ -70,10 +72,15 @@ existing references in the new project.</p> | |||||
| <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 and references to the new | |||||
| Ant project. Defaults to <code>true</code>. | |||||
| </td> | |||||
| <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> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">inheritRefs</td> | |||||
| <td valign="top">If <code>true</code>, pass all references to the | |||||
| new Ant project. Defaults to <code>false</code>.</td> | |||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| @@ -82,7 +89,7 @@ existing references in the new project.</p> | |||||
| <h4>property</h4> | <h4>property</h4> | ||||
| <p>See the description of the <a href="property.html">property task</a>.</p> | <p>See the description of the <a href="property.html">property task</a>.</p> | ||||
| <h4>reference</h4> | |||||
| <h4><a name="reference">reference</a></h4> | |||||
| <p>Used to chose references that shall be copied into the new project, | <p>Used to chose references that shall be copied into the new project, | ||||
| optionally changing their id.</p> | optionally changing their id.</p> | ||||
| @@ -173,26 +180,28 @@ a <code><path></code> with the id <code>path1</code>, but | |||||
| <code>path2</code> is not defined:</p> | <code>path2</code> is not defined:</p> | ||||
| <pre> | <pre> | ||||
| <ant antfile="subbuild.xml" /> | |||||
| <ant antfile="subbuild.xml" inheritrefs="true" /> | |||||
| </pre> | </pre> | ||||
| <p>will not override <code>subbuild</code>'s definition of | <p>will not override <code>subbuild</code>'s definition of | ||||
| <code>path1</code>, but make the parent's definition of | <code>path1</code>, but make the parent's definition of | ||||
| <code>path2</code> available in the subbuild. As does:</p> | |||||
| <code>path2</code> available in the subbuild.</p> | |||||
| <pre> | <pre> | ||||
| <ant antfile="subbuild.xml" inheritall="true" /> | |||||
| <ant antfile="subbuild.xml" /> | |||||
| </pre> | </pre> | ||||
| <p>as well as</p> | |||||
| <pre> | <pre> | ||||
| <ant antfile="subbuild.xml" inheritall="false" /> | |||||
| <ant antfile="subbuild.xml" inheritrefs="false" /> | |||||
| </pre> | </pre> | ||||
| <p>will neither override <code>path1</code> nor copy | <p>will neither override <code>path1</code> nor copy | ||||
| <code>path2</code>.</p> | <code>path2</code>.</p> | ||||
| <pre> | <pre> | ||||
| <ant antfile="subbuild.xml" inheritall="false" > | |||||
| <ant antfile="subbuild.xml" inheritrefs="false" > | |||||
| <reference refid="path1" /> | <reference refid="path1" /> | ||||
| </ant> | </ant> | ||||
| </pre> | </pre> | ||||
| @@ -201,7 +210,7 @@ a <code><path></code> with the id <code>path1</code>, but | |||||
| <code>path1</code>.</p> | <code>path1</code>.</p> | ||||
| <pre> | <pre> | ||||
| <ant antfile="subbuild.xml" inheritall="false" > | |||||
| <ant antfile="subbuild.xml" inheritrefs="false" > | |||||
| <reference refid="path1" torefid="path2" /> | <reference refid="path1" torefid="path2" /> | ||||
| </ant> | </ant> | ||||
| </pre> | </pre> | ||||
| @@ -21,6 +21,13 @@ 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 param tags. These properties are always passed regardless of the | using nested param 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>Nested <a href="#reference"><i><reference></i></a> elements can | |||||
| be used to copy references from the calling project to the new | |||||
| project, optionally under a different id. References taken from | |||||
| nested elements will override existing references in the new | |||||
| project.</p> | |||||
| <p> | <p> | ||||
| When a target is invoked by antcall, all of its dependent targets will | When a target is invoked by antcall, all of its dependent targets will | ||||
| also be called within the context of any new parameters. For example. if | also be called within the context of any new parameters. For example. if | ||||
| @@ -53,6 +60,29 @@ will be fixed and not overridable in the init task -or indeed in the "doSom | |||||
| <h4>param</h4> | <h4>param</h4> | ||||
| <p>Specifies the properties to set before running the specified target. See <a | <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.</p> | ||||
| <h4><a name="reference">reference</a></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>Examples</h3> | <h3>Examples</h3> | ||||
| <pre> | <pre> | ||||
| <target name="default"> | <target name="default"> | ||||
| @@ -66,6 +96,16 @@ href="property.html">property</a> for usage guidelines.</p> | |||||
| </target> | </target> | ||||
| </pre> | </pre> | ||||
| <p>Will run the target 'doSomethingElse' and echo 'param1=value'.</p> | <p>Will run the target 'doSomethingElse' and echo 'param1=value'.</p> | ||||
| <pre> | |||||
| <antcall ... > | |||||
| <reference refid="path1" torefid="path2" /> | |||||
| </antcall> | |||||
| </pre> | |||||
| <p>will copy the parent's definition of <code>path1</code> into the | |||||
| new project using the id <code>path2</code>.</p> | |||||
| <hr><p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | <hr><p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -54,15 +54,15 @@ | |||||
| </target> | </target> | ||||
| <target name="testInherit"> | <target name="testInherit"> | ||||
| <ant antfile="ant/references.xml" inheritAll="true" target="dummy" /> | |||||
| <ant antfile="ant/references.xml" inheritRefs="true" target="dummy" /> | |||||
| </target> | </target> | ||||
| <target name="testNoInherit"> | <target name="testNoInherit"> | ||||
| <ant antfile="ant/references.xml" inheritAll="false" target="dummy" /> | |||||
| <ant antfile="ant/references.xml" inheritRefs="false" target="dummy" /> | |||||
| </target> | </target> | ||||
| <target name="testRename"> | <target name="testRename"> | ||||
| <ant antfile="ant/references.xml" inheritAll="false" target="dummy"> | |||||
| <ant antfile="ant/references.xml" inheritRefs="false" target="dummy"> | |||||
| <reference refid="path" torefid="newpath" /> | <reference refid="path" torefid="newpath" /> | ||||
| </ant> | </ant> | ||||
| </target> | </target> | ||||
| @@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs; | |||||
| import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.ProjectComponent; | |||||
| import org.apache.tools.ant.BuildListener; | import org.apache.tools.ant.BuildListener; | ||||
| import org.apache.tools.ant.DefaultLogger; | import org.apache.tools.ant.DefaultLogger; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| @@ -65,6 +66,7 @@ import java.io.File; | |||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.lang.reflect.Method; | |||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| @@ -105,6 +107,9 @@ public class Ant extends Task { | |||||
| /** should we inherit properties from the parent ? */ | /** should we inherit properties from the parent ? */ | ||||
| private boolean inheritAll = true; | private boolean inheritAll = true; | ||||
| /** should we inherit references from the parent ? */ | |||||
| private boolean inheritRefs = false; | |||||
| /** 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(); | ||||
| @@ -123,6 +128,15 @@ public class Ant extends Task { | |||||
| inheritAll = value; | inheritAll = value; | ||||
| } | } | ||||
| /** | |||||
| * If true, inherit all references from parent Project | |||||
| * If false, inherit only those defined | |||||
| * inside the ant call itself | |||||
| */ | |||||
| public void setInheritRefs(boolean value) { | |||||
| inheritRefs = value; | |||||
| } | |||||
| public void init() { | public void init() { | ||||
| newProject = new Project(); | newProject = new Project(); | ||||
| newProject.setJavaVersionProperty(); | newProject.setJavaVersionProperty(); | ||||
| @@ -335,21 +349,64 @@ public class Ant extends Task { | |||||
| if (toRefid == null) { | if (toRefid == null) { | ||||
| toRefid = refid; | toRefid = refid; | ||||
| } | } | ||||
| newProject.addReference(toRefid, o); | |||||
| copyReference(refid, toRefid); | |||||
| } | } | ||||
| } | } | ||||
| // Now add all references that are not defined in the | // Now add all references that are not defined in the | ||||
| // subproject, if inheritAll is true | |||||
| if (inheritAll) { | |||||
| // subproject, if inheritRefs is true | |||||
| if (inheritRefs) { | |||||
| for(e = thisReferences.keys(); e.hasMoreElements();) { | for(e = thisReferences.keys(); e.hasMoreElements();) { | ||||
| String key = (String)e.nextElement(); | String key = (String)e.nextElement(); | ||||
| if (newReferences.containsKey(key)) { | if (newReferences.containsKey(key)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| newProject.addReference(key, thisReferences.get(key)); | |||||
| copyReference(key, key); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 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. | |||||
| * | |||||
| * <p>If we cannot clone it, copy the referenced object itself and | |||||
| * keep our fingers crossed.</p> | |||||
| */ | |||||
| private void copyReference(String oldKey, String newKey) { | |||||
| Object orig = project.getReference(oldKey); | |||||
| Class c = orig.getClass(); | |||||
| Object copy = orig; | |||||
| try { | |||||
| Method cloneM = c.getMethod("clone", new Class[0]); | |||||
| if (cloneM != null) { | |||||
| copy = cloneM.invoke(orig, new Object[0]); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| // not Clonable | |||||
| } | |||||
| if (copy instanceof ProjectComponent) { | |||||
| ((ProjectComponent) copy).setProject(newProject); | |||||
| } else { | |||||
| try { | |||||
| Method setProjectM = | |||||
| c.getMethod( "setProject", new Class[] {Project.class}); | |||||
| if(setProjectM != null) { | |||||
| setProjectM.invoke(copy, new Object[] {newProject}); | |||||
| } | |||||
| } catch (NoSuchMethodException e) { | |||||
| // ignore this if the class being referenced does not have | |||||
| // a set project method. | |||||
| } catch(Exception e2) { | |||||
| String msg = "Error setting new project instance for reference with id " | |||||
| + oldKey; | |||||
| throw new BuildException(msg, e2, location); | |||||
| } | } | ||||
| } | } | ||||
| newProject.addReference(newKey, copy); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -158,7 +158,8 @@ public class AntTest extends BuildFileTest { | |||||
| } | } | ||||
| public void testReferenceInheritance() { | public void testReferenceInheritance() { | ||||
| Path p = new Path(project); | |||||
| Path p = Path.systemClasspath; | |||||
| p.setProject(project); | |||||
| project.addReference("path", p); | project.addReference("path", p); | ||||
| project.addReference("no-override", p); | project.addReference("no-override", p); | ||||
| testReference("testInherit", new String[] {"path", "path"}, | testReference("testInherit", new String[] {"path", "path"}, | ||||
| @@ -172,7 +173,8 @@ public class AntTest extends BuildFileTest { | |||||
| } | } | ||||
| public void testReferenceNoInheritance() { | public void testReferenceNoInheritance() { | ||||
| Path p = new Path(project); | |||||
| Path p = Path.systemClasspath; | |||||
| p.setProject(project); | |||||
| project.addReference("path", p); | project.addReference("path", p); | ||||
| project.addReference("no-override", p); | project.addReference("no-override", p); | ||||
| testReference("testNoInherit", new String[] {"path", "path"}, | testReference("testNoInherit", new String[] {"path", "path"}, | ||||
| @@ -188,7 +190,8 @@ public class AntTest extends BuildFileTest { | |||||
| } | } | ||||
| public void testReferenceRename() { | public void testReferenceRename() { | ||||
| Path p = new Path(project); | |||||
| Path p = Path.systemClasspath; | |||||
| p.setProject(project); | |||||
| project.addReference("path", p); | project.addReference("path", p); | ||||
| testReference("testRename", new String[] {"path", "path"}, | testReference("testRename", new String[] {"path", "path"}, | ||||
| new boolean[] {true, false}, p); | new boolean[] {true, false}, p); | ||||
| @@ -266,9 +269,37 @@ public class AntTest extends BuildFileTest { | |||||
| public void targetStarted(BuildEvent event) { | public void targetStarted(BuildEvent event) { | ||||
| if (error == null) { | if (error == null) { | ||||
| try { | try { | ||||
| assertEquals("Call "+calls+" refid=\'"+keys[calls]+"\'", | |||||
| expectSame[calls], | |||||
| event.getProject().getReferences().get(keys[calls++]) == value); | |||||
| String msg = | |||||
| "Call " + calls + " refid=\'" + keys[calls] + "\'"; | |||||
| if (value == null) { | |||||
| Object o = event.getProject().getReference(keys[calls]); | |||||
| if (expectSame[calls++]) { | |||||
| assertNull(msg, o); | |||||
| } else { | |||||
| assertNotNull(msg, o); | |||||
| } | |||||
| } else { | |||||
| // a rather convoluted equals() test | |||||
| Path expect = (Path) value; | |||||
| Path received = (Path) event.getProject().getReference(keys[calls]); | |||||
| boolean shouldBeEqual = expectSame[calls++]; | |||||
| if (received == null) { | |||||
| assertTrue(msg, !shouldBeEqual); | |||||
| } else { | |||||
| String[] l1 = expect.list(); | |||||
| String[] l2 = received.list(); | |||||
| if (l1.length == l2.length) { | |||||
| for (int i=0; i<l1.length; i++) { | |||||
| if (!l1[i].equals(l2[i])) { | |||||
| assertTrue(msg, !shouldBeEqual); | |||||
| } | |||||
| } | |||||
| assertTrue(msg, shouldBeEqual); | |||||
| } else { | |||||
| assertTrue(msg, !shouldBeEqual); | |||||
| } | |||||
| } | |||||
| } | |||||
| } catch (AssertionFailedError e) { | } catch (AssertionFailedError e) { | ||||
| error = e; | error = e; | ||||
| } | } | ||||