Browse Source

changes in subant mainly concerning iterations done inside a dirset

new attributes ignoremissingbuildfiles and genericantfile
genericantfile allows to run the same build file with different base dirs
it is not compulsory any more to set the attribute target to quote quote to run the default target
PR: 18715
Submitted by: Andreas Ames (Andreas dot Ames at tenovis dot com)


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274600 13f79535-47bb-0310-9956-ffa450edef68
master
Antoine Levy-Lambert 22 years ago
parent
commit
ea42c65bec
8 changed files with 391 additions and 18 deletions
  1. +64
    -3
      docs/manual/CoreTasks/subant.html
  2. +26
    -1
      proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml
  3. +24
    -0
      src/etc/testcases/taskdefs/subant.xml
  4. +5
    -0
      src/etc/testcases/taskdefs/subant/genericsubant.xml
  5. +5
    -0
      src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml
  6. +5
    -0
      src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml
  7. +92
    -14
      src/main/org/apache/tools/ant/taskdefs/SubAnt.java
  8. +170
    -0
      src/testcases/org/apache/tools/ant/taskdefs/SubAntTest.java

+ 64
- 3
docs/manual/CoreTasks/subant.html View File

@@ -54,6 +54,31 @@
Calls a given target for all defined sub-builds. This is an extension
of ant for bulk project execution.
</p>
<table border="0" cellspacing="0" cellpadding="2" width="100%">
<!-- Subsection heading -->
<tr><td bgcolor="#828DA6">
<font color="#ffffff" face="arial,helvetica.sanserif">
<a name="Use with directories">
<strong>Use with directories</strong></a></font>
</td></tr>
<!-- Subsection body -->
<tr><td>
<p>
subant can be used with directory sets to execute a build from different directories.
2 different options are offered :
</p>
<ul>
<li>
to run the same build file <code>/somepath/otherpath/mybuild.xml</code>
with different base directories, use the genericantfile attribute
</li>
<li>if you want to run <code>directory1/mybuild.xml</code>, <code>directory2/mybuild.xml</code>, <code>....</code>,
use the antfile attribute. The subant task does not set the base directory for you in this case.<br/> because you can specify it in each build file.
</li>
</ul>

</td></tr>
</table>

</blockquote></td></tr>

@@ -93,12 +118,12 @@
<font color="#000000" size="-1" face="arial,helvetica,sanserif">antfile</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the default build file name to append to directory names found in the build path -default "build.xml"</font>
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Build file name, to use in conjunction with directories.<br/> Defaults to "build.xml".<br/> If <code>genericantfile</code> is set, this attribute is ignored.</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left" rowspan="7">
<td bgcolor="#eeeeee" valign="top" align="left" rowspan="10">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
</td>
</tr>
@@ -139,6 +164,30 @@
</td>
</tr>
<!-- Attribute -->
<tr>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">genericantfile</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Build file path, to use in conjunction with directories.<br/> Use <code>genericantfile</code>, in order to run the same build file with different basedirs.<br/> If this attribute is set, <code>antfile</code> is ignored.</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
</td>
</tr>
<!-- Attribute -->
<tr>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">ignoremissingbuildfile</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets whether to continue or fail with a build exception if the build file is missing, false by default.</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
</td>
</tr>
<!-- Attribute -->
<tr>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">inheritall</font>
@@ -163,6 +212,18 @@
</td>
</tr>
<!-- Attribute -->
<tr>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">output</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">Corresponds to <code>&lt;ant&gt;</code>'s <code>output</code> attribute.</font>
</td>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
</td>
</tr>
<!-- Attribute -->
<tr>
<td bgcolor="#eeeeee" valign="top" align="left">
<font color="#000000" size="-1" face="arial,helvetica,sanserif">target</font>
@@ -204,7 +265,7 @@
Adds a directory set to the implicit build path. <p> <em>Note that the directories will be added to the build path in no particular order, so if order is significant, one should use a file list instead!</em>
<short-description><![CDATA[Adds a directory set to the implicit build path.]]></short-description>
<description>
<![CDATA[Adds a directory set to the implicit build path. <p> <em>Note that the directories will be added to the build path in no particular o]]><![CDATA[rder, so if order is significant, one should use a file list instead!</em>]]>
<![CDATA[Adds a directory set to the implicit build path. <p> <em>Note that the directories will be added to the build path in no particular order, so if order is significant, one should use a file list instead!</em>]]>
</description>

</blockquote></td></tr>


+ 26
- 1
proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml View File

@@ -8,7 +8,22 @@
Calls a given target for all defined sub-builds. This is an extension
of ant for bulk project execution.
</p>
</description>
<subsection name="Use with directories">
<p>
subant can be used with directory sets to execute a build from different directories.
2 different options are offered :
</p>
<ul>
<li>
to run the same build file <code>/somepath/otherpath/mybuild.xml</code>
with different base directories, use the genericantfile attribute
</li>
<li>if you want to run <code>directory1/mybuild.xml</code>, <code>directory2/mybuild.xml</code>, <code>....</code>,
use the antfile attribute. The subant task does not set the base directory for you in this case.<br/> because you can specify it in each build file.
</li>
</ul>
</subsection>
</description>
<section anchor="examples" name="Example">
<pre>
&lt;project name="subant" default="subant1"&gt;
@@ -41,5 +56,15 @@
where a file called build.xml can be found.
All properties whose name starts with &quot;foo&quot; are passed, their names are changed to start with &quot;bar&quot; instead
</p>
<pre>
&lt;subant target="compile" genericantfile="/opt/project/build1.xml"&gt;
&lt;dirset dir="." includes="projects*"/&gt;
&lt;/subant&gt;
</pre>
<p>
assuming the subdirs of the project dir are called projects1, projects2, projects3
this snippet will execute the compile target of /opt/project/build1.xml,
setting the basedir to projects1, projects2, projects3
</p>
</section>
</external>

+ 24
- 0
src/etc/testcases/taskdefs/subant.xml View File

@@ -0,0 +1,24 @@
<?xml version="1.0"?>

<project name="subant-test" basedir="." default="testgenericantfile">
<target name="testnodirs" depends="cleanup">
<subant genericantfile="subant/genericsubant.xml">
<dirset dir="." includes="subant-test*"/>
</subant>

</target>
<target name="testgenericantfile">
<subant genericantfile="subant/genericsubant.xml">
<dirset dir="subant" includes="subant-test*"/>
</subant>
</target>
<target name="testantfile">
<subant antfile="mysubant.xml">
<dirset dir="." includes="subant/subant-test*"/>
</subant>

</target>
<target name="cleanup">
<!-- nothing to do -->
</target>
</project>

+ 5
- 0
src/etc/testcases/taskdefs/subant/genericsubant.xml View File

@@ -0,0 +1,5 @@
<project name="genericsubant" basedir=".." default="mysubant">
<target name="mysubant">
<echo message="${basedir}"/>
</target>
</project>

+ 5
- 0
src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml View File

@@ -0,0 +1,5 @@
<project name="mysubant" basedir="." default="mysubant">
<target name="mysubant">
<echo message="${basedir}"/>
</target>
</project>

+ 5
- 0
src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml View File

@@ -0,0 +1,5 @@
<project name="subant" basedir=".." default="mysubant">
<target name="mysubant">
<echo message="${basedir}"/>
</target>
</project>

+ 92
- 14
src/main/org/apache/tools/ant/taskdefs/SubAnt.java View File

@@ -80,9 +80,25 @@ import org.apache.tools.ant.taskdefs.Property;
* <p>
* Calls a given target for all defined sub-builds. This is an extension
* of ant for bulk project execution.
*
* <p>
* <h2> Use with directories </h2>
* <p>
* subant can be used with directory sets to execute a build from different directories.
* 2 different options are offered
* </p>
* <ul>
* <li>
* run the same build file /somepath/otherpath/mybuild.xml
* with different base directories use the genericantfile attribute
* </li>
* <li>if you want to run directory1/build.xml, directory2/build.xml, ....
* use the antfile attribute. The base directory does not get set by the subant task in this case,
* because you can specify it in each build file.
* </li>
* </ul>
* @since Ant1.6
* @author <a href="mailto:ddevienne@lgc.com">Dominique Devienne</a>
* @author <A HREF="mailto:andreas.ames@tenovis.com">Andreas Ames</A>
* @ant.task name="subant" category="control"
*/
public class SubAnt
@@ -92,14 +108,16 @@ public class SubAnt

