git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274016 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -59,9 +59,11 @@ import java.io.ByteArrayOutputStream; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.FileNotFoundException; | import java.io.FileNotFoundException; | ||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||
| import java.io.FileInputStream; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.StringReader; | import java.io.StringReader; | ||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import java.io.InputStream; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
| @@ -89,6 +91,7 @@ public class ExecTask extends Task { | |||||
| private String os; | private String os; | ||||
| private File out; | private File out; | ||||
| private File error; | private File error; | ||||
| private File input; | |||||
| private boolean logError = false; | private boolean logError = false; | ||||
| @@ -167,6 +170,13 @@ public class ExecTask extends Task { | |||||
| this.cmdl = cmdl; | this.cmdl = cmdl; | ||||
| } | } | ||||
| /** | |||||
| * Set the input to use for the task | |||||
| */ | |||||
| public void setInput(File input) { | |||||
| this.input = input; | |||||
| } | |||||
| /** | /** | ||||
| * File the output of the process is redirected to. If error is not | * File the output of the process is redirected to. If error is not | ||||
| * redirected, it too will appear in the output | * redirected, it too will appear in the output | ||||
| @@ -475,6 +485,7 @@ public class ExecTask extends Task { | |||||
| protected ExecuteStreamHandler createHandler() throws BuildException { | protected ExecuteStreamHandler createHandler() throws BuildException { | ||||
| OutputStream outputStream = null; | OutputStream outputStream = null; | ||||
| OutputStream errorStream = null; | OutputStream errorStream = null; | ||||
| InputStream inputStream = null; | |||||
| if (out == null && outputprop == null) { | if (out == null && outputprop == null) { | ||||
| outputStream = new LogOutputStream(this, Project.MSG_INFO); | outputStream = new LogOutputStream(this, Project.MSG_INFO); | ||||
| @@ -540,8 +551,18 @@ public class ExecTask extends Task { | |||||
| } else { | } else { | ||||
| errorBaos = null; | errorBaos = null; | ||||
| } | } | ||||
| if (input != null) { | |||||
| try { | |||||
| inputStream = new FileInputStream(input); | |||||
| } catch (FileNotFoundException fne) { | |||||
| throw new BuildException("Cannot read from " + input, fne, | |||||
| getLocation()); | |||||
| } | |||||
| } | |||||
| return new PumpStreamHandler(outputStream, errorStream, true, true); | |||||
| return new PumpStreamHandler(outputStream, errorStream, inputStream, | |||||
| true, true, true); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -69,24 +69,32 @@ import java.io.OutputStream; | |||||
| */ | */ | ||||
| public class PumpStreamHandler implements ExecuteStreamHandler { | public class PumpStreamHandler implements ExecuteStreamHandler { | ||||
| private Thread inputThread; | |||||
| private Thread outputThread; | |||||
| private Thread errorThread; | private Thread errorThread; | ||||
| private Thread inputThread; | |||||
| private OutputStream out; | private OutputStream out; | ||||
| private OutputStream err; | private OutputStream err; | ||||
| private InputStream input; | |||||
| private boolean closeOutOnStop = false; | private boolean closeOutOnStop = false; | ||||
| private boolean closeErrOnStop = false; | private boolean closeErrOnStop = false; | ||||
| private boolean closeInputOnStop = false; | |||||
| public PumpStreamHandler(OutputStream out, OutputStream err, | public PumpStreamHandler(OutputStream out, OutputStream err, | ||||
| boolean closeOutOnStop, boolean closeErrOnStop) { | |||||
| InputStream input, | |||||
| boolean closeOutOnStop, boolean closeErrOnStop, | |||||
| boolean closeInputOnStop) { | |||||
| this.out = out; | this.out = out; | ||||
| this.err = err; | this.err = err; | ||||
| this.input = input; | |||||
| this.closeOutOnStop = closeOutOnStop; | this.closeOutOnStop = closeOutOnStop; | ||||
| this.closeErrOnStop = closeErrOnStop; | this.closeErrOnStop = closeErrOnStop; | ||||
| this.closeInputOnStop = closeInputOnStop; | |||||
| } | } | ||||
| public PumpStreamHandler(OutputStream out, OutputStream err) { | public PumpStreamHandler(OutputStream out, OutputStream err) { | ||||
| this(out, err, false, false); | |||||
| this(out, err, null, false, false, false); | |||||
| } | } | ||||
| public PumpStreamHandler(OutputStream outAndErr) { | public PumpStreamHandler(OutputStream outAndErr) { | ||||
| @@ -103,39 +111,70 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| public void setProcessErrorStream(InputStream is) { | public void setProcessErrorStream(InputStream is) { | ||||
| createProcessErrorPump(is, err); | |||||
| if (err != null) { | |||||
| createProcessErrorPump(is, err); | |||||
| } | |||||
| } | } | ||||
| public void setProcessInputStream(OutputStream os) { | public void setProcessInputStream(OutputStream os) { | ||||
| if (input != null) { | |||||
| inputThread = createPump(input, os, true); | |||||
| } else { | |||||
| try { | |||||
| os.close(); | |||||
| } catch (IOException e) { | |||||
| //ignore | |||||
| } | |||||
| } | |||||
| } | } | ||||
| public void start() { | public void start() { | ||||
| inputThread.start(); | |||||
| outputThread.start(); | |||||
| errorThread.start(); | errorThread.start(); | ||||
| inputThread.start(); | |||||
| } | } | ||||
| public void stop() { | public void stop() { | ||||
| try { | try { | ||||
| inputThread.join(); | |||||
| } catch (InterruptedException e) {} | |||||
| outputThread.join(); | |||||
| } catch (InterruptedException e) { | |||||
| // ignore | |||||
| } | |||||
| try { | try { | ||||
| errorThread.join(); | errorThread.join(); | ||||
| } catch (InterruptedException e) {} | |||||
| } catch (InterruptedException e) { | |||||
| // ignore | |||||
| } | |||||
| if (inputThread != null) { | |||||
| try { | |||||
| inputThread.join(); | |||||
| if (closeInputOnStop) { | |||||
| input.close(); | |||||
| } | |||||
| } catch (InterruptedException e) { | |||||
| // ignore | |||||
| } catch (IOException e) { | |||||
| // ignore | |||||
| } | |||||
| } | |||||
| try { | try { | ||||
| err.flush(); | err.flush(); | ||||
| if (closeErrOnStop) { | if (closeErrOnStop) { | ||||
| err.close(); | err.close(); | ||||
| } | } | ||||
| } catch (IOException e) {} | |||||
| } catch (IOException e) { | |||||
| // ignore | |||||
| } | |||||
| try { | try { | ||||
| out.flush(); | out.flush(); | ||||
| if (closeOutOnStop) { | if (closeOutOnStop) { | ||||
| out.close(); | out.close(); | ||||
| } | } | ||||
| } catch (IOException e) {} | |||||
| } catch (IOException e) { | |||||
| // ignore | |||||
| } | |||||
| } | } | ||||
| protected OutputStream getErr() { | protected OutputStream getErr() { | ||||
| @@ -147,7 +186,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| } | } | ||||
| protected void createProcessOutputPump(InputStream is, OutputStream os) { | protected void createProcessOutputPump(InputStream is, OutputStream os) { | ||||
| inputThread = createPump(is, os); | |||||
| outputThread = createPump(is, os); | |||||
| } | } | ||||
| protected void createProcessErrorPump(InputStream is, OutputStream os) { | protected void createProcessErrorPump(InputStream is, OutputStream os) { | ||||
| @@ -160,7 +199,17 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| * given output stream. | * given output stream. | ||||
| */ | */ | ||||
| protected Thread createPump(InputStream is, OutputStream os) { | protected Thread createPump(InputStream is, OutputStream os) { | ||||
| final Thread result = new Thread(new StreamPumper(is, os)); | |||||
| return createPump(is, os, false); | |||||
| } | |||||
| /** | |||||
| * Creates a stream pumper to copy the given input stream to the | |||||
| * given output stream. | |||||
| */ | |||||
| protected Thread createPump(InputStream is, OutputStream os, | |||||
| boolean closeWhenExhausted) { | |||||
| final Thread result | |||||
| = new Thread(new StreamPumper(is, os, closeWhenExhausted)); | |||||
| result.setDaemon(true); | result.setDaemon(true); | ||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -66,23 +66,38 @@ import java.io.OutputStream; | |||||
| */ | */ | ||||
| public class StreamPumper implements Runnable { | public class StreamPumper implements Runnable { | ||||
| // TODO: make SIZE and SLEEP instance variables. | |||||
| // TODO: make SIZE an instance variable. | |||||
| // TODO: add a status flag to note if an error occured in run. | // TODO: add a status flag to note if an error occured in run. | ||||
| private static final int SIZE = 128; | private static final int SIZE = 128; | ||||
| private InputStream is; | private InputStream is; | ||||
| private OutputStream os; | private OutputStream os; | ||||
| private boolean finished; | private boolean finished; | ||||
| private boolean closeWhenExhausted; | |||||
| /** | /** | ||||
| * Create a new stream pumper. | * Create a new stream pumper. | ||||
| * | * | ||||
| * @param is input stream to read data from | * @param is input stream to read data from | ||||
| * @param os output stream to write data to. | * @param os output stream to write data to. | ||||
| * @param closeWhenExhausted if true, the output stream will be closed when | |||||
| * the input is exhausted. | |||||
| */ | */ | ||||
| public StreamPumper(InputStream is, OutputStream os) { | |||||
| public StreamPumper(InputStream is, OutputStream os, | |||||
| boolean closeWhenExhausted) { | |||||
| this.is = is; | this.is = is; | ||||
| this.os = os; | this.os = os; | ||||
| this.closeWhenExhausted = closeWhenExhausted; | |||||
| } | |||||
| /** | |||||
| * Create a new stream pumper. | |||||
| * | |||||
| * @param is input stream to read data from | |||||
| * @param os output stream to write data to. | |||||
| */ | |||||
| public StreamPumper(InputStream is, OutputStream os) { | |||||
| this(is, os, false); | |||||
| } | } | ||||
| @@ -104,6 +119,9 @@ public class StreamPumper implements Runnable { | |||||
| while ((length = is.read(buf)) > 0) { | while ((length = is.read(buf)) > 0) { | ||||
| os.write(buf, 0, length); | os.write(buf, 0, length); | ||||
| } | } | ||||
| if (closeWhenExhausted) { | |||||
| os.close(); | |||||
| } | |||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| // ignore errors | // ignore errors | ||||
| } finally { | } finally { | ||||