mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Move ProcessHelper and its friends to the processing-app, so they can be used by the unit tests
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
package processing.util.exec;
|
||||
|
||||
public interface LineProcessor {
|
||||
void processLine(final String line);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2009-10 Ben Fry and Casey Reas
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package processing.util.exec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Class to handle calling Runtime.exec() and stuffing output and error streams
|
||||
* into Strings that can be dealt with more easily.
|
||||
*
|
||||
* @author Jonathan Feinberg <jdf@pobox.com>
|
||||
*/
|
||||
public class ProcessHelper {
|
||||
private final String[] cmd;
|
||||
|
||||
public ProcessHelper(final String... cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
for (int i = 0; i < cmd.length; i++) {
|
||||
if (i != 0) {
|
||||
buffer.append(" ");
|
||||
}
|
||||
buffer.append(cmd[i]);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking execution.
|
||||
* @return exit value of process
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public ProcessResult execute() throws InterruptedException, IOException {
|
||||
final StringWriter outWriter = new StringWriter();
|
||||
final StringWriter errWriter = new StringWriter();
|
||||
final long startTime = System.currentTimeMillis();
|
||||
|
||||
final String prettyCommand = toString();
|
||||
// System.err.println("ProcessHelper: >>>>> " + Thread.currentThread().getId()
|
||||
// + " " + prettyCommand);
|
||||
final Process process = Runtime.getRuntime().exec(cmd);
|
||||
ProcessRegistry.watch(process);
|
||||
try {
|
||||
new StreamPump(process.getInputStream()).addTarget(outWriter).start();
|
||||
new StreamPump(process.getErrorStream()).addTarget(errWriter).start();
|
||||
try {
|
||||
final int result = process.waitFor();
|
||||
final long time = System.currentTimeMillis() - startTime;
|
||||
// System.err.println("ProcessHelper: <<<<< "
|
||||
// + Thread.currentThread().getId() + " " + cmd[0] + " (" + time
|
||||
// + "ms)");
|
||||
return new ProcessResult(prettyCommand, result, outWriter.toString(),
|
||||
errWriter.toString(), time);
|
||||
} catch (final InterruptedException e) {
|
||||
System.err.println("Interrupted: " + prettyCommand);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
process.destroy();
|
||||
ProcessRegistry.unwatch(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package processing.util.exec;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProcessRegistry {
|
||||
private static final Set<Process> REGISTRY = Collections
|
||||
.synchronizedSet(new HashSet<Process>());
|
||||
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (REGISTRY) {
|
||||
for (final Process p : REGISTRY) {
|
||||
try {
|
||||
// System.err.println("Cleaning up rogue process " + p);
|
||||
p.destroy();
|
||||
} catch (final Exception drop) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When starting up a process
|
||||
* @param p
|
||||
*/
|
||||
public static void watch(final Process p) {
|
||||
REGISTRY.add(p);
|
||||
}
|
||||
|
||||
public static void unwatch(final Process p) {
|
||||
REGISTRY.remove(p);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package processing.util.exec;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ProcessResult implements Iterable<String> {
|
||||
private final String cmd;
|
||||
private final long time;
|
||||
private final String output;
|
||||
private final String error;
|
||||
private final int result;
|
||||
|
||||
public ProcessResult(final String cmd, final int result, final String output,
|
||||
final String error, final long time) {
|
||||
this.cmd = cmd;
|
||||
this.output = output;
|
||||
this.error = error;
|
||||
this.result = result;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public Iterator<String> iterator() {
|
||||
return Arrays.asList(output.split("\r?\n")).iterator();
|
||||
}
|
||||
|
||||
public String getCmd() {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public int getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean succeeded() {
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
public String getStderr() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getStdout() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(cmd).append("\n");
|
||||
sb.append(" status: ").append(result).append("\n");
|
||||
sb.append(" ").append(time).append("ms").append("\n");
|
||||
sb.append(" stdout:\n").append(output).append("\n");
|
||||
sb.append(" stderr:\n").append(error);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package processing.util.exec;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
/**
|
||||
* <p>A StreamPump reads lines of text from its given InputStream
|
||||
* and informs its LineProcessors
|
||||
* until the InputStream is exhausted. <b>It is useful only for pumping lines of
|
||||
* text, and not for arbitrary binary cruft.</b> It's handy for reading
|
||||
* the output of processes that emit textual data, for example.
|
||||
*
|
||||
* @author Jonathan Feinberg <jdf@pobox.com>
|
||||
*
|
||||
*/
|
||||
public class StreamPump implements Runnable {
|
||||
private static final ExecutorService threads = Executors
|
||||
.newCachedThreadPool(new ThreadFactory() {
|
||||
public Thread newThread(final Runnable r) {
|
||||
final Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("StreamPump " + t.getId());
|
||||
return t;
|
||||
}
|
||||
});
|
||||
|
||||
private final BufferedReader reader;
|
||||
private final List<LineProcessor> outs = new CopyOnWriteArrayList<LineProcessor>();
|
||||
|
||||
public StreamPump(final InputStream in) {
|
||||
this.reader = new BufferedReader(new InputStreamReader(in));
|
||||
}
|
||||
|
||||
public StreamPump addTarget(final OutputStream out) {
|
||||
outs.add(new WriterLineProcessor(out));
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamPump addTarget(final Writer out) {
|
||||
outs.add(new WriterLineProcessor(out));
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamPump addTarget(final LineProcessor out) {
|
||||
outs.add(out);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
threads.execute(this);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
for (final LineProcessor out : outs) {
|
||||
try {
|
||||
out.processLine(line);
|
||||
} catch (final Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WriterLineProcessor implements LineProcessor {
|
||||
private final PrintWriter writer;
|
||||
|
||||
private WriterLineProcessor(final OutputStream out) {
|
||||
this.writer = new PrintWriter(out, true);
|
||||
}
|
||||
|
||||
private WriterLineProcessor(final Writer writer) {
|
||||
this.writer = new PrintWriter(writer, true);
|
||||
}
|
||||
|
||||
public void processLine(final String line) {
|
||||
writer.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
public static final LineProcessor DEVNULL = new LineProcessor() {
|
||||
public void processLine(final String line) {
|
||||
// noop
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user