mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Extracted base functionality from OSProcessHandler; moved relevant classes to 'util' module
This commit is contained in:
@@ -175,7 +175,11 @@ public class JpsServerManager implements ApplicationComponent{
|
||||
final int port = NetUtils.findAvailableSocketPort();
|
||||
final Process process = launchServer(port);
|
||||
|
||||
final OSProcessHandler processHandler = new OSProcessHandler(process, null);
|
||||
final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
|
||||
protected boolean shouldDestroyProcessRecursively() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
final Ref<String> serverStartMessage = new Ref<String>(null);
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import org.apache.commons.lang.text.StrBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,10 +17,9 @@ package com.intellij.tools;
|
||||
|
||||
import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
|
||||
|
||||
@@ -19,46 +19,19 @@ import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class OSProcessHandler extends ProcessHandler {
|
||||
public class OSProcessHandler extends BaseOSProcessHandler {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.OSProcessHandler");
|
||||
|
||||
@NotNull
|
||||
private final Process myProcess;
|
||||
|
||||
@Nullable
|
||||
private final String myCommandLine;
|
||||
|
||||
private final ProcessWaitFor myWaitFor;
|
||||
|
||||
private static class ExecutorServiceHolder {
|
||||
private static final ExecutorService ourThreadExecutorsService = createServiceImpl();
|
||||
|
||||
private static ThreadPoolExecutor createServiceImpl() {
|
||||
return new ThreadPoolExecutor(10, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "OSProcessHandler pooled thread");
|
||||
}
|
||||
});
|
||||
}
|
||||
public OSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) {
|
||||
super(process, commandLine, EncodingManager.getInstance().getDefaultCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method in order to execute the task with a custom pool
|
||||
*
|
||||
* @param task a task to run
|
||||
*/
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
|
||||
@@ -66,133 +39,7 @@ public class OSProcessHandler extends ProcessHandler {
|
||||
return application.executeOnPooledThread(task);
|
||||
}
|
||||
|
||||
return ExecutorServiceHolder.ourThreadExecutorsService.submit(task);
|
||||
}
|
||||
|
||||
public OSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) {
|
||||
myProcess = process;
|
||||
myCommandLine = commandLine;
|
||||
myWaitFor = new ProcessWaitFor(process);
|
||||
}
|
||||
|
||||
private class ProcessWaitFor {
|
||||
private final Future<?> myWaitForThreadFuture;
|
||||
private final BlockingQueue<Consumer<Integer>> myTerminationCallback = new ArrayBlockingQueue<Consumer<Integer>>(1);
|
||||
|
||||
public void detach() {
|
||||
myWaitForThreadFuture.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
public ProcessWaitFor(final Process process) {
|
||||
myWaitForThreadFuture = executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
int exitCode = 0;
|
||||
try {
|
||||
while (true) {
|
||||
try {
|
||||
exitCode = process.waitFor();
|
||||
break;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
myTerminationCallback.take().consume(exitCode);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTerminationCallback(Consumer<Integer> r) {
|
||||
myTerminationCallback.offer(r);
|
||||
}
|
||||
}
|
||||
|
||||
public Process getProcess() {
|
||||
return myProcess;
|
||||
}
|
||||
|
||||
public void startNotify() {
|
||||
final ReadProcessThread stdoutThread = new ReadProcessThread(createProcessOutReader()) {
|
||||
protected void textAvailable(String s) {
|
||||
notifyTextAvailable(s, ProcessOutputTypes.STDOUT);
|
||||
}
|
||||
};
|
||||
|
||||
final ReadProcessThread stderrThread = new ReadProcessThread(createProcessErrReader()) {
|
||||
protected void textAvailable(String s) {
|
||||
notifyTextAvailable(s, ProcessOutputTypes.STDERR);
|
||||
}
|
||||
};
|
||||
|
||||
if (myCommandLine != null) {
|
||||
notifyTextAvailable(myCommandLine + '\n', ProcessOutputTypes.SYSTEM);
|
||||
}
|
||||
|
||||
addProcessListener(new ProcessAdapter() {
|
||||
public void startNotified(final ProcessEvent event) {
|
||||
try {
|
||||
final Future<?> stdOutReadingFuture = executeOnPooledThread(stdoutThread);
|
||||
final Future<?> stdErrReadingFuture = executeOnPooledThread(stderrThread);
|
||||
|
||||
myWaitFor.setTerminationCallback(new Consumer<Integer>() {
|
||||
@Override
|
||||
public void consume(Integer exitCode) {
|
||||
try {
|
||||
// tell threads that no more attempts to read process' output should be made
|
||||
stderrThread.setProcessTerminated(true);
|
||||
stdoutThread.setProcessTerminated(true);
|
||||
|
||||
stdErrReadingFuture.get();
|
||||
stdOutReadingFuture.get();
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
onOSProcessTerminated(exitCode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
removeProcessListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super.startNotify();
|
||||
}
|
||||
|
||||
protected void onOSProcessTerminated(final int exitCode) {
|
||||
notifyProcessTerminated(exitCode);
|
||||
}
|
||||
|
||||
protected Reader createProcessOutReader() {
|
||||
return new InputStreamReader(myProcess.getInputStream(), getCharset());
|
||||
}
|
||||
|
||||
protected Reader createProcessErrReader() {
|
||||
return new InputStreamReader(myProcess.getErrorStream(), getCharset());
|
||||
}
|
||||
|
||||
protected void destroyProcessImpl() {
|
||||
try {
|
||||
closeStreams();
|
||||
}
|
||||
finally {
|
||||
doDestroyProcess();
|
||||
}
|
||||
return super.executeOnPooledThread(task);
|
||||
}
|
||||
|
||||
protected boolean shouldDestroyProcessRecursively(){
|
||||
@@ -207,141 +54,12 @@ public class OSProcessHandler extends ProcessHandler {
|
||||
final Process process = getProcess();
|
||||
if (shouldDestroyProcessRecursively()) {
|
||||
killProcessTree(process);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
protected void detachProcessImpl() {
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
closeStreams();
|
||||
|
||||
myWaitFor.detach();
|
||||
notifyProcessDetached();
|
||||
}
|
||||
};
|
||||
|
||||
executeOnPooledThread(runnable);
|
||||
}
|
||||
|
||||
protected void closeStreams() {
|
||||
try {
|
||||
myProcess.getOutputStream().close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean detachIsDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public OutputStream getProcessInput() {
|
||||
return myProcess.getOutputStream();
|
||||
}
|
||||
|
||||
// todo: to remove
|
||||
@Nullable
|
||||
public String getCommandLine() {
|
||||
return myCommandLine;
|
||||
}
|
||||
|
||||
|
||||
public Charset getCharset() {
|
||||
return EncodingManager.getInstance().getDefaultCharset();
|
||||
}
|
||||
|
||||
private abstract static class ReadProcessThread implements Runnable {
|
||||
private final Reader myReader;
|
||||
private boolean skipLF = false;
|
||||
|
||||
private boolean myIsProcessTerminated = false;
|
||||
private final char[] myBuffer = new char[8192];
|
||||
|
||||
public ReadProcessThread(final Reader reader) {
|
||||
myReader = reader;
|
||||
}
|
||||
|
||||
public synchronized void setProcessTerminated(boolean isProcessTerminated) {
|
||||
myIsProcessTerminated = isProcessTerminated;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
final int rc = readAvailable();
|
||||
if (rc == DONE) break;
|
||||
Thread.sleep(rc == READ_SOME ? 1 : 5); // give other threads a chance
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int DONE = 0;
|
||||
private static final int READ_SOME = 1;
|
||||
private static final int READ_NONE = 2;
|
||||
|
||||
private synchronized int readAvailable() throws IOException {
|
||||
char[] buffer = myBuffer;
|
||||
StringBuilder token = new StringBuilder();
|
||||
int rc = READ_NONE;
|
||||
while (myReader.ready()) {
|
||||
int n = myReader.read(buffer);
|
||||
if (n <= 0) break;
|
||||
rc = READ_SOME;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = buffer[i];
|
||||
if (skipLF && c != '\n') {
|
||||
token.append('\r');
|
||||
}
|
||||
|
||||
if (c == '\r') {
|
||||
skipLF = true;
|
||||
}
|
||||
else {
|
||||
skipLF = false;
|
||||
token.append(c);
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
textAvailable(token.toString());
|
||||
token.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token.length() != 0) {
|
||||
textAvailable(token.toString());
|
||||
token.setLength(0);
|
||||
}
|
||||
|
||||
if (myIsProcessTerminated) {
|
||||
try {
|
||||
myReader.close();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// supressed
|
||||
}
|
||||
|
||||
return DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
protected abstract void textAvailable(final String s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill whole process tree.
|
||||
* @param process Process
|
||||
@@ -357,5 +75,4 @@ public class OSProcessHandler extends ProcessHandler {
|
||||
}
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.process;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class BaseOSProcessHandler extends ProcessHandler {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.OSProcessHandlerBase");
|
||||
@NotNull
|
||||
protected final Process myProcess;
|
||||
@Nullable
|
||||
protected final String myCommandLine;
|
||||
protected final ProcessWaitFor myWaitFor;
|
||||
@Nullable
|
||||
private final Charset myCharset;
|
||||
|
||||
public BaseOSProcessHandler(@NotNull final Process process, @Nullable final String commandLine, @Nullable Charset charset) {
|
||||
myProcess = process;
|
||||
myCommandLine = commandLine;
|
||||
myCharset = charset;
|
||||
myWaitFor = new ProcessWaitFor(process);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method in order to execute the task with a custom pool
|
||||
*
|
||||
* @param task a task to run
|
||||
*/
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
return ExecutorServiceHolder.ourThreadExecutorsService.submit(task);
|
||||
}
|
||||
|
||||
public Process getProcess() {
|
||||
return myProcess;
|
||||
}
|
||||
|
||||
public void startNotify() {
|
||||
final ReadProcessThread stdoutThread = new ReadProcessThread(createProcessOutReader()) {
|
||||
protected void textAvailable(String s) {
|
||||
notifyTextAvailable(s, ProcessOutputTypes.STDOUT);
|
||||
}
|
||||
};
|
||||
|
||||
final ReadProcessThread stderrThread = new ReadProcessThread(createProcessErrReader()) {
|
||||
protected void textAvailable(String s) {
|
||||
notifyTextAvailable(s, ProcessOutputTypes.STDERR);
|
||||
}
|
||||
};
|
||||
|
||||
if (myCommandLine != null) {
|
||||
notifyTextAvailable(myCommandLine + '\n', ProcessOutputTypes.SYSTEM);
|
||||
}
|
||||
|
||||
addProcessListener(new ProcessAdapter() {
|
||||
public void startNotified(final ProcessEvent event) {
|
||||
try {
|
||||
final Future<?> stdOutReadingFuture = executeOnPooledThread(stdoutThread);
|
||||
final Future<?> stdErrReadingFuture = executeOnPooledThread(stderrThread);
|
||||
|
||||
myWaitFor.setTerminationCallback(new Consumer<Integer>() {
|
||||
@Override
|
||||
public void consume(Integer exitCode) {
|
||||
try {
|
||||
// tell threads that no more attempts to read process' output should be made
|
||||
stderrThread.setProcessTerminated(true);
|
||||
stdoutThread.setProcessTerminated(true);
|
||||
|
||||
stdErrReadingFuture.get();
|
||||
stdOutReadingFuture.get();
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
onOSProcessTerminated(exitCode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
removeProcessListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super.startNotify();
|
||||
}
|
||||
|
||||
protected void onOSProcessTerminated(final int exitCode) {
|
||||
notifyProcessTerminated(exitCode);
|
||||
}
|
||||
|
||||
protected Reader createProcessOutReader() {
|
||||
return createInputStreamReader(myProcess.getInputStream());
|
||||
}
|
||||
|
||||
protected Reader createProcessErrReader() {
|
||||
return createInputStreamReader(myProcess.getErrorStream());
|
||||
}
|
||||
|
||||
private Reader createInputStreamReader(InputStream streamToRead) {
|
||||
final Charset charset = getCharset();
|
||||
if (charset == null) {
|
||||
// use default charset
|
||||
return new InputStreamReader(streamToRead);
|
||||
}
|
||||
return new InputStreamReader(streamToRead, charset);
|
||||
}
|
||||
|
||||
protected void destroyProcessImpl() {
|
||||
try {
|
||||
closeStreams();
|
||||
}
|
||||
finally {
|
||||
doDestroyProcess();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doDestroyProcess() {
|
||||
getProcess().destroy();
|
||||
}
|
||||
|
||||
protected void detachProcessImpl() {
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
closeStreams();
|
||||
|
||||
myWaitFor.detach();
|
||||
notifyProcessDetached();
|
||||
}
|
||||
};
|
||||
|
||||
executeOnPooledThread(runnable);
|
||||
}
|
||||
|
||||
protected void closeStreams() {
|
||||
try {
|
||||
myProcess.getOutputStream().close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean detachIsDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public OutputStream getProcessInput() {
|
||||
return myProcess.getOutputStream();
|
||||
}
|
||||
|
||||
// todo: to remove
|
||||
@Nullable
|
||||
public String getCommandLine() {
|
||||
return myCommandLine;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Charset getCharset() {
|
||||
return myCharset;
|
||||
}
|
||||
|
||||
private static class ExecutorServiceHolder {
|
||||
private static final ExecutorService ourThreadExecutorsService = createServiceImpl();
|
||||
|
||||
private static ThreadPoolExecutor createServiceImpl() {
|
||||
return new ThreadPoolExecutor(10, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "OSProcessHandler pooled thread");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class ReadProcessThread implements Runnable {
|
||||
private final Reader myReader;
|
||||
private boolean skipLF = false;
|
||||
|
||||
private boolean myIsProcessTerminated = false;
|
||||
private final char[] myBuffer = new char[8192];
|
||||
|
||||
public ReadProcessThread(final Reader reader) {
|
||||
myReader = reader;
|
||||
}
|
||||
|
||||
public synchronized void setProcessTerminated(boolean isProcessTerminated) {
|
||||
myIsProcessTerminated = isProcessTerminated;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
final int rc = readAvailable();
|
||||
if (rc == DONE) {
|
||||
break;
|
||||
}
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(rc == READ_SOME ? 1L : 5L); // give other threads a chance
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int DONE = 0;
|
||||
private static final int READ_SOME = 1;
|
||||
private static final int READ_NONE = 2;
|
||||
|
||||
private synchronized int readAvailable() throws IOException {
|
||||
char[] buffer = myBuffer;
|
||||
StringBuilder token = new StringBuilder();
|
||||
int rc = READ_NONE;
|
||||
while (myReader.ready()) {
|
||||
int n = myReader.read(buffer);
|
||||
if (n <= 0) break;
|
||||
rc = READ_SOME;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = buffer[i];
|
||||
if (skipLF && c != '\n') {
|
||||
token.append('\r');
|
||||
}
|
||||
|
||||
if (c == '\r') {
|
||||
skipLF = true;
|
||||
}
|
||||
else {
|
||||
skipLF = false;
|
||||
token.append(c);
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
textAvailable(token.toString());
|
||||
token.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token.length() != 0) {
|
||||
textAvailable(token.toString());
|
||||
token.setLength(0);
|
||||
}
|
||||
|
||||
if (myIsProcessTerminated) {
|
||||
try {
|
||||
myReader.close();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// supressed
|
||||
}
|
||||
|
||||
return DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
protected abstract void textAvailable(final String s);
|
||||
}
|
||||
|
||||
protected class ProcessWaitFor {
|
||||
private final Future<?> myWaitForThreadFuture;
|
||||
private final BlockingQueue<Consumer<Integer>> myTerminationCallback = new ArrayBlockingQueue<Consumer<Integer>>(1);
|
||||
|
||||
public void detach() {
|
||||
myWaitForThreadFuture.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
public ProcessWaitFor(final Process process) {
|
||||
myWaitForThreadFuture = executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
int exitCode = 0;
|
||||
try {
|
||||
while (true) {
|
||||
try {
|
||||
exitCode = process.waitFor();
|
||||
break;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
myTerminationCallback.take().consume(exitCode);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTerminationCallback(Consumer<Integer> r) {
|
||||
myTerminationCallback.offer(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import com.intellij.openapi.compiler.CompilerManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
|
||||
Reference in New Issue
Block a user