diff --git a/docs/manual/CoreTasks/subant.html b/docs/manual/CoreTasks/subant.html index 4ae44af77..b0829d495 100644 --- a/docs/manual/CoreTasks/subant.html +++ b/docs/manual/CoreTasks/subant.html @@ -54,6 +54,31 @@ Calls a given target for all defined sub-builds. This is an extension of ant for bulk project execution.

+ + + + + +
+ + + Use with directories +
+

+ subant can be used with directory sets to execute a build from different directories. + 2 different options are offered : +

+
    +
  • + to run the same build file /somepath/otherpath/mybuild.xml + with different base directories, use the genericantfile attribute +
  • +
  • if you want to run directory1/mybuild.xml, directory2/mybuild.xml, ...., + use the antfile attribute. The subant task does not set the base directory for you in this case.
    because you can specify it in each build file. +
  • +
+ +
@@ -93,12 +118,12 @@ antfile - 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.
Defaults to "build.xml".
If genericantfile is set, this attribute is ignored.
String - + Optional @@ -139,6 +164,30 @@ + + + genericantfile + + + Build file path, to use in conjunction with directories.
Use genericantfile, in order to run the same build file with different basedirs.
If this attribute is set, antfile is ignored.
+ + + File + + + + + + ignoremissingbuildfile + + + Sets whether to continue or fail with a build exception if the build file is missing, false by default. + + + boolean + + + inheritall @@ -163,6 +212,18 @@ + + + output + + + Corresponds to <ant>'s output attribute. + + + String + + + target @@ -204,7 +265,7 @@ Adds a directory set to the implicit build path.

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! - Note that the directories will be added to the build path in no particular o]]>]]> + 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!]]> diff --git a/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml b/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml index 5cdf9561a..f1326c78c 100644 --- a/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml +++ b/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml @@ -8,7 +8,22 @@ Calls a given target for all defined sub-builds. This is an extension of ant for bulk project execution.

- + +

+ subant can be used with directory sets to execute a build from different directories. + 2 different options are offered : +

+ +
+
         <project name="subant" default="subant1">
@@ -41,5 +56,15 @@
             where a file called build.xml can be found.
             All properties whose name starts with "foo" are passed, their names are changed to start with "bar" instead
         

+
+          <subant target="compile" genericantfile="/opt/project/build1.xml">
+             <dirset dir="." includes="projects*"/>
+          </subant>
+        
+

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

\ No newline at end of file diff --git a/src/etc/testcases/taskdefs/subant.xml b/src/etc/testcases/taskdefs/subant.xml new file mode 100644 index 000000000..e2c00c01a --- /dev/null +++ b/src/etc/testcases/taskdefs/subant.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/etc/testcases/taskdefs/subant/genericsubant.xml b/src/etc/testcases/taskdefs/subant/genericsubant.xml new file mode 100644 index 000000000..a121a7fa7 --- /dev/null +++ b/src/etc/testcases/taskdefs/subant/genericsubant.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml b/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml new file mode 100644 index 000000000..6c5d17d4d --- /dev/null +++ b/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml b/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml new file mode 100644 index 000000000..055267426 --- /dev/null +++ b/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/taskdefs/SubAnt.java b/src/main/org/apache/tools/ant/taskdefs/SubAnt.java index 292c0b18d..d283f1709 100644 --- a/src/main/org/apache/tools/ant/taskdefs/SubAnt.java +++ b/src/main/org/apache/tools/ant/taskdefs/SubAnt.java @@ -80,9 +80,25 @@ import org.apache.tools.ant.taskdefs.Property; *

* Calls a given target for all defined sub-builds. This is an extension * of ant for bulk project execution. - * + *

+ *

Use with directories

+ *

+ * subant can be used with directory sets to execute a build from different directories. + * 2 different options are offered + *

+ * * @since Ant1.6 * @author Dominique Devienne + * @author Andreas Ames * @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; ifailOnError is true. 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.
+ * Defaults to "build.xml".
+ * If genericantfile 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.
+ * Use genericantfile, in order to run the same build file with different basedirs.
+ * If this attribute is set, antfile 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 <ant>'s + * output attribute. + * + * @param s the filename to write the output to. + */ + public void setOutput(String s) { + this.output = s; + } + /** * Corresponds to <ant>'s * inheritall 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 <ant> 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()); diff --git a/src/testcases/org/apache/tools/ant/taskdefs/SubAntTest.java b/src/testcases/org/apache/tools/ant/taskdefs/SubAntTest.java new file mode 100644 index 000000000..9cb4c7091 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/SubAntTest.java @@ -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 + * . + */ + +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; + } + + } + + +}