summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorChristian Halstrick <christian.halstrick@sap.com>2015-06-17 14:54:11 +0200
committerMatthias Sohn <matthias.sohn@sap.com>2015-11-02 22:19:47 +0100
commit67a77d402aa4bab609cb639fee9d18f42aed1d59 (patch)
treea9cd5551bd22b9f12c813ed06facf4c450e18721 /org.eclipse.jgit
parent8473bc4f8d2d69ca8aa3b4889660ed17d08f2270 (diff)
downloadjgit-67a77d402aa4bab609cb639fee9d18f42aed1d59.tar.gz
jgit-67a77d402aa4bab609cb639fee9d18f42aed1d59.zip
Enhance FS.runProcess() to support stdin-redirection and binary data
In order to support filters in gitattributes FS.runProcess() is made public. Support for stdin redirection has been added. Support for binary data on stdin/stdout (as used be clean/smudge filters) has been added. Change-Id: Ice2c152e9391368dc5748d7b825a838e3eb755f9 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java111
1 files changed, 71 insertions, 40 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 4e4371e8db..bcaf62a0c4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -44,15 +44,13 @@
package org.eclipse.jgit.util;
import java.io.BufferedReader;
-import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.OutputStreamWriter;
import java.io.PrintStream;
-import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -864,52 +862,88 @@ public abstract class FS {
* Runs the given process until termination, clearing its stdout and stderr
* streams on-the-fly.
*
- * @param hookProcessBuilder
- * The process builder configured for this hook.
+ * @param processBuilder
+ * The process builder configured for this process.
* @param outRedirect
- * A print stream on which to redirect the hook's stdout. Can be
- * <code>null</code>, in which case the hook's standard output
- * will be lost.
+ * A OutputStream on which to redirect the processes stdout. Can
+ * be <code>null</code>, in which case the processes standard
+ * output will be lost.
* @param errRedirect
- * A print stream on which to redirect the hook's stderr. Can be
- * <code>null</code>, in which case the hook's standard error
- * will be lost.
+ * A OutputStream on which to redirect the processes stderr. Can
+ * be <code>null</code>, in which case the processes standard
+ * error will be lost.
* @param stdinArgs
* A string to pass on to the standard input of the hook. Can be
* <code>null</code>.
- * @return the exit value of this hook.
+ * @return the exit value of this process.
* @throws IOException
- * if an I/O error occurs while executing this hook.
+ * if an I/O error occurs while executing this process.
* @throws InterruptedException
* if the current thread is interrupted while waiting for the
* process to end.
- * @since 3.7
+ * @since 4.2
*/
- protected int runProcess(ProcessBuilder hookProcessBuilder,
+ public int runProcess(ProcessBuilder processBuilder,
OutputStream outRedirect, OutputStream errRedirect, String stdinArgs)
throws IOException, InterruptedException {
+ InputStream in = (stdinArgs == null) ? null : new ByteArrayInputStream(
+ stdinArgs.getBytes(Constants.CHARACTER_ENCODING));
+ return runProcess(processBuilder, outRedirect, errRedirect, in);
+ }
+
+ /**
+ * Runs the given process until termination, clearing its stdout and stderr
+ * streams on-the-fly.
+ *
+ * @param processBuilder
+ * The process builder configured for this process.
+ * @param outRedirect
+ * An OutputStream on which to redirect the processes stdout. Can
+ * be <code>null</code>, in which case the processes standard
+ * output will be lost. If binary is set to <code>false</code>
+ * then it is expected that the process emits text data which
+ * should be processed line by line.
+ * @param errRedirect
+ * An OutputStream on which to redirect the processes stderr. Can
+ * be <code>null</code>, in which case the processes standard
+ * error will be lost.
+ * @param inRedirect
+ * An InputStream from which to redirect the processes stdin. Can
+ * be <code>null</code>, in which case the process doesn't get
+ * any data over stdin. If binary is set to
+ * <code>false</code> then it is expected that the process
+ * expects text data which should be processed line by line.
+ * @return the return code of this process.
+ * @throws IOException
+ * if an I/O error occurs while executing this process.
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the
+ * process to end.
+ * @since 4.2
+ */
+ public int runProcess(ProcessBuilder processBuilder,
+ OutputStream outRedirect, OutputStream errRedirect,
+ InputStream inRedirect) throws IOException,
+ InterruptedException {
final ExecutorService executor = Executors.newFixedThreadPool(2);
Process process = null;
// We'll record the first I/O exception that occurs, but keep on trying
// to dispose of our open streams and file handles
IOException ioException = null;
try {
- process = hookProcessBuilder.start();
+ process = processBuilder.start();
final Callable<Void> errorGobbler = new StreamGobbler(
process.getErrorStream(), errRedirect);
final Callable<Void> outputGobbler = new StreamGobbler(
process.getInputStream(), outRedirect);
executor.submit(errorGobbler);
executor.submit(outputGobbler);
- if (stdinArgs != null) {
- final PrintWriter stdinWriter = new PrintWriter(
- process.getOutputStream());
- stdinWriter.print(stdinArgs);
- stdinWriter.flush();
- // We are done with this hook's input. Explicitly close its
- // stdin now to kick off any blocking read the hook might have.
- stdinWriter.close();
+ OutputStream outputStream = process.getOutputStream();
+ if (inRedirect != null) {
+ new StreamGobbler(inRedirect, outputStream)
+ .call();
}
+ outputStream.close();
return process.waitFor();
} catch (IOException e) {
ioException = e;
@@ -1187,30 +1221,27 @@ public abstract class FS {
* </p>
*/
private static class StreamGobbler implements Callable<Void> {
- private final BufferedReader reader;
+ private InputStream in;
- private final BufferedWriter writer;
+ private OutputStream out;
public StreamGobbler(InputStream stream, OutputStream output) {
- this.reader = new BufferedReader(new InputStreamReader(stream));
- if (output == null)
- this.writer = null;
- else
- this.writer = new BufferedWriter(new OutputStreamWriter(output));
+ this.in = stream;
+ this.out = output;
}
public Void call() throws IOException {
boolean writeFailure = false;
-
- String line = null;
- while ((line = reader.readLine()) != null) {
- // Do not try to write again after a failure, but keep reading
- // as long as possible to prevent the input stream from choking.
- if (!writeFailure && writer != null) {
+ byte buffer[] = new byte[4096];
+ int readBytes;
+ while ((readBytes = in.read(buffer)) != -1) {
+ // Do not try to write again after a failure, but keep
+ // reading as long as possible to prevent the input stream
+ // from choking.
+ if (!writeFailure && out != null) {
try {
- writer.write(line);
- writer.newLine();
- writer.flush();
+ out.write(buffer, 0, readBytes);
+ out.flush();
} catch (IOException e) {
writeFailure = true;
}