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
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
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
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>
<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>
</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>
</tr>
</table>
@@ -82,7 +89,7 @@ existing references in the new project.</p>
<h4>property</h4>
<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,
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>

<pre>
&lt;ant antfile=&quot;subbuild.xml&quot; /&gt;
&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;true&quot; /&gt;
</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>
<code>path2</code> available in the subbuild.</p>

<pre>
&lt;ant antfile=&quot;subbuild.xml&quot; inheritall=&quot;true&quot; /&gt;
&lt;ant antfile=&quot;subbuild.xml&quot; /&gt;
</pre>

<p>as well as</p>

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

<p>will neither override <code>path1</code> nor copy
<code>path2</code>.</p>

<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;/ant&gt;
</pre>
@@ -201,7 +210,7 @@ a <code>&lt;path&gt;</code> with the id <code>path1</code>, but
<code>path1</code>.</p>

<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;/ant&gt;
</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
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>

<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>
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
@@ -53,6 +60,29 @@ will be fixed and not overridable in the init task -or indeed in the &quot;doSom
<h4>param</h4>
<p>Specifies the properties to set before running the specified target. See <a
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>
<pre>
&lt;target name=&quot;default&quot;&gt;
@@ -66,6 +96,16 @@ href="property.html">property</a> for usage guidelines.</p>
&lt;/target&gt;
</pre>
<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
Reserved.</p>



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

@@ -54,15 +54,15 @@
</target>

<target name="testInherit">
<ant antfile="ant/references.xml" inheritAll="true" target="dummy" />
<ant antfile="ant/references.xml" inheritRefs="true" target="dummy" />
</target>

<target name="testNoInherit">
<ant antfile="ant/references.xml" inheritAll="false" target="dummy" />
<ant antfile="ant/references.xml" inheritRefs="false" target="dummy" />
</target>

<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" />
</ant>
</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.Project;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.BuildException;
@@ -65,6 +66,7 @@ import java.io.File;
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
@@ -105,6 +107,9 @@ public class Ant extends Task {
/** should we inherit properties from the parent ? */
private boolean inheritAll = true;
/** should we inherit references from the parent ? */
private boolean inheritRefs = false;
/** the properties to pass to the new project */
private Vector properties = new Vector();
@@ -123,6 +128,15 @@ public class Ant extends Task {
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() {
newProject = new Project();
newProject.setJavaVersionProperty();
@@ -335,21 +349,64 @@ public class Ant extends Task {
if (toRefid == null) {
toRefid = refid;
}
newProject.addReference(toRefid, o);
copyReference(refid, toRefid);
}
}

// 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();) {
String key = (String)e.nextElement();
if (newReferences.containsKey(key)) {
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() {
Path p = new Path(project);
Path p = Path.systemClasspath;
p.setProject(project);
project.addReference("path", p);
project.addReference("no-override", p);
testReference("testInherit", new String[] {"path", "path"},
@@ -172,7 +173,8 @@ public class AntTest extends BuildFileTest {
}

public void testReferenceNoInheritance() {
Path p = new Path(project);
Path p = Path.systemClasspath;
p.setProject(project);
project.addReference("path", p);
project.addReference("no-override", p);
testReference("testNoInherit", new String[] {"path", "path"},
@@ -188,7 +190,8 @@ public class AntTest extends BuildFileTest {
}

public void testReferenceRename() {
Path p = new Path(project);
Path p = Path.systemClasspath;
p.setProject(project);
project.addReference("path", p);
testReference("testRename", new String[] {"path", "path"},
new boolean[] {true, false}, p);
@@ -266,9 +269,37 @@ public class AntTest extends BuildFileTest {
public void targetStarted(BuildEvent event) {
if (error == null) {
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) {
error = e;
}


Loading…
Cancel
Save