You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by David Markley <da...@hextris.com> on 2003/02/06 19:15:36 UTC

[PROPOSAL] ant task: rebuild and resultproperty attributes

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;