Attached is a patch that adds caching and failure handling to the Ant task. These features better support hierarchical build environments.
<ant dir="mylib" rebuild="false" resultproperty="my.failure"/> The rebuild attribute allows the user to specify whether or not the same Ant target will be invoked multiple times during a single Ant run. An example where this becomes useful is when multiple projects use the ant task to build a common library. If the projects are executed individually, they will always invoke the common library build. When placed in a hierarchical build and having the rebuild attribute set to false, the common library build will only be attempted once. The second new feature involved the ability to capture failures from the ant task. This behaves similarly to the failonerror and resultproperty found in the exec task. The difference being that the failonerror attribute is redundant. If the resultproperty is set to a non-empty string, failures are captured and placed in the resultproperty and the build continues. I've included the ability to have all ant tasks ignore failures, depending on whether or not the 'forcebuild' property is set. I know this would probably be the least likely to make it into the ant task, but it is very beneficial. Simply by setting the 'forcebuild' property, the entire hierarchical system is set to ignore build failures from ant task calls. In this case, the resultproperty does not need to be specified but will be set if it is. In either case, a MSG_ERR will be generated with the build exception information. The default values for these new attributes result in the normal, current ant task behavior. For your review, ++David http://www.hextris.com/ Index: src/main/org/apache/tools/ant/taskdefs/Ant.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Ant.j ava,v retrieving revision 1.72 diff -u -r1.72 Ant.java --- src/main/org/apache/tools/ant/taskdefs/Ant.java 31 Jan 2003 07:57:41 -0000 1.72 +++ src/main/org/apache/tools/ant/taskdefs/Ant.java 6 Feb 2003 17:37:35 -0000 @@ -96,6 +96,18 @@ */ public class Ant extends Task { + /** the hashtable of targets that have already been invoked. */ + private static Hashtable built = new Hashtable(); + + /** + * If true, always build the target. Otherwise, check to + * see if the target and file have already been invoked. + */ + private boolean rebuild = true; + + /** the result property to be set on any build failure. */ + private String resultProperty = null; + /** the basedir where is executed the build file */ private File dir = null; @@ -146,6 +158,23 @@ } /** + * If true, invokes the Ant project, regardless of whether or not + * it has been previously invoked during the current build. + * Defaults to true. + */ + public void setRebuild(boolean value) { + rebuild = value; + } + + /** + * If set to a non-empty string, any build failures in the + * called project will be caught and placed in this property. + */ + public void setResultProperty(String resultProperty) { + this.resultProperty = resultProperty; + } + + /** * Creates a Project instance for the project to call. */ public void init() { @@ -339,6 +368,62 @@ * Do the execution. */ public void execute() throws BuildException { + + /* + * If rebuild is false, check to see if the target for the + * new project has already been invoked. If it has, don't + * invoke it again. + */ + if (! rebuild) { + File tmpDir = dir; + String tmpAntFile = antFile; + String tmpTarget = target; + + if (null == tmpDir) { + tmpDir = getProject().getBaseDir(); + } + if (null == tmpTarget) { + tmpTarget = "[default]"; + } + if (tmpAntFile == null) { + tmpAntFile = "build.xml"; + } + File file = FileUtils.newFileUtils().resolveFile(tmpDir, tmpAntFile); + tmpAntFile = file.getAbsolutePath(); + String key = tmpAntFile+"###"+tmpTarget; + if (null == built.get(key)) { + built.put(key,""); + } else { + log("Already built "+tmpTarget+" target in "+tmpAntFile, Project.MSG_VERBOSE); + return; + } + } + /* + * If the resultProperty is null or empty and the forcebuild + * property is not set, execute the project and let any exception + * bubble up. Otherwise, catch the exception and put it in the + * resultProperty (if specified). + */ + if ((null == resultProperty || resultProperty.equals("")) && + null == getProject().getProperty("forcebuild")) { + executeProject(); + } else { + try { + executeProject(); + } catch (BuildException ex) { + String msg = ex.toString(); + if (null != resultProperty && !resultProperty.equals("")) { + getProject().setNewProperty(resultProperty, msg); + } + getProject().log(msg, Project.MSG_ERR); + } + } + } + + /** + * Perform the actual project execution. + */ + private void executeProject() throws BuildException { File savedDir = dir; String savedAntFile = antFile; String savedTarget = target;
