diff --git a/docs/manual/running.html b/docs/manual/running.html index 9e11288d0..4a0a770ff 100644 --- a/docs/manual/running.html +++ b/docs/manual/running.html @@ -95,6 +95,8 @@ Options: -file <file> '' -f <file> '' -D<property>=<value> use value for given property + -keep-going, -k execute all targets that do not depend + on failed target(s) -propertyfile <name> load all properties from file with -D properties taking precedence -inputhandler <class> the class which will handle input requests diff --git a/src/main/org/apache/tools/ant/Main.java b/src/main/org/apache/tools/ant/Main.java index 30deedd9c..48d0d911f 100644 --- a/src/main/org/apache/tools/ant/Main.java +++ b/src/main/org/apache/tools/ant/Main.java @@ -113,6 +113,9 @@ public class Main implements AntMain { /** Indicates whether this build is to support interactive input */ private boolean allowInput = true; + /** keep going mode */ + private boolean keepGoingMode = false; + /** * The Ant logger class. There may be only one logger. It will have * the right to use the 'out' PrintStream. The class must implements the @@ -422,6 +425,8 @@ public class Main implements AntMain { "using the -propertyfile argument"; throw new BuildException(msg); } + } else if (arg.equals("-k") || arg.equals("-keep-going")) { + keepGoingMode = true; } else if (arg.startsWith("-")) { // we don't have any more args to recognize! String msg = "Unknown argument: " + arg; @@ -634,6 +639,8 @@ public class Main implements AntMain { project.setUserProperty("ant.file", buildFile.getAbsolutePath()); + project.setKeepGoingMode(keepGoingMode); + ProjectHelper.configureProject(project, buildFile); if (projectHelp) { @@ -800,6 +807,8 @@ public class Main implements AntMain { msg.append(" -file ''" + lSep); msg.append(" -f ''" + lSep); msg.append(" -D= use value for given property" + lSep); + msg.append(" -keep-going, -k execute all targets that do not depend" + lSep); + msg.append(" on failed target(s)" + lSep); msg.append(" -propertyfile load all properties from file with -D" + lSep); msg.append(" properties taking precedence" + lSep); msg.append(" -inputhandler the class which will handle input requests" + lSep); diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java index 53f9332f5..f80a4b1e9 100644 --- a/src/main/org/apache/tools/ant/Project.java +++ b/src/main/org/apache/tools/ant/Project.java @@ -65,6 +65,8 @@ import java.util.Hashtable; import java.util.Properties; import java.util.Stack; import java.util.Vector; +import java.util.Set; +import java.util.HashSet; import org.apache.tools.ant.input.DefaultInputHandler; import org.apache.tools.ant.input.InputHandler; import org.apache.tools.ant.types.FilterSet; @@ -207,6 +209,11 @@ public class Project { */ private InputStream defaultInputStream = null; + /** + * Keep going flag + */ + private boolean keepGoingMode = false; + /** * Sets the input handler * @@ -272,6 +279,7 @@ public class Project { public void initSubProject(Project subProject) { ComponentHelper.getComponentHelper(subProject) .initSubProject(ComponentHelper.getComponentHelper(this)); + subProject.setKeepGoingMode(this.isKeepGoingMode()); } /** @@ -778,6 +786,26 @@ public class Project { return baseDir; } + /** + * Sets "keep-going" mode. In this mode ANT will try to execute + * as many targets as possible. All targets that do not depend + * on failed target(s) will be executed. + * @param keepGoingMode "keep-going" mode + * @since Ant 1.6 + */ + public void setKeepGoingMode(boolean keepGoingMode) { + this.keepGoingMode = keepGoingMode; + } + + /** + * Returns the keep-going mode. + * @return "keep-going" mode + * @since Ant 1.6 + */ + public boolean isKeepGoingMode() { + return this.keepGoingMode; + } + /** * Returns the version of Java this class is running under. * @return the version of Java as a String, e.g. "1.1" @@ -1174,13 +1202,70 @@ public class Project { // graph. Vector sortedTargets = topoSort(targetName, targets); - int curidx = 0; - Target curtarget; - - do { - curtarget = (Target) sortedTargets.elementAt(curidx++); - curtarget.performTasks(); - } while (!curtarget.getName().equals(targetName)); + Set succeededTargets = new HashSet(); + BuildException buildException = null; // first build exception + for (Enumeration iter = sortedTargets.elements(); + iter.hasMoreElements();) { + Target curtarget = (Target) iter.nextElement(); + boolean canExecute = true; + for (Enumeration depIter = curtarget.getDependencies(); + depIter.hasMoreElements();) { + String dependencyName = ((String) depIter.nextElement()); + if (!succeededTargets.contains(dependencyName)) { + canExecute = false; + log(curtarget, + "Cannot execute '" + curtarget.getName() + "' - '" + + dependencyName + "' failed or was not executed.", + MSG_ERR); + break; + } + } + if (canExecute) { + Throwable thrownException = null; + try { + curtarget.performTasks(); + succeededTargets.add(curtarget.getName()); + } catch (RuntimeException ex) { + if (!(keepGoingMode)) { + throw ex; // throw further + } + thrownException = ex; + } catch (Throwable ex) { + if (!(keepGoingMode)) { + throw new BuildException(ex); + } + thrownException = ex; + } + if (thrownException != null) { + if (thrownException instanceof BuildException) { + log(curtarget, + "Target '" + curtarget.getName() + + "' failed with message '" + + thrownException.getMessage() + "'.", MSG_ERR); + // only the first build exception is reported + if (buildException == null) { + buildException = (BuildException) thrownException; + } + } else { + log(curtarget, + "Target '" + curtarget.getName() + + "' failed with message '" + + thrownException.getMessage() + "'.", MSG_ERR); + thrownException.printStackTrace(System.err); + if (buildException == null) { + buildException = + new BuildException(thrownException); + } + } + } + } + if (curtarget.getName().equals(targetName)) { // old exit condition + break; + } + } + if (buildException != null) { + throw buildException; + } } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/SubAnt.java b/src/main/org/apache/tools/ant/taskdefs/SubAnt.java index 83ec721e0..82d59fa34 100644 --- a/src/main/org/apache/tools/ant/taskdefs/SubAnt.java +++ b/src/main/org/apache/tools/ant/taskdefs/SubAnt.java @@ -134,18 +134,57 @@ public class SubAnt target = getOwningTarget().getName(); } */ + BuildException buildException = null; for (int i = 0; i < count; ++i) { - File directory = null; - File file = new File(filenames[i]); - if (file.isDirectory()) { - if (genericantfile != null) { - directory = file; - file = genericantfile; + File file = null; + Throwable thrownException = null; + try { + File directory = null; + file = new File(filenames[i]); + if (file.isDirectory()) { + if (genericantfile != null) { + directory = file; + file = genericantfile; + } else { + file = new File(file, antfile); + } + } + execute(file, directory); + } catch (RuntimeException ex) { + if (!(getProject().isKeepGoingMode())) { + throw ex; // throw further + } + thrownException = ex; + } catch (Throwable ex) { + if (!(getProject().isKeepGoingMode())) { + throw new BuildException(ex); + } + thrownException = ex; + } + if (thrownException != null) { + if (thrownException instanceof BuildException) { + log("File '" + file + + "' failed with message '" + + thrownException.getMessage() + "'.", Project.MSG_ERR); + // only the first build exception is reported + if (buildException == null) { + buildException = (BuildException) thrownException; + } } else { - file = new File(file, antfile); + log("Target '" + file + + "' failed with message '" + + thrownException.getMessage() + "'.", Project.MSG_ERR); + thrownException.printStackTrace(System.err); + if (buildException == null) { + buildException = + new BuildException(thrownException); + } } } - execute(file, directory); + } + // check if one of the builds failed in keep going mode + if (buildException != null) { + throw buildException; } }