Browse Source

Add a new inheritRefs attribute to <ant> with a default value of false

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-ffa450edef68
master
Stefan Bodewig 23 years ago
parent
commit
3745d5dc70
6 changed files with 172 additions and 35 deletions
  1. +3
    -3
      WHATSNEW
  2. +28
    -19
      docs/manual/CoreTasks/ant.html
  3. +40
    -0
      docs/manual/CoreTasks/antcall.html
  4. +3
    -3
      src/etc/testcases/taskdefs/ant.xml
  5. +61
    -4
      src/main/org/apache/tools/ant/taskdefs/Ant.java
  6. +37
    -6
      src/testcases/org/apache/tools/ant/taskdefs/AntTest.java

+ 3
- 3
WHATSNEW View File

@@ -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.


+ 28
- 19
docs/manual/CoreTasks/ant.html View File

@@ -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>&lt;reference&gt;</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>&lt;path&gt;</code> with the id <code>path1</code>, but
<code>path2</code> is not defined:</p> <code>path2</code> is not defined:</p>


<pre> <pre>
&lt;ant antfile=&quot;subbuild.xml&quot; /&gt;
&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;true&quot; /&gt;
</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>
&lt;ant antfile=&quot;subbuild.xml&quot; inheritall=&quot;true&quot; /&gt;
&lt;ant antfile=&quot;subbuild.xml&quot; /&gt;
</pre> </pre>


<p>as well as</p>

<pre> <pre>
&lt;ant antfile=&quot;subbuild.xml&quot; inheritall=&quot;false&quot; /&gt;
&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot; /&gt;
</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>
&lt;ant antfile=&quot;subbuild.xml&quot; inheritall=&quot;false&quot; &gt;
&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot; &gt;
&lt;reference refid=&quot;path1&quot; /&gt; &lt;reference refid=&quot;path1&quot; /&gt;
&lt;/ant&gt; &lt;/ant&gt;
</pre> </pre>
@@ -201,7 +210,7 @@ a <code>&lt;path&gt;</code> with the id <code>path1</code>, but
<code>path1</code>.</p> <code>path1</code>.</p>


<pre> <pre>
&lt;ant antfile=&quot;subbuild.xml&quot; inheritall=&quot;false&quot; &gt;
&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot; &gt;
&lt;reference refid=&quot;path1&quot; torefid=&quot;path2&quot; /&gt; &lt;reference refid=&quot;path1&quot; torefid=&quot;path2&quot; /&gt;
&lt;/ant&gt; &lt;/ant&gt;
</pre> </pre>


+ 40
- 0
docs/manual/CoreTasks/antcall.html View File

@@ -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>&lt;reference&gt;</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 &quot;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>
&lt;target name=&quot;default&quot;&gt; &lt;target name=&quot;default&quot;&gt;
@@ -66,6 +96,16 @@ href="property.html">property</a> for usage guidelines.</p>
&lt;/target&gt; &lt;/target&gt;
</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>
&lt;antcall ... &gt;
&lt;reference refid=&quot;path1&quot; torefid=&quot;path2&quot; /&gt;
&lt;/antcall&gt;
</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 &copy; 2000,2001 Apache Software Foundation. All rights <hr><p align="center">Copyright &copy; 2000,2001 Apache Software Foundation. All rights
Reserved.</p> Reserved.</p>




+ 3
- 3
src/etc/testcases/taskdefs/ant.xml View File

@@ -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>


+ 61
- 4
src/main/org/apache/tools/ant/taskdefs/Ant.java View File

@@ -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);
} }


/** /**


+ 37
- 6
src/testcases/org/apache/tools/ant/taskdefs/AntTest.java View File

@@ -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;
} }


Loading…
Cancel
Save