Skip to content

Commit

Permalink
Bring in and adapt command line steps to use ProcessRunner.
Browse files Browse the repository at this point in the history
  • Loading branch information
israelcolomer committed Oct 24, 2016
1 parent 78b6031 commit 3d2f3f4
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 42 deletions.
166 changes: 166 additions & 0 deletions core/src/main/java/foundation/stack/datamill/ProcessRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package foundation.stack.datamill;

import com.google.common.base.Joiner;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
* @author Ravi Chodavarapu (rchodava@gmail.com)
*/
public class ProcessRunner {
private static final Logger logger = LoggerFactory.getLogger(ProcessRunner.class);

private static final ListeningExecutorService processStreamProcessors =
MoreExecutors.listeningDecorator(Executors.newCachedThreadPool(new ThreadFactory() {
private final ThreadFactory threadFactory = Executors.defaultThreadFactory();

@Override
public Thread newThread(Runnable r) {
Thread thread = threadFactory.newThread(r);
if (thread != null) {
thread.setDaemon(true);
}

return thread;
}
}));

public static void runProcess(File workingDirectory, String... command) throws IOException {
runProcess(null, workingDirectory, command);
}

public static void runProcess(Marker marker, File workingDirectory, String... command) throws IOException {
logger.debug(marker, "{}", Joiner.on(' ').join(command));

Process process = new ProcessBuilder().directory(workingDirectory).command(command).start();

try {
readLinesFromStream(marker, process.getInputStream());
readLinesFromStream(marker, process.getErrorStream());
} catch (InterruptedException e) {
throw new IOException(e);
}
}

public static ExecutionResult runProcessAndWait(File workingDirectory, String... command) throws IOException {
return runProcessAndWait(null, workingDirectory, command);
}

public static ExecutionResult runProcessAndWait(Marker marker, File workingDirectory, String... command) throws IOException {
logger.debug(marker, "{}", Joiner.on(' ').join(command));

Process process = new ProcessBuilder().directory(workingDirectory).command(command).start();

try {
ListenableFuture<List<String>> standardOutputFuture = readLinesFromStream(marker, process.getInputStream());
ListenableFuture<List<String>> standardErrorFuture = readLinesFromStream(marker, process.getErrorStream());

int exitCode = process.waitFor();

List<List<String>> results = Futures.allAsList(standardOutputFuture, standardErrorFuture).get(1, TimeUnit.SECONDS);

return new ExecutionResult(exitCode, results.size() > 0 ? results.get(0) : null, results.size() > 1 ? results.get(1) : null);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(e);
}
}

private static ListenableFuture<List<String>> readLinesFromStream(Marker marker, InputStream inputStream) throws InterruptedException {
BufferedReader processOutput = new BufferedReader(new InputStreamReader(inputStream));
List<String> output = new CopyOnWriteArrayList<>();
return processStreamProcessors.submit(() -> {
try {
String line;
do {
line = processOutput.readLine();
if (line != null) {
output.add(line);
logger.debug(marker, line);
}
} while (line != null && !Thread.interrupted());
} catch (IOException e) {
}
return output;
});
}

public static int runProcessAndGetResult(File workingDirectory, String... command) throws IOException, InterruptedException {
return runProcessAndGetResult(null, workingDirectory, command);
}

public static int runProcessAndGetResult(Marker marker, File workingDirectory, String... command) throws IOException, InterruptedException {
logger.debug(marker, "{}", Joiner.on(' ').join(command));

Process process = new ProcessBuilder().directory(workingDirectory).command(command).redirectErrorStream(true).start();

BufferedReader processOutput = new BufferedReader(new
InputStreamReader(process.getInputStream()));

Thread processOutputThread = null;
if (logger.isDebugEnabled()) {
processOutputThread = new Thread(() -> {
try {
String line;
do {
line = processOutput.readLine();
logger.debug(marker, "{}", line);
} while (line != null && !Thread.interrupted());
} catch (IOException e) {
}
});

processOutputThread.start();
}

int result = process.waitFor();

if (processOutputThread != null) {
processOutputThread.join(500);
}

return result;
}

public static class ExecutionResult {
private final int exitCode;
private final List<String> standardOutput;
private final List<String> errorOutput;

public ExecutionResult(int exitCode, List<String> standardOutput, List<String> errorOutput) {
this.exitCode = exitCode;
this.standardOutput = standardOutput;
this.errorOutput = errorOutput;
}

public int getExitCode() {
return exitCode;
}

public List<String> getStandardOutput() {
return standardOutput;
}

public List<String> getErrorOutput() {
return errorOutput;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,19 @@
import cucumber.api.java.After;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import foundation.stack.datamill.Pair;
import foundation.stack.datamill.ProcessRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -160,19 +156,18 @@ public void executeCommandFromRelativeLocation(String command, String relativePa

try {
File temporaryDirectory = getOrCreateTemporaryDirectory();
File workingDirectory = resolvedRelativePath != null ?
new File(temporaryDirectory, resolvedRelativePath) : temporaryDirectory;
Process process = Runtime.getRuntime().exec(resolvedCommand, null, workingDirectory);
Pair<Integer, List<String>> executionResult = doRunProcess(process);
if (executionResult.getFirst() != 0) {
fail("Received result code " + executionResult.getFirst() + " after executing " + resolvedCommand);
File workingDirectory = resolvedRelativePath != null ? new File(temporaryDirectory, resolvedRelativePath) : temporaryDirectory;
ProcessRunner.ExecutionResult executionResult = ProcessRunner.runProcessAndWait(workingDirectory, resolvedCommand.split(" "));
if (executionResult.getExitCode() != 0) {
fail("Received result code " + executionResult.getExitCode() + " after executing " + resolvedCommand);
}
if (executionResult.getSecond() != null && !executionResult.getSecond().isEmpty()) {
String commandResult = Joiner.on(System.getProperty("line.separator")).join(executionResult.getSecond());
if (executionResult.getStandardOutput() != null && !executionResult.getStandardOutput().isEmpty()) {
String commandResult = Joiner.on(System.getProperty("line.separator")).join(executionResult.getStandardOutput());
logger.debug("Command execution of [{}] returned following results: {}", resolvedCommand, commandResult);
propertyStore.put(COMMAND_RESULT, commandResult);
}
} catch (InterruptedException | IOException e) {
} catch (IOException e) {
logger.error("Error while executing {}", resolvedCommand, e);
fail("Error while executing " + resolvedCommand);
}
}
Expand Down Expand Up @@ -255,32 +250,4 @@ public void cleanUp() throws IOException {
delete(temporaryDirectory);
}
}

private Pair<Integer, List<String>> doRunProcess(Process process) throws IOException, InterruptedException {
List<String> output = readLinesFromStream(process.getInputStream());
int result = process.waitFor();

return new Pair<>(result, output);
}

private List<String> readLinesFromStream(InputStream inputStream) throws InterruptedException {
BufferedReader processOutput = new BufferedReader(new InputStreamReader(inputStream));
List<String> output = new CopyOnWriteArrayList<>();

String line = null;
do {
try {
line = processOutput.readLine();
if (line != null) {
output.add(line);
logger.debug("{}", line);
}
} catch (IOException e) {
e.printStackTrace();
}
} while (line != null);

return output;
}

}

0 comments on commit 3d2f3f4

Please sign in to comment.