private String target = null;
private String antfile = "build.xml";
private File genericantfile = null;
private boolean inheritAll = false;
private boolean inheritRefs = false;
private boolean failOnError = true;
private boolean ignoreMissingBuildFile = false;
private String output = null;

private Vector properties = new Vector();
private Vector references = new Vector();
private Vector propertySets = new Vector();

/**
* Runs the various sub-builds.
*/
@@ -122,11 +140,27 @@ public class SubAnt
}
*/
for (int i=0; i<count; ++i) {
boolean doit=true;
File directory=null;
File file = new File(filenames[i]);
if (file.isDirectory()) {
file = new File(file, antfile);
if (genericantfile != null) {
directory = file;
file = genericantfile;
}
else {
file = new File(file, antfile);
boolean fileFound=file.exists();
if(ignoreMissingBuildFile && !fileFound) {
log("Build file '" + file + "' not found.", Project.MSG_INFO);
doit=false;
}

}
}
if (doit) {
execute(file, directory);
}
execute(file);
}
}

@@ -134,12 +168,13 @@ public class SubAnt
* Runs the given target on the provided build file.
*
* @param file the build file to execute
* @param directory the directory of the current iteration
* @throws BuildException is the file cannot be found, read, is
* a directory, or the target called failed, but only if
* <code>failOnError</code> is <code>true</code>. Otherwise,
* a warning log message is simply output.
*/
private void execute(File file)
private void execute(File file, File directory)
throws BuildException {
if (!file.exists() || file.isDirectory() || !file.canRead()) {
String msg = "Invalid file: "+file;
@@ -150,7 +185,7 @@ public class SubAnt
return;
}

Ant ant = createAntTask();
Ant ant = createAntTask(directory);
String antfilename = null;
try {
antfilename = file.getCanonicalPath();
@@ -172,8 +207,9 @@ public class SubAnt
}

/**
* Sets the default build file name to append to directory
* names found in the build path -default "build.xml"
* Build file name, to use in conjunction with directories.<br/>
* Defaults to "build.xml".<br/>
* If <code>genericantfile</code> is set, this attribute is ignored.
*
* @param antfile the short build file name. Defaults to "build.xml".
*/
@@ -181,6 +217,17 @@ public class SubAnt
this.antfile = antfile;
}

/**
* Build file path, to use in conjunction with directories.<br/>
* Use <code>genericantfile</code>, in order to run the same build file with different basedirs.<br/>
* If this attribute is set, <code>antfile</code> is ignored.
*
* @param afile (path of the generic ant file, absolute or relative to project base directory)
* */
public void setGenericAntfile(File afile) {
this.genericantfile=afile;
}

/**
* Sets whether to fail with a build exception on error, or go on.
*
@@ -190,6 +237,16 @@ public class SubAnt
this.failOnError = failOnError;
}

/**
* Sets whether to continue or fail with a build exception if the build
* file is missing, false by default.
*
* @param ignoreMissingBuildFile the new value for this boolean flag.
*/
public void setIgnoreMissingBuildFile(boolean ignoreMissingBuildFile) {
this.ignoreMissingBuildFile = ignoreMissingBuildFile;
}

/**
* The target to call on the different sub-builds. Set to "" to execute
* the default target.
@@ -200,6 +257,16 @@ public class SubAnt
this.target = target;
}

/**
* Corresponds to <code>&lt;ant&gt;</code>'s
* <code>output</code> attribute.
*
* @param s the filename to write the output to.
*/
public void setOutput(String s) {
this.output = s;
}

