Skip to content

Commit

Permalink
Merge pull request #32 from TheRoddyWMS/improved-execution-result
Browse files Browse the repository at this point in the history
Impoved [Async]ExecutionResult interface.
  • Loading branch information
vinjana committed May 6, 2021
2 parents bd32bf6 + 85e5803 commit 1e926e0
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 156 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,15 @@ systemProp.https.proxyPort=HTTPS_proxy_port
```

where you substitute the correct proxies and ports required for your environment.

## Changelog

* 0.0.8

- Refactored `AsyncExecutionResult` and `ExecutionResult` to improve the stdout and stderr handling. This also affects `ExecutionResult.resultLines` field/accessors.
- Improved support for additional output stream in `LocalExecutionHelper`
- Changes are required for Roddy 3.6.1 improvements related to better error reporting and handling.

* 0.0.7

- Added `AsyncExecutionResult` to handle asynchronous execution of command executions.
15 changes: 0 additions & 15 deletions RoddyToolLib.iml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import java.util.concurrent.CompletableFuture
/** Like ExecutionResult, but taking Futures of the exit code (usually the actual process) and the standard output and
* error streams. Calling any of the methods will block until the process is finished!
*
* TODO Make ExecutionResult and AsyncExecutionResult common subclasses of an IExecutionResult interface.
* TODO Make ExecutionResult and AsyncExecutionResult common subclasses of an IExecutionResult
* interface.
*
*/

class AsyncExecutionResult extends ExecutionResult {

private final Future<Integer> exitCodeF
Expand All @@ -19,40 +22,45 @@ class AsyncExecutionResult extends ExecutionResult {
* that return the values will block until the result is available.
*
* @param process
* @param stdout
* @param stderr
* @param stdoutF
* @param stderrF
* @param successful Can be a future. By default (when set to null), it will be set success if exitCode == 0.
*/
AsyncExecutionResult(CompletableFuture<Integer> process,
CompletableFuture<List<String>> stdout,
CompletableFuture<List<String>> stderr,
CompletableFuture<Boolean> successful = null) {
super(true, 0, [], "") // These are only stub-values.
this.exitCodeF = process
this.stderrF = stderr
this.stdoutF = stdout
if (null == successful) {
this.successfulF = process.thenApply {exitCode ->
exitCode == 0
}
} else {
this.successfulF = successful
AsyncExecutionResult(List<String> command,
Integer processId,
CompletableFuture<Integer> exitCodeF,
CompletableFuture<List<String>> stdoutF,
CompletableFuture<List<String>> stderrF) {
super(command, false, -1, [], [], processId as String)
this.exitCodeF = exitCodeF
this.stderrF = stderrF
this.stdoutF = stdoutF
this.successfulF = exitCodeF.thenApply { exitCode ->
exitCode == 0
}
}

/** Convert the asynchronous result into a synchronous one. This will obviously block until
* the referee process is finished.
*/
ExecutionResult asExecutionResult() {
new ExecutionResult(command, successful, exitCode, stdout, stderr, processID)
}

@Override
int getExitCode() {
return exitCodeF.get()
}


@Override
List<String> getResultLines() {
return stdoutF.get()
List<String> getStdout() {
return this.stdoutF.get()
}

@Override
String getFirstLine() {
return stdoutF.get()
List<String> getStderr() {
return this.stderrF.get()
}

@Override
Expand Down
134 changes: 134 additions & 0 deletions src/main/groovy/de/dkfz/roddy/execution/io/ExecutionResult.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2016 German Cancer Research Center (Deutsches Krebsforschungszentrum, DKFZ).
*
* Distributed under the MIT License (license terms are at https://www.github.com/TheRoddyWMS/Roddy/LICENSE.txt).
*/

package de.dkfz.roddy.execution.io

import de.dkfz.roddy.core.InfoObject

/**
* Stores the result of a command execution.
* Commands can i.e. be executed via ssh or on the local command line.
*
* TODO Make ExecutionResult and AsyncExecutionResult common subclasses of an IExecutionResult
* interface.
*
* @author michael
*/
class ExecutionResult extends InfoObject {

/**
* This can hold some sort of process id for a process
*/
protected final String processID

/**
* Successful or not?
*/
protected final boolean successful

/**
* This field is only kept for backwards-compatibility with Roddy plugins that are compiled
* to access this field directly, instead of via the accessor. For this reason the field is
* also kept public. Not that the changes in AsyncExecutionResult, and its late initialization
* there is irrelevant in this context, because all old code refers to ExecutionResult.
*/
@Deprecated
public final List<String> resultLines

/**
* All result lines.
*/
protected final List<String> stdout
protected final List<String> stderr

protected final int exitCode

/**
* Executed command that produced the result.
*/
protected final List<String> command

/** Contain the results of an execution. Note that the usage of this class is quite inconsistent. In particular
* occasionally the result indicates success, but the process actually failed.
*
* @param successful Whether the execution was successful. Some tools produce an exit code == 0 but may still
* have failed. A prominent example is the BWA aligner. For this reason the successful field
* allows specifying success from e.g. standard output or error of the process rather than
* just the exit code.
* @param exitCode The actual exit code.
* @param stdout This should be the standard output.
* @param stderr This should be the standard error.
* @param processID The process ID, if available.
*/
ExecutionResult(List<String> command,
boolean successful,
int exitCode,
List<String> stdout = [],
List<String> stderr = [],
String processID = null) {
this.command = command
this.processID = processID
this.successful = successful
this.exitCode = exitCode
this.stdout = stdout
this.stderr = stderr
// This will initialize the final field of ExecutionResult. Old client code using
// ExecutionResult variables that refer to AsyncExecutionResult will retrieve this
// value, rather than getting the maybe updated value via getResultLines()!
this.resultLines = stdout + stderr
}

String getProcessID() {
return processID
}

int getExitCode() {
return exitCode
}

/** Convenience method */
String getFirstStdoutLine() {
return stdout.size() > 0 ? stdout.get(0) : null
}

@Deprecated
List<String> getResultLines() {
return getStdout() + getStderr()
}

List<String> getStdout() {
return stdout
}

List<String> getStderr() {
return stderr
}

boolean isSuccessful() {
return successful
}

boolean getSuccessful() {
return isSuccessful()
}

@Deprecated
int getErrorNumber() {
return exitCode
}

List<String> toStatusMessage() {
return [successful ? "Success" : "Error" +
" executing command (exitCode=${exitCode}, command=${command.join(" ")}):",
"stdout={${this.stdout.join("\n")}}",
"stderr={${stderr.join("\n")}}"]
}

String toStatusLine() {
return toStatusMessage().join(" ")
}

}
94 changes: 0 additions & 94 deletions src/main/groovy/de/dkfz/roddy/execution/io/ExecutionResult.java

This file was deleted.

Loading

0 comments on commit 1e926e0

Please sign in to comment.