From cfcef50fba38a3e3f9e4c634ef1692698c0685a5 Mon Sep 17 00:00:00 2001 From: mharmer Date: Mon, 26 Nov 2018 17:45:17 -0800 Subject: [PATCH] Adding target failure support so that builds no longer report success in the event of a failure. Since Parallel-Ant can be executing two or more targets at the same time, the ParallelExecutor was updated to handle potentially multiple BuildExceptions being thrown (via the new notifiyException callback). In the case there are multiple BuildExceptions reported at the same time, these are collected into a single string and a single new BuildException is thrown with this content. Additionally, the ParallelExecutor will signal the executor to stop upon any BuildException occurring to stop the build as soon as possible. --- .../build/pant/DependencyGraphEntry.java | 3 ++ .../tools/build/pant/ParallelExecutor.java | 29 ++++++++++++++++++- .../build/pant/TargetExecutionNotifier.java | 3 ++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/codeaholics/tools/build/pant/DependencyGraphEntry.java b/src/main/java/org/codeaholics/tools/build/pant/DependencyGraphEntry.java index fd3b5c4..4720765 100644 --- a/src/main/java/org/codeaholics/tools/build/pant/DependencyGraphEntry.java +++ b/src/main/java/org/codeaholics/tools/build/pant/DependencyGraphEntry.java @@ -19,6 +19,7 @@ import java.util.HashSet; import java.util.Set; +import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Target; public class DependencyGraphEntry implements Runnable { @@ -87,6 +88,8 @@ public void run() { executionNotifier.notifyStarting(this); try { targetExecutor.executeTarget(target); + } catch (BuildException e) { + executionNotifier.notifyException(this, e); } finally { executionNotifier.notifyComplete(this); } diff --git a/src/main/java/org/codeaholics/tools/build/pant/ParallelExecutor.java b/src/main/java/org/codeaholics/tools/build/pant/ParallelExecutor.java index e826f6e..081f405 100644 --- a/src/main/java/org/codeaholics/tools/build/pant/ParallelExecutor.java +++ b/src/main/java/org/codeaholics/tools/build/pant/ParallelExecutor.java @@ -45,6 +45,8 @@ public class ParallelExecutor implements Executor { private AntWrapper antWrapper = new AntWrapperImpl(); private ExecutorService executorService; + private final List buildExceptions = new LinkedList(); + private int queued; @SuppressWarnings("unused") private int started; @@ -112,6 +114,25 @@ private void executeTarget(final Target target, final Map target } catch (final InterruptedException e) { // ignore } + + // Check for any exceptions that were thrown from the executorService + if (buildExceptions.size() > 1) { + // Combine the multiple exceptions into a new BuildException so all the errors are propagated to the user + String msg = "\n" + buildExceptions.size() + " failures occurred while building:"; + + int i = 0; + for (BuildException e : buildExceptions) { + i += 1; + msg += "\nFailure " + i + ":\n" + e + "\n"; + } + + throw new BuildException(msg); + } else { + // 0 or 1 exceptions, if 1 exists then just throw it + for (BuildException e : buildExceptions) { + throw e; + } + } } private int getNumberOfThreads(final Project project) { @@ -171,6 +192,12 @@ public synchronized void notifyComplete(final DependencyGraphEntry dependencyGra executorService.shutdown(); } } + + @Override + public synchronized void notifyException(final DependencyGraphEntry dependencyGraphEntry, BuildException e) { + buildExceptions.add(e); + executorService.shutdown(); + } }; } @@ -235,4 +262,4 @@ private void verifyPrePhaseTargets(final Map targetsByName) { public Executor getSubProjectExecutor() { return SUB_EXECUTOR; } -} \ No newline at end of file +} diff --git a/src/main/java/org/codeaholics/tools/build/pant/TargetExecutionNotifier.java b/src/main/java/org/codeaholics/tools/build/pant/TargetExecutionNotifier.java index 117a40f..d0b326f 100644 --- a/src/main/java/org/codeaholics/tools/build/pant/TargetExecutionNotifier.java +++ b/src/main/java/org/codeaholics/tools/build/pant/TargetExecutionNotifier.java @@ -16,7 +16,10 @@ * limitations under the License. */ +import org.apache.tools.ant.BuildException; + public interface TargetExecutionNotifier { public void notifyStarting(DependencyGraphEntry dependencyGraphEntry); public void notifyComplete(DependencyGraphEntry dependencyGraphEntry); + public void notifyException(DependencyGraphEntry dependencyGraphEntry, BuildException e); }