/**
* Corresponds to <code>&lt;ant&gt;</code>'s
* <code>inheritall</code> attribute.
@@ -288,13 +355,13 @@ public class SubAnt

/**
* Set the buildpath to be used to find sub-projects.
*
*
* @param s an Ant Path object containing the buildpath.
*/
public void setBuildpath(Path s) {
getBuildpath().append(s);
}
/**
* Creates a nested build path, and add it to the implicit build path.
*
@@ -339,26 +406,37 @@ public class SubAnt
/**
* Creates the &lt;ant&gt; task configured to run a specific target.
*
* @param directory : if not null the directory where the build should run
*
* @return the ant task, configured with the explicit properties and
* references necessary to run the sub-build.
*/
private Ant createAntTask() {
private Ant createAntTask(File directory) {
Ant ant = (Ant) getProject().createTask("ant");
ant.setOwningTarget(getOwningTarget());
ant.init();
if(target.length()>0) {
if(target != null && target.length()>0) {
ant.setTarget(target);
}


if (output != null) {
ant.setOutput(output);
}

if (directory != null) {
ant.setDir(directory);
}

ant.setInheritAll(inheritAll);
for (Enumeration i = properties.elements(); i.hasMoreElements();) {
copyProperty(ant.createProperty(), (Property) i.nextElement());
}
for (Enumeration i = propertySets.elements(); i.hasMoreElements();) {
ant.addPropertyset((PropertySet) i.nextElement());
}
ant.setInheritRefs(inheritRefs);
for (Enumeration i = references.elements(); i.hasMoreElements();) {
ant.addReference((Ant.Reference) i.nextElement());


+ 170
- 0
src/testcases/org/apache/tools/ant/taskdefs/SubAntTest.java View File

@@ -0,0 +1,170 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.tools.ant.taskdefs;

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.input.InputHandler;
import org.apache.tools.ant.types.Path;

/**
* @author Antoine Levy-Lambert
* @version $Revision$
*/
public class SubAntTest extends BuildFileTest {

public SubAntTest(String name) {
super(name);
}

public void setUp() {
configureProject("src/etc/testcases/taskdefs/subant.xml");
}

public void tearDown() {
executeTarget("cleanup");
}

public void testnodirs() {
project.executeTarget("testnodirs");
expectLog("testnodirs", "No sub-builds to iterate on");
}

// target must be specified
public void testgenericantfile() {
File dir1 = project.resolveFile(".");
File dir2 = project.resolveFile("subant/subant-test1");
File dir3 = project.resolveFile("subant/subant-test2");

testBaseDirs("testgenericantfile",
new String[] { dir1.getAbsolutePath(),
dir2.getAbsolutePath(),
dir3.getAbsolutePath()

});
}

public void testantfile() {
File dir1 = project.resolveFile(".");
// basedir of subant/subant-test1/subant.xml is ..
// therefore we expect here the subant/subant-test1 subdirectory
File dir2 = project.resolveFile("subant/subant-test1");
// basedir of subant/subant-test2/subant.xml is ..
// therefore we expect here the subant subdirectory
File dir3 = project.resolveFile("subant");

testBaseDirs("testantfile",
new String[] { dir1.getAbsolutePath(),
dir2.getAbsolutePath(),
dir3.getAbsolutePath()

});

}

protected void testBaseDirs(String target, String[] dirs) {
SubAntTest.BasedirChecker bc = new SubAntTest.BasedirChecker(dirs);
project.addBuildListener(bc);
executeTarget(target);
AssertionFailedError ae = bc.getError();
if (ae != null) {
throw ae;
}
project.removeBuildListener(bc);
}

private class BasedirChecker implements BuildListener {
private String[] expectedBasedirs;
private int calls = 0;
private AssertionFailedError error;

BasedirChecker(String[] dirs) {
expectedBasedirs = dirs;
}

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 (event.getTarget().getName().equals("")) {
return;
}
if (error == null) {
try {
assertEquals(expectedBasedirs[calls++],
event.getProject().getBaseDir().getAbsolutePath());
} catch (AssertionFailedError e) {
error = e;
}
}
}

AssertionFailedError getError() {
return error;
}

}


}

Loading…
Cancel
Save