diff --git a/LaraFramework/src/pt/up/fe/specs/lara/WeaverLauncher.java b/LaraFramework/src/pt/up/fe/specs/lara/WeaverLauncher.java index ba3106c0d..670225f10 100644 --- a/LaraFramework/src/pt/up/fe/specs/lara/WeaverLauncher.java +++ b/LaraFramework/src/pt/up/fe/specs/lara/WeaverLauncher.java @@ -14,10 +14,13 @@ package pt.up.fe.specs.lara; import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -29,12 +32,16 @@ import org.lara.interpreter.joptions.config.interpreter.LaraiKeys; import org.lara.interpreter.weaver.interf.WeaverEngine; +import org.openjdk.jmh.runner.RunnerException; + +import com.google.gson.Gson; import larai.LaraI; import pt.up.fe.specs.lara.doc.LaraDocLauncher; import pt.up.fe.specs.lara.unit.LaraUnitLauncher; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsLogs; +import pt.up.fe.specs.util.SpecsStrings; import pt.up.fe.specs.util.SpecsSystem; import pt.up.fe.specs.util.utilities.CachedValue; @@ -454,7 +461,7 @@ public String[] executeParallel(String[][] args, int threads, List weave var customThreadPool = threads > 0 ? new ForkJoinPool(threads) : new ForkJoinPool(); // Choose executor - Function weaverExecutor = weaverCommand.isEmpty() ? this::executeSafe + Function weaverExecutor = weaverCommand.isEmpty() ? this::executeSafe : weaverArgs -> this.executeOtherJvm(weaverArgs, weaverCommand, workingFolder); SpecsLogs.info("Launching " + args.length + " instances of weaver " + engine.getName() @@ -487,7 +494,7 @@ public String[] executeParallel(String[][] args, int threads, List weave } // Launch tasks - List> tasks = new ArrayList<>(); + List> tasks = new ArrayList<>(); for (var weaverArgs : adaptedArgs) { tasks.add(customThreadPool.submit(() -> weaverExecutor.apply(weaverArgs))); } @@ -497,7 +504,50 @@ public String[] executeParallel(String[][] args, int threads, List weave // Wait for tasks for (var task : tasks) { - task.get(); + var result = task.get(); + + var e = result.getException().orElse(null); + + if (e == null) { + continue; + } + + // If there is an exception, look for the results file and write an error json + try (StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter)) { + + e.printStackTrace(printWriter); + var stackTrace = stringWriter.toString(); + + var taskArgs = result.getArgs(); + + // Get JSON results file + var indexOfR = taskArgs.length - 2; + + if (taskArgs[indexOfR] != "-r") { + throw new RunnerException( + "Expected second to last argument to be '-r': " + Arrays.toString(taskArgs)); + } + + var resultsFile = taskArgs[indexOfR + 1]; + + var results = new LinkedHashMap(); + var lastCause = SpecsSystem.getLastCause(e); + results.put("error", SpecsStrings.escapeJson(lastCause.getMessage())); + results.put("args", args); + results.put("stackTrace", SpecsStrings.escapeJson(stackTrace)); + + // var resultsReturn = new HashMap<>(); + // // Must be inside an array + // resultsReturn.put("output", "[" + new Gson().toJson(results) + "]"); + + SpecsIo.write(new File(resultsFile), new Gson().toJson(results)); + + SpecsLogs.info("Exception during weaver execution:\n" + stackTrace); + } catch (Exception ex) { + SpecsLogs.info("Exception while retrieving error information: " + e); + ex.printStackTrace(); + } } // Arrays.asList(adaptedArgs).stream() @@ -538,24 +588,25 @@ private String[] collectResults(List resultFiles) { results.add("{}"); continue; } - + // System.out.println("CONTENTS:\n" + SpecsIo.read(resultFile)); results.add(SpecsIo.read(resultFile)); } return results.toArray(size -> new String[size]); } - private boolean executeSafe(String[] args) { + private WeaverResult executeSafe(String[] args) { try { // Create new WeaverEngine var weaverEngineConstructor = getDefaultConstructor(); - return new WeaverLauncher(weaverEngineConstructor.newInstance()).launch(args); + var weaverLauncher = new WeaverLauncher(weaverEngineConstructor.newInstance()); + return new WeaverResult(args, weaverLauncher.launch(args)); } catch (Exception e) { // throw new RuntimeException("Could not execute", e); - SpecsLogs.info("Exception during weaver execution: " + e); - e.printStackTrace(); - return false; + // SpecsLogs.info("Exception during weaver execution: " + e); + // e.printStackTrace(); + return new WeaverResult(args, e); } } @@ -573,7 +624,7 @@ private Constructor getDefaultConstructor() { throw new RuntimeException("Could not find default constructor for WeaverEngine " + engine.getClass()); } - private boolean executeOtherJvm(String[] args, List weaverCommand, File workingDir) { + private WeaverResult executeOtherJvm(String[] args, List weaverCommand, File workingDir) { try { // DEBUG // if (true) { @@ -593,13 +644,11 @@ private boolean executeOtherJvm(String[] args, List weaverCommand, File // var result = SpecsSystem.run(newArgs, SpecsIo.getWorkingDir()); var result = SpecsSystem.run(newArgs, workingDir); - return result == 0; + return new WeaverResult(args, result == 0); // return execute(args); } catch (Exception e) { - SpecsLogs.info("Exception during weaver execution: " + e); - e.printStackTrace(); - return false; + return new WeaverResult(args, e); } } diff --git a/LaraFramework/src/pt/up/fe/specs/lara/WeaverResult.java b/LaraFramework/src/pt/up/fe/specs/lara/WeaverResult.java new file mode 100644 index 000000000..ecc9f7bd4 --- /dev/null +++ b/LaraFramework/src/pt/up/fe/specs/lara/WeaverResult.java @@ -0,0 +1,60 @@ +/** + * Copyright 2024 SPeCS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.specs.lara; + +import java.util.Optional; + +public class WeaverResult { + + private final boolean isSuccess; + private final String[] args; + private final Exception exception; + + private WeaverResult(String[] args, boolean isSuccess, Exception exception) { + this.args = args; + this.isSuccess = isSuccess; + this.exception = exception; + } + + /** + * For executions without exception. + * + * @param isSuccess + */ + public WeaverResult(String[] args, boolean isSuccess) { + this(args, isSuccess, null); + } + + /** + * Unsuccessful execution with exception. + * + * @param e + */ + public WeaverResult(String[] args, Exception e) { + this(args, false, e); + } + + public boolean isSuccess() { + return isSuccess; + } + + public String[] getArgs() { + return args; + } + + public Optional getException() { + return Optional.ofNullable(exception); + } + +}