Commit c7189fad authored by Vasily Romanikhin's avatar Vasily Romanikhin
Browse files

CPP-10911: CapturingProcessRunner

parent d8d24ab2
Branches unavailable Tags unavailable
No related merge requests found
Showing with 146 additions and 89 deletions
+146 -89
......@@ -17,7 +17,6 @@ package com.intellij.execution.process;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
......@@ -30,13 +29,11 @@ import java.nio.charset.Charset;
* @author yole
*/
public class CapturingProcessHandler extends OSProcessHandler {
private static final Logger LOG = Logger.getInstance(CapturingProcessHandler.class);
private final ProcessOutput myOutput = new ProcessOutput();
private final CapturingProcessRunner myProcessRunner;
public CapturingProcessHandler(@NotNull GeneralCommandLine commandLine) throws ExecutionException {
super(commandLine);
addProcessListener(createProcessAdapter(myOutput));
myProcessRunner = new CapturingProcessRunner(this, processOutput -> createProcessAdapter(processOutput));
}
/** @deprecated Use {@link #CapturingProcessHandler(Process, Charset, String)} instead (to be removed in IDEA 17) */
......@@ -56,31 +53,21 @@ public class CapturingProcessHandler extends OSProcessHandler {
*/
public CapturingProcessHandler(@NotNull Process process, @Nullable Charset charset, /*@NotNull*/ String commandLine) {
super(process, commandLine, charset);
addProcessListener(createProcessAdapter(myOutput));
myProcessRunner = new CapturingProcessRunner(this, processOutput -> createProcessAdapter(processOutput));
}
protected CapturingProcessAdapter createProcessAdapter(ProcessOutput processOutput) {
return new CapturingProcessAdapter(processOutput);
}
@NotNull
public ProcessOutput runProcess() {
startNotify();
if (waitFor()) {
setErrorCodeIfNotYetSet();
}
else {
LOG.info("runProcess: exit value unavailable");
}
return myOutput;
@Override
public Charset getCharset() {
return myCharset != null ? myCharset : super.getCharset();
}
private void setErrorCodeIfNotYetSet() {
// if exit code was set on processTerminated, no need to rewrite it
// WinPtyProcess returns -2 if pty is already closed
if (!myOutput.isExitCodeSet()) {
myOutput.setExitCode(getProcess().exitValue());
}
@NotNull
public ProcessOutput runProcess() {
return myProcessRunner.runProcess();
}
/**
......@@ -89,7 +76,7 @@ public class CapturingProcessHandler extends OSProcessHandler {
* @param timeoutInMilliseconds non-positive means infinity
*/
public ProcessOutput runProcess(int timeoutInMilliseconds) {
return runProcess(timeoutInMilliseconds, true);
return myProcessRunner.runProcess(timeoutInMilliseconds);
}
/**
......@@ -99,83 +86,21 @@ public class CapturingProcessHandler extends OSProcessHandler {
* @param destroyOnTimeout whether to kill the process after timeout passes
*/
public ProcessOutput runProcess(int timeoutInMilliseconds, boolean destroyOnTimeout) {
// keep in sync with runProcessWithProgressIndicator
if (timeoutInMilliseconds <= 0) {
return runProcess();
}
else {
startNotify();
if (waitFor(timeoutInMilliseconds)) {
setErrorCodeIfNotYetSet();
}
else {
if (destroyOnTimeout) {
destroyProcess();
}
myOutput.setTimeout();
}
return myOutput;
}
}
@Override
public Charset getCharset() {
return myCharset != null ? myCharset : super.getCharset();
return myProcessRunner.runProcess(timeoutInMilliseconds, destroyOnTimeout);
}
@NotNull
public ProcessOutput runProcessWithProgressIndicator(@NotNull ProgressIndicator indicator) {
return runProcessWithProgressIndicator(indicator, -1);
return myProcessRunner.runProcess(indicator);
}
@NotNull
public ProcessOutput runProcessWithProgressIndicator(@NotNull ProgressIndicator indicator, int timeoutInMilliseconds) {
return runProcessWithProgressIndicator(indicator, timeoutInMilliseconds, true);
return myProcessRunner.runProcess(indicator, timeoutInMilliseconds);
}
@NotNull
public ProcessOutput runProcessWithProgressIndicator(@NotNull ProgressIndicator indicator, int timeoutInMilliseconds, boolean destroyOnTimeout) {
// keep in sync with runProcess
if (timeoutInMilliseconds <= 0) {
timeoutInMilliseconds = Integer.MAX_VALUE;
}
final int WAIT_INTERVAL = 100;
int waitingTime = 0;
boolean setExitCode = true;
startNotify();
while (!waitFor(WAIT_INTERVAL)) {
waitingTime += WAIT_INTERVAL;
boolean timeout = waitingTime >= timeoutInMilliseconds;
boolean canceled = indicator.isCanceled();
if (canceled || timeout) {
boolean destroying = canceled || destroyOnTimeout;
setExitCode = destroying;
if (destroying && !isProcessTerminating() && !isProcessTerminated()) {
destroyProcess();
}
if (canceled) {
myOutput.setCancelled();
}
else {
myOutput.setTimeout();
}
break;
}
}
if (setExitCode) {
if (waitFor()) {
setErrorCodeIfNotYetSet();
}
else {
LOG.info("runProcess: exit value unavailable");
}
}
return myOutput;
return myProcessRunner.runProcess(indicator, timeoutInMilliseconds, destroyOnTimeout);
}
}
\ No newline at end of file
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.intellij.execution.process;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public class CapturingProcessRunner {
@NotNull private ProcessOutput myOutput;
@NotNull private BaseProcessHandler myProcessHandler;
@NotNull private static final Logger LOG = Logger.getInstance(CapturingProcessRunner.class);
public CapturingProcessRunner(@NotNull BaseProcessHandler processHandler) {
this(processHandler, processOutput -> new CapturingProcessAdapter(processOutput));
}
public CapturingProcessRunner(@NotNull BaseProcessHandler processHandler,
@NotNull Function<ProcessOutput, ProcessAdapter> processAdapterProducer) {
myOutput = new ProcessOutput();
myProcessHandler = processHandler;
myProcessHandler.addProcessListener(processAdapterProducer.apply(myOutput));
}
@NotNull
public ProcessOutput runProcess() {
myProcessHandler.startNotify();
if (myProcessHandler.waitFor()) {
setErrorCodeIfNotYetSet();
}
else {
LOG.info("runProcess: exit value unavailable");
}
return myOutput;
}
@NotNull
public ProcessOutput runProcess(int timeoutInMilliseconds) {
return runProcess(timeoutInMilliseconds, true);
}
@NotNull
public ProcessOutput runProcess(int timeoutInMilliseconds, boolean destroyOnTimeout) {
// keep in sync with runProcessWithProgressIndicator
if (timeoutInMilliseconds <= 0) {
return runProcess();
}
else {
myProcessHandler.startNotify();
if (myProcessHandler.waitFor(timeoutInMilliseconds)) {
setErrorCodeIfNotYetSet();
}
else {
if (destroyOnTimeout) {
myProcessHandler.destroyProcess();
}
myOutput.setTimeout();
}
return myOutput;
}
}
@NotNull
public ProcessOutput runProcess(@NotNull ProgressIndicator indicator) {
return runProcess(indicator, -1);
}
@NotNull
public ProcessOutput runProcess(@NotNull ProgressIndicator indicator, int timeoutInMilliseconds) {
return runProcess(indicator, timeoutInMilliseconds, true);
}
@NotNull
public ProcessOutput runProcess(@NotNull ProgressIndicator indicator,
int timeoutInMilliseconds,
boolean destroyOnTimeout) {
// keep in sync with runProcess
if (timeoutInMilliseconds <= 0) {
timeoutInMilliseconds = Integer.MAX_VALUE;
}
final int WAIT_INTERVAL = 100;
int waitingTime = 0;
boolean setExitCode = true;
myProcessHandler.startNotify();
while (!myProcessHandler.waitFor(WAIT_INTERVAL)) {
waitingTime += WAIT_INTERVAL;
boolean timeout = waitingTime >= timeoutInMilliseconds;
boolean canceled = indicator.isCanceled();
if (canceled || timeout) {
boolean destroying = canceled || destroyOnTimeout;
setExitCode = destroying;
if (destroying && !myProcessHandler.isProcessTerminating() && !myProcessHandler.isProcessTerminated()) {
myProcessHandler.destroyProcess();
}
if (canceled) {
myOutput.setCancelled();
}
else {
myOutput.setTimeout();
}
break;
}
}
if (setExitCode) {
if (myProcessHandler.waitFor()) {
setErrorCodeIfNotYetSet();
}
else {
LOG.info("runProcess: exit value unavailable");
}
}
return myOutput;
}
private void setErrorCodeIfNotYetSet() {
// if exit code was set on processTerminated, no need to rewrite it
// WinPtyProcess returns -2 if pty is already closed
if (!myOutput.isExitCodeSet()) {
myOutput.setExitCode(myProcessHandler.getProcess().exitValue());
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment