use unified implementation of capturing stdout and stderr

This commit is contained in:
Dmitry Jemerov
2009-07-29 21:22:44 +04:00
parent 4dffb269f9
commit c43da5c5aa
2 changed files with 22 additions and 142 deletions
@@ -3,6 +3,7 @@ package com.jetbrains.python.sdk;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetConfiguration;
import com.intellij.facet.FacetManager;
@@ -307,7 +308,7 @@ public class PythonSdkType extends SdkType {
out.close();
}
return SdkUtil.getProcessOutput(sdk_path, new String[] {bin_path, scriptFile.getPath()}).getStdout();
return SdkUtil.getProcessOutput(sdk_path, new String[] {bin_path, scriptFile.getPath()}).getStdoutLines();
}
finally {
FileUtil.delete(scriptFile);
@@ -333,7 +334,7 @@ public class PythonSdkType extends SdkType {
version_opt = "-V";
}
Pattern pattern = Pattern.compile(version_regexp);
String version = SdkUtil.getFirstMatch(SdkUtil.getProcessOutput(sdkHome, new String[] {binaryPath, version_opt}).getStderr(), pattern);
String version = SdkUtil.getFirstMatch(SdkUtil.getProcessOutput(sdkHome, new String[] {binaryPath, version_opt}).getStderrLines(), pattern);
return version;
}
@@ -409,10 +410,10 @@ public class PythonSdkType extends SdkType {
out.close();
try {
final SdkUtil.ProcessCallInfo run_result = SdkUtil.getProcessOutput(sdkPath, new String[] {bin_path, find_bin_file.getPath()});
final ProcessOutput run_result = SdkUtil.getProcessOutput(sdkPath, new String[] {bin_path, find_bin_file.getPath()});
if (run_result.getExitValue() == 0) {
for (String line : run_result.getStdout()) {
if (run_result.getExitCode() == 0) {
for (String line : run_result.getStdoutLines()) {
// line = "mod_name path"
int cutpos = line.indexOf(' ');
String modname = line.substring(0, cutpos);
@@ -428,13 +429,13 @@ public class PythonSdkType extends SdkType {
indicator.setText2(modname);
}
LOG.info("Skeleton for " + modname);
final SdkUtil.ProcessCallInfo gen_result = SdkUtil.getProcessOutput(sdkPath,
final ProcessOutput gen_result = SdkUtil.getProcessOutput(sdkPath,
new String[] {bin_path, gen3_file.getPath(), "-d", stubsRoot, modname}, RUN_TIMEOUT
);
if (gen_result.getExitValue() != 0) {
if (gen_result.getExitCode() != 0) {
StringBuffer sb = new StringBuffer("Skeleton for ");
sb.append(modname).append(" failed. stderr: --");
for (String err_line : gen_result.getStderr()) sb.append(err_line).append("\n");
for (String err_line : gen_result.getStderrLines()) sb.append(err_line).append("\n");
sb.append("--");
LOG.warn(sb.toString());
}
@@ -443,8 +444,8 @@ public class PythonSdkType extends SdkType {
}
else {
StringBuffer sb = new StringBuffer();
for (String err_line : run_result.getStderr()) sb.append(err_line).append("\n");
LOG.error("failed to run find_binaries, exit code " + run_result.getExitValue() + ", stderr '" + sb.toString() + "'");
for (String err_line : run_result.getStderrLines()) sb.append(err_line).append("\n");
LOG.error("failed to run find_binaries, exit code " + run_result.getExitCode() + ", stderr '" + sb.toString() + "'");
}
}
finally {
+11 -132
View File
@@ -1,17 +1,15 @@
package com.jetbrains.python.sdk;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -25,41 +23,10 @@ import java.util.regex.Pattern;
public class SdkUtil {
protected static final Logger LOG = Logger.getInstance("#com.jetbrains.python.sdk.SdkVersionUtil");
private static final List<String> NO_LINES = new ArrayList<String>();
private SdkUtil() {
// explicitly none
}
/**
* A holder for stdout and stderr lines of a finished process.
*/
public static class ProcessCallInfo {
private final List<String> myStdoutLines;
private final List<String> myStderrLines;
private final int myExitCode;
public static final int TIMEOUT_CODE = -32768;
protected ProcessCallInfo(List<String> stdout_lines, List<String> stderr_lines, int exit_code) {
myStdoutLines = stdout_lines;
myStderrLines = stderr_lines;
myExitCode = exit_code;
}
public List<String> getStdout() {
return myStdoutLines;
}
public List<String> getStderr() {
return myStderrLines;
}
public int getExitValue() {
return myExitCode;
}
}
/**
* Executes a process and returns its stdout and stderr outputs as lists of lines.
* @param homePath process run directory
@@ -67,7 +34,7 @@ public class SdkUtil {
* @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null.
*/
@NotNull
public static ProcessCallInfo getProcessOutput(String homePath, @NonNls String[] command) {
public static ProcessOutput getProcessOutput(String homePath, @NonNls String[] command) {
return getProcessOutput(homePath, command, -1);
}
@@ -81,110 +48,22 @@ public class SdkUtil {
* the process timed out, exit code is ProcessCallInfo.TIMEOUT_CODE.
*/
@NotNull
public static ProcessCallInfo getProcessOutput(String homePath, @NonNls String[] command, final int timeout) {
public static ProcessOutput getProcessOutput(String homePath, @NonNls String[] command, final int timeout) {
if (homePath == null || !new File(homePath).exists()) {
return new ProcessCallInfo(null, null, -1);
return new ProcessOutput();
}
List<String> stdout = NO_LINES;
List<String> stderr = NO_LINES;
int exit_code = -1;
try {
//noinspection HardCodedStringLiteral
Application app = ApplicationManager.getApplication();
Process process = Runtime.getRuntime().exec(command);
ReadLinesThread stdout_thread = new ReadLinesThread(process.getInputStream());
final Future<?> stdout_future = app.executeOnPooledThread(stdout_thread);
ReadLinesThread stderr_thread = new ReadLinesThread(process.getErrorStream());
final Future<?> stderr_future = app.executeOnPooledThread(stderr_thread);
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicBoolean timed_out = new AtomicBoolean(false);
if (timeout > 0) {
final Thread worker = Thread.currentThread();
Runnable watchdog = new Runnable() {
public void run() {
try {
Thread.sleep(timeout);
if (! done.get()) {
timed_out.set(true);
worker.interrupt();
}
}
catch (InterruptedException ignore) { }
}
};
app.executeOnPooledThread(watchdog);
}
try {
try {
process.waitFor();
}
catch (InterruptedException e) {
if (! timed_out.get()) {
LOG.info(e);
}
process.destroy();
}
}
finally {
done.set(true);
try {
stdout_future.get();
stderr_future.get();
stdout = stdout_thread.getResult();
stderr = stderr_thread.getResult();
if (timed_out.get()){
exit_code = ProcessCallInfo.TIMEOUT_CODE;
}
else {
exit_code = process.exitValue();
}
}
catch (Exception e) {
LOG.info(e);
}
}
Process process = Runtime.getRuntime().exec(command, null, new File(homePath));
CapturingProcessHandler processHandler = new CapturingProcessHandler(process);
return processHandler.runProcess(timeout);
}
catch (IOException ex) {
LOG.info(ex);
return new ProcessOutput();
}
return new ProcessCallInfo(stdout, stderr, exit_code);
}
public static class ReadLinesThread implements Runnable {
private final InputStream myStream;
private final List<String> my_lines = new ArrayList<String>();
protected ReadLinesThread(InputStream stream) {
myStream = stream;
}
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(myStream)); // NOTE: [dch] I wonder if it needs closing
try {
while (true) {
String s = reader.readLine();
if (s == null) break;
my_lines.add(s);
}
reader.close();
}
catch (IOException e) {
LOG.info(e);
}
}
@NotNull
public List<String> getResult() {
return my_lines;
}
}
/**
* Finds the first match in a list os Strings.
* @param lines list of lines, may be null.