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 | |||
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 | |||
=========================================== | |||
@@ -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 | |||
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> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
@@ -60,15 +70,41 @@ setting of <i>inheritAll</i>. This allows you to parameterize your subprojects. | |||
<td align="center" valign="top">No</td> | |||
</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 align="center" valign="top">No</td> | |||
</tr> | |||
</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 | |||
attributes dir and inheritall, see the following table for | |||
@@ -119,6 +155,60 @@ details:</p> | |||
<property name="output.type" value="html"/> | |||
</ant> | |||
</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> | |||
<p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | |||
Reserved.</p> | |||
@@ -53,4 +53,18 @@ | |||
<ant antfile="ant/ant.xml" target="callback" inheritAll="false" /> | |||
</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> |
@@ -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 */ | |||
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; } | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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 <nico@seessle.de> | |||
* @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 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; | |||
} | |||
} | |||
} |