mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
platform: added async version of execute() in RunProfileStarter
It allows to create asynchronous run profiles which can be started after BeforeRun tasks (e.g. Build)
This commit is contained in:
@@ -20,6 +20,9 @@ import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
|
||||
import static org.jetbrains.concurrency.Promises.rejectedPromise;
|
||||
|
||||
/**
|
||||
* The callback used to execute a process from the {@link ExecutionManager#startRunProfile(RunProfileStarter, com.intellij.execution.configurations.RunProfileState, com.intellij.execution.runners.ExecutionEnvironment)}
|
||||
@@ -29,4 +32,19 @@ import org.jetbrains.annotations.Nullable;
|
||||
public abstract class RunProfileStarter {
|
||||
@Nullable
|
||||
public abstract RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException;
|
||||
|
||||
/**
|
||||
* Async version of {@link #execute(RunProfileState, ExecutionEnvironment)}.
|
||||
* You must NOT throw exceptions in this method.
|
||||
* Instead return {@link org.jetbrains.concurrency.Promises#rejectedPromise(Throwable)} or call {@link org.jetbrains.concurrency.AsyncPromise#setError(Throwable)}
|
||||
*/
|
||||
public Promise<RunContentDescriptor> executeAsync(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) {
|
||||
try {
|
||||
RunContentDescriptor result = execute(state, environment);
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
return rejectedPromise(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,14 @@ public abstract class AsyncGenericProgramRunner<Settings extends RunnerSettings>
|
||||
@Nullable final Callback callback,
|
||||
@Nullable final RunProfileStarter starter) {
|
||||
ExecutionManager.getInstance(environment.getProject()).startRunProfile(new RunProfileStarter() {
|
||||
@Override
|
||||
public Promise<RunContentDescriptor> executeAsync(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) {
|
||||
if (starter == null) {
|
||||
return Promise.resolve(postProcess(environment, null, callback));
|
||||
}
|
||||
return starter.executeAsync(state, environment).then(descriptor -> postProcess(environment, descriptor, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException {
|
||||
return postProcess(environment, starter == null ? null : starter.execute(state, environment), callback);
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.docking.DockManager;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.SmartList;
|
||||
@@ -377,63 +378,59 @@ public class ExecutionManagerImpl extends ExecutionManager implements Disposable
|
||||
}
|
||||
|
||||
RunProfile profile = environment.getRunProfile();
|
||||
boolean started = false;
|
||||
try {
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarting(executor.getId(), environment);
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarting(executor.getId(), environment);
|
||||
|
||||
final RunContentDescriptor descriptor = starter.execute(state, environment);
|
||||
if (descriptor != null) {
|
||||
final Trinity<RunContentDescriptor, RunnerAndConfigurationSettings, Executor> trinity =
|
||||
Trinity.create(descriptor, environment.getRunnerAndConfigurationSettings(), executor);
|
||||
myRunningConfigurations.add(trinity);
|
||||
Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity));
|
||||
getContentManager().showRunContent(executor, descriptor, environment.getContentToReuse());
|
||||
final ProcessHandler processHandler = descriptor.getProcessHandler();
|
||||
if (processHandler != null) {
|
||||
if (!processHandler.isStartNotified()) {
|
||||
processHandler.startNotify();
|
||||
}
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(executor.getId(), environment, processHandler);
|
||||
started = true;
|
||||
starter.executeAsync(state, environment).done(descriptor -> {
|
||||
AppUIUtil.invokeOnEdt(() -> {
|
||||
if (descriptor != null) {
|
||||
final Trinity<RunContentDescriptor, RunnerAndConfigurationSettings, Executor> trinity =
|
||||
Trinity.create(descriptor, environment.getRunnerAndConfigurationSettings(), executor);
|
||||
myRunningConfigurations.add(trinity);
|
||||
Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity));
|
||||
getContentManager().showRunContent(executor, descriptor, environment.getContentToReuse());
|
||||
final ProcessHandler processHandler = descriptor.getProcessHandler();
|
||||
if (processHandler != null) {
|
||||
if (!processHandler.isStartNotified()) {
|
||||
processHandler.startNotify();
|
||||
}
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(executor.getId(), environment, processHandler);
|
||||
|
||||
ProcessExecutionListener listener = new ProcessExecutionListener(project, executor.getId(), environment, processHandler, descriptor);
|
||||
processHandler.addProcessListener(listener);
|
||||
|
||||
// Since we cannot guarantee that the listener is added before process handled is start notified,
|
||||
// we have to make sure the process termination events are delivered to the clients.
|
||||
// Here we check the current process state and manually deliver events, while
|
||||
// the ProcessExecutionListener guarantees each such event is only delivered once
|
||||
// either by this code, or by the ProcessHandler.
|
||||
ProcessExecutionListener listener = new ProcessExecutionListener(project, executor.getId(), environment, processHandler, descriptor);
|
||||
processHandler.addProcessListener(listener);
|
||||
|
||||
boolean terminating = processHandler.isProcessTerminating();
|
||||
boolean terminated = processHandler.isProcessTerminated();
|
||||
if (terminating || terminated) {
|
||||
listener.processWillTerminate(new ProcessEvent(processHandler), false /*doesn't matter*/);
|
||||
// Since we cannot guarantee that the listener is added before process handled is start notified,
|
||||
// we have to make sure the process termination events are delivered to the clients.
|
||||
// Here we check the current process state and manually deliver events, while
|
||||
// the ProcessExecutionListener guarantees each such event is only delivered once
|
||||
// either by this code, or by the ProcessHandler.
|
||||
|
||||
if (terminated) {
|
||||
//noinspection ConstantConditions
|
||||
int exitCode = processHandler.getExitCode();
|
||||
listener.processTerminated(new ProcessEvent(processHandler, exitCode));
|
||||
boolean terminating = processHandler.isProcessTerminating();
|
||||
boolean terminated = processHandler.isProcessTerminated();
|
||||
if (terminating || terminated) {
|
||||
listener.processWillTerminate(new ProcessEvent(processHandler), false /*doesn't matter*/);
|
||||
|
||||
if (terminated) {
|
||||
//noinspection ConstantConditions
|
||||
int exitCode = processHandler.getExitCode();
|
||||
listener.processTerminated(new ProcessEvent(processHandler, exitCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
environment.setContentToReuse(descriptor);
|
||||
}
|
||||
environment.setContentToReuse(descriptor);
|
||||
else {
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment);
|
||||
}
|
||||
}, o -> project.isDisposed());
|
||||
}).rejected(e -> {
|
||||
if (!(e instanceof ProcessCanceledException)) {
|
||||
ExecutionException error = e instanceof ExecutionException ? (ExecutionException)e : new ExecutionException(e);
|
||||
ExecutionUtil.handleExecutionError(project, ExecutionManager.getInstance(project).getContentManager().getToolWindowIdByEnvironment(environment),
|
||||
profile, error);
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
ExecutionUtil.handleExecutionError(project,
|
||||
ExecutionManager.getInstance(project).getContentManager().getToolWindowIdByEnvironment(environment),
|
||||
profile, e);
|
||||
LOG.info(e);
|
||||
}
|
||||
finally {
|
||||
if (!started) {
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment);
|
||||
}
|
||||
}
|
||||
project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment);
|
||||
});
|
||||
};
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && !myForceCompilationInTests) {
|
||||
|
||||
Reference in New Issue
Block a user