diff --git a/java/execution/impl/intellij.java.execution.impl.iml b/java/execution/impl/intellij.java.execution.impl.iml
index 0873bb1247e0..33b02cfea857 100644
--- a/java/execution/impl/intellij.java.execution.impl.iml
+++ b/java/execution/impl/intellij.java.execution.impl.iml
@@ -29,6 +29,7 @@
+
diff --git a/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java b/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java
index 193c79c00286..1b9f7bc59b41 100644
--- a/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java
+++ b/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskDebugRunner.java
@@ -16,8 +16,16 @@
package com.intellij.openapi.externalSystem.service.execution;
import com.intellij.build.BuildView;
+import com.intellij.debugger.DebugEnvironment;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.DefaultDebugEnvironment;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JavaDebugProcess;
+import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.GenericDebuggerRunner;
+import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
@@ -26,8 +34,14 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.ide.ui.EditorOptionsTopHitProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
+import com.intellij.xdebugger.XDebugProcess;
+import com.intellij.xdebugger.XDebugProcessStarter;
+import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.XDebuggerManager;
+import com.intellij.xdebugger.impl.XDebugSessionImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,6 +53,8 @@ import java.net.ServerSocket;
public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
static final Logger LOG = Logger.getInstance(ExternalSystemTaskDebugRunner.class);
+ private static final String ATTACH_VM_FAILED = "ATTACH_VM_FAILED";
+
@NotNull
@Override
public String getRunnerId() {
@@ -54,11 +70,11 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
@Override
protected RunContentDescriptor createContentDescriptor(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment)
throws ExecutionException {
- if (state instanceof ExternalSystemRunConfiguration.MyRunnableState) {
- ExternalSystemRunConfiguration.MyRunnableState myRunnableState = (ExternalSystemRunConfiguration.MyRunnableState)state;
+ if (state instanceof ExternalSystemRunnableState) {
+ ExternalSystemRunnableState myRunnableState = (ExternalSystemRunnableState)state;
int port = myRunnableState.getDebugPort();
if (port > 0) {
- RunContentDescriptor runContentDescriptor = doGetRunContentDescriptor(myRunnableState, environment, port);
+ RunContentDescriptor runContentDescriptor = doGetRunContentDescriptor(myRunnableState, environment);
if (runContentDescriptor == null) return null;
ProcessHandler processHandler = runContentDescriptor.getProcessHandler();
@@ -76,18 +92,16 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
LOG.warn(String.format(
"Can't attach debugger to external system task execution. Reason: invalid run profile state is provided"
+ "- expected '%s' but got '%s'",
- ExternalSystemRunConfiguration.MyRunnableState.class.getName(), state.getClass().getName()
+ ExternalSystemRunnableState.class.getName(), state.getClass().getName()
));
}
return null;
}
@Nullable
- private RunContentDescriptor doGetRunContentDescriptor(@NotNull ExternalSystemRunConfiguration.MyRunnableState state,
- @NotNull ExecutionEnvironment environment,
- int port) throws ExecutionException {
- RemoteConnection connection = new RemoteConnection(true, "127.0.0.1", String.valueOf(port), true);
- RunContentDescriptor runContentDescriptor = attachVirtualMachine(state, environment, connection, true);
+ private RunContentDescriptor doGetRunContentDescriptor(@NotNull ExternalSystemRunnableState state,
+ @NotNull ExecutionEnvironment environment) throws ExecutionException {
+ RunContentDescriptor runContentDescriptor = createProcessToDebug(state, environment);
if (runContentDescriptor == null) return null;
state.setContentDescriptor(runContentDescriptor);
@@ -109,4 +123,55 @@ public class ExternalSystemTaskDebugRunner extends GenericDebuggerRunner {
descriptor.setRunnerLayoutUi(runContentDescriptor.getRunnerLayoutUi());
return descriptor;
}
+
+ @NotNull
+ private XDebugProcess jvmProcessToDebug(@NotNull XDebugSession session,
+ ExternalSystemRunnableState state,
+ @NotNull ExecutionEnvironment env) throws ExecutionException {
+ RemoteConnection connection = new RemoteConnection(true, "127.0.0.1", String.valueOf(state.getDebugPort()), true);
+ DebugEnvironment environment = new DefaultDebugEnvironment(env, state, connection, DebugEnvironment.LOCAL_START_TIMEOUT);
+
+ final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(env.getProject()).attachVirtualMachine(environment);
+
+ if (debuggerSession == null) {
+ throw new ExecutionException(ATTACH_VM_FAILED);
+ }
+
+ final DebugProcessImpl debugProcess = debuggerSession.getProcess();
+
+
+ XDebugSessionImpl sessionImpl = (XDebugSessionImpl)session;
+ ExecutionResult executionResult = debugProcess.getExecutionResult();
+ sessionImpl.addExtraActions(executionResult.getActions());
+ if (executionResult instanceof DefaultExecutionResult) {
+ sessionImpl.addRestartActions(((DefaultExecutionResult)executionResult).getRestartActions());
+ }
+ return JavaDebugProcess.create(session, debuggerSession);
+ }
+
+ @Nullable
+ private RunContentDescriptor createProcessToDebug(ExternalSystemRunnableState state,
+ @NotNull ExecutionEnvironment env) throws ExecutionException {
+
+ RunContentDescriptor result;
+
+ try {
+ result = XDebuggerManager.getInstance(env.getProject()).startSession(env, new XDebugProcessStarter() {
+ @Override
+ @NotNull
+ public XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
+ XDebugProcess nonJvmDebugProcess = state.startDebugProcess(session, env);
+ return nonJvmDebugProcess != null ? nonJvmDebugProcess : jvmProcessToDebug(session, state, env);
+ }
+ }).getRunContentDescriptor();
+ }
+ catch (ExecutionException e) {
+ if (!e.getMessage().equals(ATTACH_VM_FAILED)) {
+ throw e;
+ }
+ result = null;
+ }
+
+ return result;
+ }
}
diff --git a/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ForkedDebuggerThread.java b/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ForkedDebuggerThread.java
index 585edac80993..373f64818105 100644
--- a/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ForkedDebuggerThread.java
+++ b/java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ForkedDebuggerThread.java
@@ -10,7 +10,6 @@ import com.intellij.debugger.engine.managerThread.DebuggerCommand;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ProgramRunnerUtil;
-import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.impl.ConsoleViewImpl;
@@ -18,8 +17,6 @@ import com.intellij.execution.impl.EditorHyperlinkSupport;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.remote.RemoteConfiguration;
-import com.intellij.execution.remote.RemoteConfigurationType;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.runners.ProgramRunner;
@@ -32,6 +29,8 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.markup.HighlighterLayer;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.externalSystem.debugger.DebuggerBackendExtension;
+import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.StreamUtil;
@@ -64,9 +63,9 @@ class ForkedDebuggerThread extends Thread {
private final ExecutionConsole myMainExecutionConsole;
ForkedDebuggerThread(@NotNull ProcessHandler mainProcessHandler,
- @NotNull RunContentDescriptor mainRunContentDescriptor,
- @NotNull ServerSocket socket,
- @NotNull Project project) {
+ @NotNull RunContentDescriptor mainRunContentDescriptor,
+ @NotNull ServerSocket socket,
+ @NotNull Project project) {
super("external task forked debugger runner");
setDaemon(true);
mySocket = socket;
@@ -122,6 +121,16 @@ class ForkedDebuggerThread extends Thread {
// the stream can not be closed in the current thread
//noinspection IOResourceOpenedButNotSafelyClosed
DataInputStream stream = new DataInputStream(accept.getInputStream());
+
+ String debuggerId = stream.readUTF();
+ String processName = stream.readUTF();
+ String processParameters = stream.readUTF();
+
+ if (processParameters.startsWith(ForkedDebuggerHelper.FINISH_PARAMS)) {
+ removeTerminatedForks(processName, processParameters, accept, stream);
+ return;
+ }
+
myMainProcessHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(@NotNull ProcessEvent event) {
@@ -129,76 +138,78 @@ class ForkedDebuggerThread extends Thread {
StreamUtil.closeStream(accept);
}
});
- int signal = stream.readInt();
- String processName = stream.readUTF();
- if (signal > 0) {
- String debugPort = String.valueOf(signal);
- attachVM(myProject, processName, debugPort, new ProgramRunner.Callback() {
- @Override
- public void processStarted(RunContentDescriptor descriptor) {
- // select tab for the forked process only when it has been suspended
- descriptor.setSelectContentWhenAdded(false);
- // restore selection of the 'main' tab to avoid flickering of the reused content tab when no suspend events occur
- ProcessHandler forkedProcessHandler = descriptor.getProcessHandler();
- if (forkedProcessHandler != null) {
- myMainProcessHandler.addProcessListener(new ProcessAdapter() {
- @Override
- public void processWillTerminate(@NotNull ProcessEvent event, boolean willBeDestroyed) {
- myMainProcessHandler.removeProcessListener(this);
- terminateForkedProcess(forkedProcessHandler);
- }
- });
-
- forkedProcessHandler.addProcessListener(new MyForkedProcessListener(descriptor, processName));
- try {
- accept.getOutputStream().write(0);
- stream.close();
- }
- catch (IOException e) {
- ExternalSystemTaskDebugRunner.LOG.debug(e);
- }
+ for (DebuggerBackendExtension extension : DebuggerBackendExtension.EP_NAME.getExtensionList()) {
+ if (extension.id().equals(debuggerId)) {
+ RunnerAndConfigurationSettings settings = extension.debugConfigurationSettings(myProject, processName, processParameters);
+ runDebugConfiguration(settings, new ProgramRunner.Callback() {
+ @Override
+ public void processStarted(RunContentDescriptor descriptor) {
+ handleStartedDebugConfiguration(descriptor, processName, accept, stream);
}
- }
- });
- }
- else if (signal == 0) {
- // remove content for terminated forked processes
- ApplicationManager.getApplication().invokeLater(() -> {
- final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
- ContentManager contentManager = toolWindowManager.getToolWindow(ToolWindowId.DEBUG).getContentManager();
- Content content = contentManager.findContent(processName);
- if (content != null) {
- RunContentDescriptor descriptor = content.getUserData(RunContentDescriptor.DESCRIPTOR_KEY);
- if (descriptor != null) {
- ProcessHandler handler = descriptor.getProcessHandler();
- if (handler != null) {
- handler.destroyProcess();
- }
- }
- }
- try {
- accept.getOutputStream().write(0);
- stream.close();
- }
- catch (IOException e) {
- ExternalSystemTaskDebugRunner.LOG.debug(e);
- }
- });
+ });
+ break;
+ }
}
}
- private static void attachVM(@NotNull Project project, String runConfigName, @NotNull String debugPort, ProgramRunner.Callback callback) {
- RunnerAndConfigurationSettings runSettings = RunManager.getInstance(project).createConfiguration(runConfigName, RemoteConfigurationType.class);
- runSettings.setActivateToolWindowBeforeRun(false);
-
- RemoteConfiguration configuration = (RemoteConfiguration)runSettings.getConfiguration();
- configuration.HOST = "localhost";
- configuration.PORT = debugPort;
- configuration.USE_SOCKET_TRANSPORT = true;
- configuration.SERVER_MODE = true;
-
+ private void unblockRemote(Socket socket, DataInputStream inputStream) {
try {
+ socket.getOutputStream().write(0);
+ inputStream.close();
+ }
+ catch (IOException e) {
+ ExternalSystemTaskDebugRunner.LOG.debug(e);
+ }
+ }
+
+ private void handleStartedDebugConfiguration(RunContentDescriptor descriptor,
+ String processName,
+ Socket socket,
+ DataInputStream inputStream) {
+ // select tab for the forked process only when it has been suspended
+ descriptor.setSelectContentWhenAdded(false);
+
+ // restore selection of the 'main' tab to avoid flickering of the reused content tab when no suspend events occur
+ ProcessHandler forkedProcessHandler = descriptor.getProcessHandler();
+ if (forkedProcessHandler != null) {
+ myMainProcessHandler.addProcessListener(new ProcessAdapter() {
+ @Override
+ public void processWillTerminate(@NotNull ProcessEvent event, boolean willBeDestroyed) {
+ myMainProcessHandler.removeProcessListener(this);
+ terminateForkedProcess(forkedProcessHandler);
+ }
+ });
+
+ forkedProcessHandler.addProcessListener(new MyForkedProcessListener(descriptor, processName));
+ unblockRemote(socket, inputStream);
+ }
+ }
+
+ private void removeTerminatedForks(@NotNull String processName,
+ @NotNull String processParams,
+ Socket socket,
+ DataInputStream inputStream) {
+ ApplicationManager.getApplication().invokeLater(() -> {
+ final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
+ ContentManager contentManager = toolWindowManager.getToolWindow(ToolWindowId.DEBUG).getContentManager();
+ Content content = contentManager.findContent(processName);
+ if (content != null) {
+ RunContentDescriptor descriptor = content.getUserData(RunContentDescriptor.DESCRIPTOR_KEY);
+ if (descriptor != null) {
+ ProcessHandler handler = descriptor.getProcessHandler();
+ if (handler != null) {
+ handler.destroyProcess();
+ }
+ }
+ }
+ unblockRemote(socket, inputStream);
+ });
+ }
+
+ private static void runDebugConfiguration(@NotNull RunnerAndConfigurationSettings runSettings, ProgramRunner.Callback callback) {
+ try {
+ runSettings.setActivateToolWindowBeforeRun(false);
ExecutionEnvironment environment = ExecutionEnvironmentBuilder.create(DefaultDebugExecutor.getDebugExecutorInstance(), runSettings)
.contentToReuse(null)
.dataContext(null)
@@ -339,7 +350,8 @@ class ForkedDebuggerThread extends Thread {
debugProcess.stop(true);
}
});
- } else {
+ }
+ else {
processHandler.destroyProcess();
}
}
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/debugger/DebuggerBackendExtension.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/debugger/DebuggerBackendExtension.java
new file mode 100644
index 000000000000..e31bee86feb9
--- /dev/null
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/debugger/DebuggerBackendExtension.java
@@ -0,0 +1,43 @@
+// Copyright 2000-2019 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.openapi.externalSystem.debugger;
+
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Provides ability to preconfigure tasks run by external system and to attach them with debugger.
+ */
+public interface DebuggerBackendExtension {
+ ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.externalSystem.debuggerBackend");
+
+ String id();
+
+ default List initializationCode(@NotNull String dispatchPort, @NotNull String parameters) {
+ return new ArrayList();
+ }
+
+ RunnerAndConfigurationSettings debugConfigurationSettings(@NotNull Project project,
+ @NotNull String processName,
+ @NotNull String processParameters);
+
+ default HashMap splitParameters(@NotNull String processParameters) {
+ HashMap result = new HashMap();
+
+ final String[] envVars = processParameters.split(ForkedDebuggerHelper.PARAMETERS_SEPARATOR);
+ for (String envVar : envVars) {
+ final int idx = envVar.indexOf('=');
+ if (idx > -1) {
+ result.put(envVar.substring(0, idx), idx < envVar.length() - 1 ? envVar.substring(idx + 1) : "");
+ }
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/platform/external-system-impl/intellij.platform.externalSystem.impl.iml b/platform/external-system-impl/intellij.platform.externalSystem.impl.iml
index 40b4bcf44189..1a5d2d747a00 100644
--- a/platform/external-system-impl/intellij.platform.externalSystem.impl.iml
+++ b/platform/external-system-impl/intellij.platform.externalSystem.impl.iml
@@ -20,5 +20,6 @@
+
\ No newline at end of file
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
index 4cf5a582ff79..7ad6910e985a 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
@@ -2,51 +2,29 @@
package com.intellij.openapi.externalSystem.service.execution;
import com.intellij.build.*;
-import com.intellij.build.events.BuildEvent;
-import com.intellij.build.events.FailureResult;
-import com.intellij.build.events.impl.FinishBuildEventImpl;
-import com.intellij.build.events.impl.StartBuildEventImpl;
-import com.intellij.build.events.impl.SuccessResultImpl;
import com.intellij.diagnostic.logging.LogConfigurationPanel;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.console.DuplexConsoleView;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.impl.ExecutionManagerImpl;
-import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.FakeRerunAction;
-import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.icons.AllIcons;
-import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.FoldingModel;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
-import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter;
-import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemBuildEvent;
-import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskExecutionEvent;
-import com.intellij.openapi.externalSystem.service.internal.ExternalSystemExecuteTaskTask;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
-import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
-import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
@@ -59,10 +37,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopes;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.net.NetUtils;
import com.intellij.util.text.CharArrayUtil;
-import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.xmlb.Accessor;
import com.intellij.util.xmlb.SerializationFilter;
import com.intellij.util.xmlb.XmlSerializer;
@@ -72,31 +47,24 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
-import java.io.IOException;
import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.ServerSocket;
import java.util.Collections;
-import static com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.DEBUG_FORK_SOCKET_PARAM;
-import static com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.DEBUG_SETUP_PREFIX;
-import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.convert;
-import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.getConsoleManagerFor;
import static com.intellij.openapi.util.text.StringUtil.nullize;
/**
* @author Denis Zhdanov
*/
public class ExternalSystemRunConfiguration extends LocatableConfigurationBase implements SearchScopeProvidingRunProfile {
- private static final ExtensionPointName EP_NAME
+ static final ExtensionPointName EP_NAME
= ExtensionPointName.create("com.intellij.externalSystem.runConfigurationExtension");
public static final Key RUN_INPUT_KEY = Key.create("RUN_INPUT_KEY");
public static final Key> PROGRESS_LISTENER_KEY = Key.create("PROGRESS_LISTENER_KEY");
- private static final Logger LOG = Logger.getInstance(ExternalSystemRunConfiguration.class);
+ static final Logger LOG = Logger.getInstance(ExternalSystemRunConfiguration.class);
private ExternalSystemTaskExecutionSettings mySettings = new ExternalSystemTaskExecutionSettings();
- private static final boolean DISABLE_FORK_DEBUGGER = Boolean.getBoolean("external.system.disable.fork.debugger");
+ static final boolean DISABLE_FORK_DEBUGGER = Boolean.getBoolean("external.system.disable.fork.debugger");
public ExternalSystemRunConfiguration(@NotNull ProjectSystemId externalSystemId,
Project project,
@@ -178,7 +146,8 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) {
// DebugExecutor ID - com.intellij.execution.executors.DefaultDebugExecutor.EXECUTOR_ID
String debugExecutorId = ToolWindowId.DEBUG;
- MyRunnableState runnableState = new MyRunnableState(mySettings, getProject(), debugExecutorId.equals(executor.getId()), this, env);
+ ExternalSystemRunnableState
+ runnableState = new ExternalSystemRunnableState(mySettings, getProject(), debugExecutorId.equals(executor.getId()), this, env);
copyUserDataTo(runnableState);
return runnableState;
}
@@ -203,264 +172,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
return scope;
}
- public static class MyRunnableState extends UserDataHolderBase implements RunProfileState {
-
- @NotNull private final ExternalSystemTaskExecutionSettings mySettings;
- @NotNull private final Project myProject;
- @NotNull private final ExternalSystemRunConfiguration myConfiguration;
- @NotNull private final ExecutionEnvironment myEnv;
- @Nullable private RunContentDescriptor myContentDescriptor;
-
- private final int myDebugPort;
- private ServerSocket myForkSocket = null;
-
- public MyRunnableState(@NotNull ExternalSystemTaskExecutionSettings settings,
- @NotNull Project project,
- boolean debug,
- @NotNull ExternalSystemRunConfiguration configuration,
- @NotNull ExecutionEnvironment env) {
- mySettings = settings;
- myProject = project;
- myConfiguration = configuration;
- myEnv = env;
- int port;
- if (debug) {
- try {
- port = NetUtils.findAvailableSocketPort();
- }
- catch (IOException e) {
- LOG.warn("Unexpected I/O exception occurred on attempt to find a free port to use for external system task debugging", e);
- port = 0;
- }
- }
- else {
- port = 0;
- }
- myDebugPort = port;
- }
-
- public int getDebugPort() {
- return myDebugPort;
- }
-
- @Nullable
- public ServerSocket getForkSocket() {
- if (myForkSocket == null && !DISABLE_FORK_DEBUGGER) {
- try {
- myForkSocket = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- return myForkSocket;
- }
-
- @Nullable
- @Override
- public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
- if (myProject.isDisposed()) return null;
-
- String jvmParametersSetup = getJvmParametersSetup();
-
- ApplicationManager.getApplication().assertIsDispatchThread();
- FileDocumentManager.getInstance().saveAllDocuments();
-
- final ExternalSystemExecuteTaskTask task = new ExternalSystemExecuteTaskTask(myProject, mySettings, jvmParametersSetup);
- copyUserDataTo(task);
-
- final String executionName = StringUtil.isNotEmpty(mySettings.getExecutionName())
- ? mySettings.getExecutionName()
- : StringUtil.isNotEmpty(myConfiguration.getName())
- ? myConfiguration.getName() : AbstractExternalSystemTaskConfigurationType.generateName(
- myProject, mySettings.getExternalSystemId(), mySettings.getExternalProjectPath(),
- mySettings.getTaskNames(), mySettings.getExecutionName(), ": ", "");
-
- final ExternalSystemProcessHandler processHandler = new ExternalSystemProcessHandler(task, executionName);
- final ExternalSystemExecutionConsoleManager
- consoleManager = getConsoleManagerFor(task);
-
- final ExecutionConsole consoleView =
- consoleManager.attachExecutionConsole(myProject, task, myEnv, processHandler);
- AnAction[] restartActions;
- if (consoleView == null) {
- restartActions = AnAction.EMPTY_ARRAY;
- Disposer.register(myProject, processHandler);
- }
- else {
- Disposer.register(myProject, consoleView);
- Disposer.register(consoleView, processHandler);
- restartActions = consoleManager.getRestartActions(consoleView);
- }
- Class extends BuildProgressListener> progressListenerClazz = task.getUserData(PROGRESS_LISTENER_KEY);
- final BuildProgressListener progressListener =
- progressListenerClazz != null ? ServiceManager.getService(myProject, progressListenerClazz)
- : createBuildView(task.getId(), executionName, task.getExternalProjectPath(), consoleView);
-
- EP_NAME.forEachExtensionSafe(extension -> extension.attachToProcess(myConfiguration, processHandler, myEnv.getRunnerSettings()));
-
- ApplicationManager.getApplication().executeOnPooledThread(() -> {
- final String startDateTime = DateFormatUtil.formatTimeWithSeconds(System.currentTimeMillis());
- final String greeting;
- final String settingsDescription = StringUtil.isEmpty(mySettings.toString()) ? "" : String.format(" '%s'", mySettings.toString());
- if (mySettings.getTaskNames().size() > 1) {
- greeting = ExternalSystemBundle.message("run.text.starting.multiple.task", startDateTime, settingsDescription) + "\n";
- }
- else {
- greeting = ExternalSystemBundle.message("run.text.starting.single.task", startDateTime, settingsDescription) + "\n";
- }
- processHandler.notifyTextAvailable(greeting + "\n", ProcessOutputTypes.SYSTEM);
- try (BuildEventDispatcher eventDispatcher = new ExternalSystemEventDispatcher(task.getId(), progressListener, false)) {
- ExternalSystemTaskNotificationListenerAdapter taskListener = new ExternalSystemTaskNotificationListenerAdapter() {
- @Override
- public void onStart(@NotNull ExternalSystemTaskId id, String workingDir) {
- if (progressListener != null) {
- long eventTime = System.currentTimeMillis();
- AnAction rerunTaskAction = new MyTaskRerunAction(progressListener, myEnv, myContentDescriptor);
- BuildViewSettingsProvider viewSettingsProvider =
- consoleView instanceof BuildViewSettingsProvider ?
- new BuildViewSettingsProviderAdapter((BuildViewSettingsProvider)consoleView) : null;
- progressListener.onEvent(id,
- new StartBuildEventImpl(new DefaultBuildDescriptor(id, executionName, workingDir, eventTime), "running...")
- .withProcessHandler(processHandler, view -> foldGreetingOrFarewell(consoleView, greeting, true))
- .withContentDescriptorSupplier(() -> myContentDescriptor)
- .withRestartAction(rerunTaskAction)
- .withRestartActions(restartActions)
- .withExecutionEnvironment(myEnv)
- .withBuildViewSettingsProvider(viewSettingsProvider)
- );
- }
- }
-
- @Override
- public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
- if (consoleView != null) {
- consoleManager.onOutput(consoleView, processHandler, text, stdOut ? ProcessOutputTypes.STDOUT : ProcessOutputTypes.STDERR);
- }
- else {
- processHandler.notifyTextAvailable(text, stdOut ? ProcessOutputTypes.STDOUT : ProcessOutputTypes.STDERR);
- }
- eventDispatcher.setStdOut(stdOut);
- eventDispatcher.append(text);
- }
-
- @Override
- public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) {
- FailureResult failureResult =
- ExternalSystemUtil.createFailureResult(executionName + " failed", e, id.getProjectSystemId(), myProject);
- eventDispatcher.onEvent(id, new FinishBuildEventImpl(id, null, System.currentTimeMillis(), "failed", failureResult));
- processHandler.notifyProcessTerminated(1);
- }
-
- @Override
- public void onSuccess(@NotNull ExternalSystemTaskId id) {
- eventDispatcher.onEvent(id, new FinishBuildEventImpl(
- id, null, System.currentTimeMillis(), "successful", new SuccessResultImpl()));
- }
-
- @Override
- public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
- if (event instanceof ExternalSystemBuildEvent) {
- eventDispatcher.onEvent(event.getId(), ((ExternalSystemBuildEvent)event).getBuildEvent());
- }
- else if (event instanceof ExternalSystemTaskExecutionEvent) {
- BuildEvent buildEvent = convert(((ExternalSystemTaskExecutionEvent)event));
- eventDispatcher.onEvent(event.getId(), buildEvent);
- }
- }
-
- @Override
- public void onEnd(@NotNull ExternalSystemTaskId id) {
- final String endDateTime = DateFormatUtil.formatTimeWithSeconds(System.currentTimeMillis());
- final String farewell;
- if (mySettings.getTaskNames().size() > 1) {
- farewell = ExternalSystemBundle.message("run.text.ended.multiple.task", endDateTime, settingsDescription);
- }
- else {
- farewell = ExternalSystemBundle.message("run.text.ended.single.task", endDateTime, settingsDescription);
- }
- processHandler.notifyTextAvailable(farewell + "\n", ProcessOutputTypes.SYSTEM);
- foldGreetingOrFarewell(consoleView, farewell, false);
- processHandler.notifyProcessTerminated(0);
- eventDispatcher.close();
- }
- };
- task.execute(ArrayUtil.prepend(taskListener, ExternalSystemTaskNotificationListener.EP_NAME.getExtensions()));
- }
- });
- ExecutionConsole executionConsole = progressListener instanceof ExecutionConsole ? (ExecutionConsole)progressListener : consoleView;
- DefaultActionGroup actionGroup = new DefaultActionGroup();
- if (executionConsole instanceof BuildView) {
- actionGroup.addAll(((BuildView)executionConsole).getSwitchActions());
- actionGroup.add(BuildTreeFilters.createFilteringActionsGroup((BuildView)executionConsole));
- }
- DefaultExecutionResult executionResult = new DefaultExecutionResult(executionConsole, processHandler, actionGroup.getChildren(null));
- executionResult.setRestartActions(restartActions);
- return executionResult;
- }
-
- @Nullable
- private String getJvmParametersSetup() throws ExecutionException {
- final SimpleJavaParameters extensionsJP = new SimpleJavaParameters();
- EP_NAME.forEachExtensionSafe(
- extension -> extension.updateVMParameters(myConfiguration, extensionsJP, myEnv.getRunnerSettings(), myEnv.getExecutor()));
- String jvmParametersSetup;
- if (myDebugPort > 0) {
- jvmParametersSetup = DEBUG_SETUP_PREFIX + myDebugPort;
- if (getForkSocket() != null) {
- jvmParametersSetup += (" " + DEBUG_FORK_SOCKET_PARAM + getForkSocket().getLocalPort());
- }
- }
- else {
- final ParametersList allVMParameters = new ParametersList();
- final ParametersList data = myEnv.getUserData(ExternalSystemTaskExecutionSettings.JVM_AGENT_SETUP_KEY);
- if (data != null) {
- for (String parameter : data.getList()) {
- if (parameter.startsWith("-agentlib:")) continue;
- if (parameter.startsWith("-agentpath:")) continue;
- if (parameter.startsWith("-javaagent:")) continue;
- throw new ExecutionException(ExternalSystemBundle.message("run.invalid.jvm.agent.configuration", parameter));
- }
- allVMParameters.addAll(data.getParameters());
- }
- allVMParameters.addAll(extensionsJP.getVMParametersList().getParameters());
- jvmParametersSetup = allVMParameters.getParametersString();
- }
- return nullize(jvmParametersSetup);
- }
-
- private BuildProgressListener createBuildView(ExternalSystemTaskId id,
- String executionName,
- String workingDir,
- ExecutionConsole executionConsole) {
- BuildDescriptor buildDescriptor = new DefaultBuildDescriptor(id, executionName, workingDir, System.currentTimeMillis());
- return new BuildView(myProject, executionConsole, buildDescriptor, "build.toolwindow.run.selection.state",
- new ViewManager() {
- @Override
- public boolean isConsoleEnabledByDefault() {
- return true;
- }
-
- @Override
- public boolean isBuildContentView() {
- return false;
- }
- });
- }
-
- public void setContentDescriptor(@Nullable RunContentDescriptor contentDescriptor) {
- myContentDescriptor = contentDescriptor;
- if (contentDescriptor != null) {
- contentDescriptor.setExecutionId(myEnv.getExecutionId());
- RunnerAndConfigurationSettings settings = myEnv.getRunnerAndConfigurationSettings();
- if (settings != null) {
- contentDescriptor.setActivateToolWindowWhenAdded(settings.isActivateToolWindowBeforeRun());
- }
- }
- }
- }
-
- private static void foldGreetingOrFarewell(@Nullable ExecutionConsole consoleView, String text, boolean isGreeting) {
+ static void foldGreetingOrFarewell(@Nullable ExecutionConsole consoleView, String text, boolean isGreeting) {
int limit = 100;
if (text.length() < limit) {
return;
@@ -505,7 +217,7 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
}
}
- private static class MyTaskRerunAction extends FakeRerunAction {
+ static class MyTaskRerunAction extends FakeRerunAction {
private final BuildProgressListener myProgressListener;
private final RunContentDescriptor myContentDescriptor;
private final ExecutionEnvironment myEnvironment;
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunnableState.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunnableState.java
new file mode 100644
index 000000000000..1deca11c70dd
--- /dev/null
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunnableState.java
@@ -0,0 +1,324 @@
+// Copyright 2000-2019 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.openapi.externalSystem.service.execution;
+
+import com.intellij.build.*;
+import com.intellij.build.events.BuildEvent;
+import com.intellij.build.events.FailureResult;
+import com.intellij.build.events.impl.FinishBuildEventImpl;
+import com.intellij.build.events.impl.StartBuildEventImpl;
+import com.intellij.build.events.impl.SuccessResultImpl;
+import com.intellij.execution.*;
+import com.intellij.execution.configurations.ParametersList;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.SimpleJavaParameters;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.ui.ExecutionConsole;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager;
+import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter;
+import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemBuildEvent;
+import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskExecutionEvent;
+import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper;
+import com.intellij.openapi.externalSystem.service.internal.ExternalSystemExecuteTaskTask;
+import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.net.NetUtils;
+import com.intellij.util.text.DateFormatUtil;
+import com.intellij.xdebugger.XDebugProcess;
+import com.intellij.xdebugger.XDebugSession;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+
+import static com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.DEBUG_FORK_SOCKET_PARAM;
+import static com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX;
+import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.convert;
+import static com.intellij.openapi.externalSystem.util.ExternalSystemUtil.getConsoleManagerFor;
+import static com.intellij.openapi.util.text.StringUtil.nullize;
+
+public class ExternalSystemRunnableState extends UserDataHolderBase implements RunProfileState {
+
+ @NotNull private final ExternalSystemTaskExecutionSettings mySettings;
+ @NotNull private final Project myProject;
+ @NotNull private final ExternalSystemRunConfiguration myConfiguration;
+ @NotNull private final ExecutionEnvironment myEnv;
+ @Nullable private RunContentDescriptor myContentDescriptor;
+
+ private final int myDebugPort;
+ private ServerSocket myForkSocket = null;
+
+ public ExternalSystemRunnableState(@NotNull ExternalSystemTaskExecutionSettings settings,
+ @NotNull Project project,
+ boolean debug,
+ @NotNull ExternalSystemRunConfiguration configuration,
+ @NotNull ExecutionEnvironment env) {
+ mySettings = settings;
+ myProject = project;
+ myConfiguration = configuration;
+ myEnv = env;
+ int port;
+ if (debug) {
+ try {
+ port = NetUtils.findAvailableSocketPort();
+ }
+ catch (IOException e) {
+ ExternalSystemRunConfiguration.LOG
+ .warn("Unexpected I/O exception occurred on attempt to find a free port to use for external system task debugging", e);
+ port = 0;
+ }
+ }
+ else {
+ port = 0;
+ }
+ myDebugPort = port;
+ }
+
+ public int getDebugPort() {
+ return myDebugPort;
+ }
+
+ @Nullable
+ public ServerSocket getForkSocket() {
+ if (myForkSocket == null && !ExternalSystemRunConfiguration.DISABLE_FORK_DEBUGGER) {
+ try {
+ myForkSocket = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
+ }
+ catch (IOException e) {
+ ExternalSystemRunConfiguration.LOG.error(e);
+ }
+ }
+ return myForkSocket;
+ }
+
+ @Nullable
+ @Override
+ public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
+ if (myProject.isDisposed()) return null;
+
+ String jvmParametersSetup = getJvmParametersSetup();
+
+ ApplicationManager.getApplication().assertIsDispatchThread();
+ FileDocumentManager.getInstance().saveAllDocuments();
+
+ final ExternalSystemExecuteTaskTask task = new ExternalSystemExecuteTaskTask(myProject, mySettings, jvmParametersSetup);
+ copyUserDataTo(task);
+
+ final String executionName = StringUtil.isNotEmpty(mySettings.getExecutionName())
+ ? mySettings.getExecutionName()
+ : StringUtil.isNotEmpty(myConfiguration.getName())
+ ? myConfiguration.getName() : AbstractExternalSystemTaskConfigurationType.generateName(
+ myProject, mySettings.getExternalSystemId(), mySettings.getExternalProjectPath(),
+ mySettings.getTaskNames(), mySettings.getExecutionName(), ": ", "");
+
+ final ExternalSystemProcessHandler processHandler = new ExternalSystemProcessHandler(task, executionName);
+ final ExternalSystemExecutionConsoleManager
+ consoleManager = getConsoleManagerFor(task);
+
+ final ExecutionConsole consoleView =
+ consoleManager.attachExecutionConsole(myProject, task, myEnv, processHandler);
+ AnAction[] restartActions;
+ if (consoleView == null) {
+ restartActions = AnAction.EMPTY_ARRAY;
+ Disposer.register(myProject, processHandler);
+ }
+ else {
+ Disposer.register(myProject, consoleView);
+ Disposer.register(consoleView, processHandler);
+ restartActions = consoleManager.getRestartActions(consoleView);
+ }
+ Class extends BuildProgressListener> progressListenerClazz = task.getUserData(ExternalSystemRunConfiguration.PROGRESS_LISTENER_KEY);
+ final BuildProgressListener progressListener =
+ progressListenerClazz != null ? ServiceManager.getService(myProject, progressListenerClazz)
+ : createBuildView(task.getId(), executionName, task.getExternalProjectPath(), consoleView);
+
+ ExternalSystemRunConfiguration.EP_NAME
+ .forEachExtensionSafe(extension -> extension.attachToProcess(myConfiguration, processHandler, myEnv.getRunnerSettings()));
+
+ ApplicationManager.getApplication().executeOnPooledThread(() -> {
+ final String startDateTime = DateFormatUtil.formatTimeWithSeconds(System.currentTimeMillis());
+ final String greeting;
+ final String settingsDescription = StringUtil.isEmpty(mySettings.toString()) ? "" : String.format(" '%s'", mySettings.toString());
+ if (mySettings.getTaskNames().size() > 1) {
+ greeting = ExternalSystemBundle.message("run.text.starting.multiple.task", startDateTime, settingsDescription) + "\n";
+ }
+ else {
+ greeting = ExternalSystemBundle.message("run.text.starting.single.task", startDateTime, settingsDescription) + "\n";
+ }
+ processHandler.notifyTextAvailable(greeting + "\n", ProcessOutputTypes.SYSTEM);
+ try (BuildEventDispatcher eventDispatcher = new ExternalSystemEventDispatcher(task.getId(), progressListener, false)) {
+ ExternalSystemTaskNotificationListenerAdapter taskListener = new ExternalSystemTaskNotificationListenerAdapter() {
+ @Override
+ public void onStart(@NotNull ExternalSystemTaskId id, String workingDir) {
+ if (progressListener != null) {
+ long eventTime = System.currentTimeMillis();
+ AnAction rerunTaskAction = new ExternalSystemRunConfiguration.MyTaskRerunAction(progressListener, myEnv, myContentDescriptor);
+ BuildViewSettingsProvider viewSettingsProvider =
+ consoleView instanceof BuildViewSettingsProvider ?
+ new BuildViewSettingsProviderAdapter((BuildViewSettingsProvider)consoleView) : null;
+ progressListener.onEvent(id,
+ new StartBuildEventImpl(new DefaultBuildDescriptor(id, executionName, workingDir, eventTime),
+ "running...")
+ .withProcessHandler(processHandler, view -> ExternalSystemRunConfiguration
+ .foldGreetingOrFarewell(consoleView, greeting, true))
+ .withContentDescriptorSupplier(() -> myContentDescriptor)
+ .withRestartAction(rerunTaskAction)
+ .withRestartActions(restartActions)
+ .withExecutionEnvironment(myEnv)
+ .withBuildViewSettingsProvider(viewSettingsProvider)
+ );
+ }
+ }
+
+ @Override
+ public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
+ if (consoleView != null) {
+ consoleManager.onOutput(consoleView, processHandler, text, stdOut ? ProcessOutputTypes.STDOUT : ProcessOutputTypes.STDERR);
+ }
+ else {
+ processHandler.notifyTextAvailable(text, stdOut ? ProcessOutputTypes.STDOUT : ProcessOutputTypes.STDERR);
+ }
+ eventDispatcher.setStdOut(stdOut);
+ eventDispatcher.append(text);
+ }
+
+ @Override
+ public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) {
+ FailureResult failureResult =
+ ExternalSystemUtil.createFailureResult(executionName + " failed", e, id.getProjectSystemId(), myProject);
+ eventDispatcher.onEvent(id, new FinishBuildEventImpl(id, null, System.currentTimeMillis(), "failed", failureResult));
+ processHandler.notifyProcessTerminated(1);
+ }
+
+ @Override
+ public void onSuccess(@NotNull ExternalSystemTaskId id) {
+ eventDispatcher.onEvent(id, new FinishBuildEventImpl(
+ id, null, System.currentTimeMillis(), "successful", new SuccessResultImpl()));
+ }
+
+ @Override
+ public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
+ if (event instanceof ExternalSystemBuildEvent) {
+ eventDispatcher.onEvent(event.getId(), ((ExternalSystemBuildEvent)event).getBuildEvent());
+ }
+ else if (event instanceof ExternalSystemTaskExecutionEvent) {
+ BuildEvent buildEvent = convert(((ExternalSystemTaskExecutionEvent)event));
+ eventDispatcher.onEvent(event.getId(), buildEvent);
+ }
+ }
+
+ @Override
+ public void onEnd(@NotNull ExternalSystemTaskId id) {
+ final String endDateTime = DateFormatUtil.formatTimeWithSeconds(System.currentTimeMillis());
+ final String farewell;
+ if (mySettings.getTaskNames().size() > 1) {
+ farewell = ExternalSystemBundle.message("run.text.ended.multiple.task", endDateTime, settingsDescription);
+ }
+ else {
+ farewell = ExternalSystemBundle.message("run.text.ended.single.task", endDateTime, settingsDescription);
+ }
+ processHandler.notifyTextAvailable(farewell + "\n", ProcessOutputTypes.SYSTEM);
+ ExternalSystemRunConfiguration.foldGreetingOrFarewell(consoleView, farewell, false);
+ processHandler.notifyProcessTerminated(0);
+ eventDispatcher.close();
+ }
+ };
+ task.execute(ArrayUtil.prepend(taskListener, ExternalSystemTaskNotificationListener.EP_NAME.getExtensions()));
+ }
+ });
+ ExecutionConsole executionConsole = progressListener instanceof ExecutionConsole ? (ExecutionConsole)progressListener : consoleView;
+ DefaultActionGroup actionGroup = new DefaultActionGroup();
+ if (executionConsole instanceof BuildView) {
+ actionGroup.addAll(((BuildView)executionConsole).getSwitchActions());
+ actionGroup.add(BuildTreeFilters.createFilteringActionsGroup((BuildView)executionConsole));
+ }
+ DefaultExecutionResult executionResult = new DefaultExecutionResult(executionConsole, processHandler, actionGroup.getChildren(null));
+ executionResult.setRestartActions(restartActions);
+ return executionResult;
+ }
+
+ @Nullable
+ private String getJvmParametersSetup() throws ExecutionException {
+ final SimpleJavaParameters extensionsJP = new SimpleJavaParameters();
+ ExternalSystemRunConfiguration.EP_NAME.forEachExtensionSafe(
+ extension -> extension.updateVMParameters(myConfiguration, extensionsJP, myEnv.getRunnerSettings(), myEnv.getExecutor()));
+ String jvmParametersSetup;
+ if (myDebugPort > 0) {
+ jvmParametersSetup = ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX + myDebugPort;
+ if (getForkSocket() != null) {
+ jvmParametersSetup += (" " + DEBUG_FORK_SOCKET_PARAM + getForkSocket().getLocalPort());
+ }
+ }
+ else {
+ final ParametersList allVMParameters = new ParametersList();
+ final ParametersList data = myEnv.getUserData(ExternalSystemTaskExecutionSettings.JVM_AGENT_SETUP_KEY);
+ if (data != null) {
+ for (String parameter : data.getList()) {
+ if (parameter.startsWith("-agentlib:")) continue;
+ if (parameter.startsWith("-agentpath:")) continue;
+ if (parameter.startsWith("-javaagent:")) continue;
+ throw new ExecutionException(ExternalSystemBundle.message("run.invalid.jvm.agent.configuration", parameter));
+ }
+ allVMParameters.addAll(data.getParameters());
+ }
+ allVMParameters.addAll(extensionsJP.getVMParametersList().getParameters());
+ jvmParametersSetup = allVMParameters.getParametersString();
+ }
+ return nullize(jvmParametersSetup);
+ }
+
+ private BuildProgressListener createBuildView(ExternalSystemTaskId id,
+ String executionName,
+ String workingDir,
+ ExecutionConsole executionConsole) {
+ BuildDescriptor buildDescriptor = new DefaultBuildDescriptor(id, executionName, workingDir, System.currentTimeMillis());
+ return new BuildView(myProject, executionConsole, buildDescriptor, "build.toolwindow.run.selection.state",
+ new ViewManager() {
+ @Override
+ public boolean isConsoleEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public boolean isBuildContentView() {
+ return false;
+ }
+ });
+ }
+
+ public void setContentDescriptor(@Nullable RunContentDescriptor contentDescriptor) {
+ myContentDescriptor = contentDescriptor;
+ if (contentDescriptor != null) {
+ contentDescriptor.setExecutionId(myEnv.getExecutionId());
+ RunnerAndConfigurationSettings settings = myEnv.getRunnerAndConfigurationSettings();
+ if (settings != null) {
+ contentDescriptor.setActivateToolWindowWhenAdded(settings.isActivateToolWindowBeforeRun());
+ }
+ }
+ }
+
+ @Nullable
+ public XDebugProcess startDebugProcess(@NotNull XDebugSession session,
+ @NotNull ExecutionEnvironment env) {
+ return null;
+ }
+}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt
index 576b13c901c9..e3620c395106 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskRunner.kt
@@ -43,7 +43,7 @@ class ExternalSystemTaskRunner : GenericProgramRunner() {
@Throws(ExecutionException::class)
override fun doExecute(state: RunProfileState, environment: ExecutionEnvironment): RunContentDescriptor? {
- if (state !is ExternalSystemRunConfiguration.MyRunnableState && state !is HistoryTestRunnableState) {
+ if (state !is ExternalSystemRunnableState && state !is HistoryTestRunnableState) {
return null
}
@@ -54,7 +54,7 @@ class ExternalSystemTaskRunner : GenericProgramRunner() {
return runContentDescriptor
}
- (state as ExternalSystemRunConfiguration.MyRunnableState).setContentDescriptor(runContentDescriptor)
+ (state as ExternalSystemRunnableState).setContentDescriptor(runContentDescriptor)
if (executionResult.executionConsole is BuildView) {
return runContentDescriptor
}
diff --git a/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerConfiguration.java b/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerConfiguration.java
index c9bfac482653..3c88742e982a 100644
--- a/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerConfiguration.java
+++ b/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerConfiguration.java
@@ -25,13 +25,13 @@ public class ForkedDebuggerConfiguration {
@Nullable
public static ForkedDebuggerConfiguration parse(@Nullable String jvmAgentSetup) {
- if (jvmAgentSetup != null && jvmAgentSetup.startsWith(ForkedDebuggerHelper.DEBUG_SETUP_PREFIX)) {
+ if (jvmAgentSetup != null && jvmAgentSetup.startsWith(ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX)) {
int forkSocketIndex = jvmAgentSetup.indexOf(ForkedDebuggerHelper.DEBUG_FORK_SOCKET_PARAM);
if (forkSocketIndex > 0) {
try {
int forkSocketPort =
Integer.parseInt(jvmAgentSetup.substring(forkSocketIndex + ForkedDebuggerHelper.DEBUG_FORK_SOCKET_PARAM.length()));
- int debugPort = Integer.parseInt(jvmAgentSetup.substring(ForkedDebuggerHelper.DEBUG_SETUP_PREFIX.length(), forkSocketIndex - 1));
+ int debugPort = Integer.parseInt(jvmAgentSetup.substring(ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX.length(), forkSocketIndex - 1));
return new ForkedDebuggerConfiguration(forkSocketPort, debugPort);
}
catch (NumberFormatException ignore) {
@@ -42,6 +42,6 @@ public class ForkedDebuggerConfiguration {
}
public String getJvmAgentSetup(boolean isJdk9orLater) {
- return ForkedDebuggerHelper.DEBUG_SETUP_PREFIX + (isJdk9orLater ? "127.0.0.1:" : "") + myDebugPort;
+ return ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX + (isJdk9orLater ? "127.0.0.1:" : "") + myDebugPort;
}
}
diff --git a/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerHelper.java b/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerHelper.java
index db47d2c9c925..5c098ceca4f9 100644
--- a/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerHelper.java
+++ b/platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerHelper.java
@@ -11,51 +11,57 @@ import java.net.Socket;
*/
public class ForkedDebuggerHelper {
- public static final String DEBUG_SETUP_PREFIX = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=";
+ public static final String JVM_DEBUG_SETUP_PREFIX = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=";
public static final String DEBUG_FORK_SOCKET_PARAM = "-forkSocket";
- public static String setupDebugger(String processName, int debugPort) {
- String setup = "";
+ public static final String DEBUG_SERVER_PORT_KEY = "DEBUG_SERVER_PORT";
+ public static final String PARAMETERS_SEPARATOR = ";";
+
+ public static final String FINISH_PARAMS = "FINISH_PARAMS";
+
+ // returns port at which debugger is supposed to communicate with debuggee process
+ public static int setupDebugger(String debuggerId, String processName, String processParameters, int dispatchPort) {
+ int port = 0;
try {
- if (debugPort > -1) {
- int debugAddress = findAvailableSocketPort();
- if (debugAddress > -1) {
- setup = DEBUG_SETUP_PREFIX + debugAddress;
- send(debugAddress, processName, debugPort);
- }
- }
+ port = findAvailableSocketPort();
+ processParameters = (processParameters == null || processParameters.isEmpty()) ? "" : processParameters + PARAMETERS_SEPARATOR;
+ processParameters = processParameters + DEBUG_SERVER_PORT_KEY + "=" + port;
+ send(debuggerId, processName, processParameters, dispatchPort);
}
- catch (Exception e) {
+ catch (IOException e) {
//noinspection CallToPrintStackTrace
e.printStackTrace();
}
- return setup;
+ return port;
}
- public static void processFinished(String processName, int debugPort) {
- send(0, processName, debugPort);
- }
-
- private static void send(int signal, String processName, int debugPort) {
+ public static void signalizeFinish(String debuggerId, String processName, int dispatchPort) {
try {
- Socket socket = new Socket("127.0.0.1", debugPort);
+ send(debuggerId, processName, FINISH_PARAMS, dispatchPort);
+ }
+ catch (IOException e) {
+ //noinspection CallToPrintStackTrace
+ e.printStackTrace();
+ }
+ }
+
+ private static void send(String debuggerId, String processName, String processParameters, int dispatchPort) throws IOException {
+ Socket socket = new Socket("127.0.0.1", dispatchPort);
+ try {
+ DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
try {
- DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
- try {
- stream.writeInt(signal);
- stream.writeUTF(processName);
- // wait for the signal handling
- int read = socket.getInputStream().read();
- }
- finally {
- stream.close();
- }
+ stream.writeUTF(debuggerId);
+ stream.writeUTF(processName);
+ stream.writeUTF(processParameters);
+ // wait for the signal handling
+ int read = socket.getInputStream().read();
}
finally {
- socket.close();
+ stream.close();
}
}
- catch (Exception ignore) {
+ finally {
+ socket.close();
}
}
@@ -76,6 +82,11 @@ public class ForkedDebuggerHelper {
e.printStackTrace();
}
}
+
+ if (port <= -1) {
+ throw new IOException("Failed to find available port");
+ }
+
return port;
}
finally {
diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml
index 587ae5c81322..a732cd6b11ed 100644
--- a/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensionPoints.xml
@@ -2,6 +2,8 @@
+
+
diff --git a/plugins/gradle/java/src/service/debugger/GradleJvmDebuggerBackend.kt b/plugins/gradle/java/src/service/debugger/GradleJvmDebuggerBackend.kt
new file mode 100644
index 000000000000..3203f540f9f3
--- /dev/null
+++ b/plugins/gradle/java/src/service/debugger/GradleJvmDebuggerBackend.kt
@@ -0,0 +1,49 @@
+// Copyright 2000-2019 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 org.jetbrains.plugins.gradle.service.debugger
+
+import com.intellij.execution.RunManager.Companion.getInstance
+import com.intellij.execution.RunnerAndConfigurationSettings
+import com.intellij.execution.remote.RemoteConfiguration
+import com.intellij.execution.remote.RemoteConfigurationType
+import com.intellij.openapi.externalSystem.debugger.DebuggerBackendExtension
+import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper
+import com.intellij.openapi.project.Project
+
+class GradleJvmDebuggerBackend : DebuggerBackendExtension {
+ override fun id() = "Gradle JVM"
+
+ override fun debugConfigurationSettings(project: Project,
+ processName: String,
+ processParameters: String): RunnerAndConfigurationSettings {
+ val runSettings = getInstance(project).createConfiguration(processName, RemoteConfigurationType::class.java)
+ val description = splitParameters(processParameters)
+
+ val configuration = runSettings.configuration as RemoteConfiguration
+ configuration.HOST = "localhost"
+ configuration.PORT = description[ForkedDebuggerHelper.DEBUG_SERVER_PORT_KEY]
+ configuration.USE_SOCKET_TRANSPORT = true
+ configuration.SERVER_MODE = true
+
+ return runSettings
+ }
+
+ override fun initializationCode(dispatchPort: String, parameters: String) = listOf(
+ "import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper",
+ "gradle.taskGraph.beforeTask { Task task ->",
+ " if (task instanceof org.gradle.api.tasks.testing.Test) {",
+ " task.maxParallelForks = 1",
+ " task.forkEvery = 0",
+ " }",
+ " if (task instanceof JavaForkOptions) {",
+ " def debugPort = ForkedDebuggerHelper.setupDebugger('${id()}', task.path, '$parameters', $dispatchPort)",
+ " def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
+ " jvmArgs << ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX + debugPort",
+ " task.jvmArgs = jvmArgs",
+ " }",
+ "}",
+ "gradle.taskGraph.afterTask { Task task ->",
+ " if (task instanceof JavaForkOptions) {",
+ " ForkedDebuggerHelper.signalizeFinish('${id()}', task.path, $dispatchPort)",
+ " }",
+ "}")
+}
\ No newline at end of file
diff --git a/plugins/gradle/java/src/service/project/JavaGradleProjectResolver.java b/plugins/gradle/java/src/service/project/JavaGradleProjectResolver.java
index 56d44a4f98c3..37d20e7b11ac 100644
--- a/plugins/gradle/java/src/service/project/JavaGradleProjectResolver.java
+++ b/plugins/gradle/java/src/service/project/JavaGradleProjectResolver.java
@@ -6,14 +6,18 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
+import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerConfiguration;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.Order;
import com.intellij.openapi.util.io.StreamUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
+import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.execution.ParametersListUtil;
import org.gradle.tooling.model.idea.IdeaModule;
import org.gradle.tooling.model.idea.IdeaProject;
import org.jetbrains.annotations.NotNull;
@@ -31,6 +35,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
+import java.util.stream.Collectors;
/**
* @author Vladislav.Soroka
@@ -144,11 +149,11 @@ public class JavaGradleProjectResolver extends AbstractProjectResolverExtension
@Override
public void enhanceTaskProcessing(@NotNull List taskNames,
- @Nullable String jvmParametersSetup,
@NotNull Consumer initScriptConsumer,
- boolean testExecutionExpected) {
+ @NotNull Map parameters) {
+ String testExecutionExpected = parameters.get(GradleProjectResolverExtension.TEST_EXECUTION_EXPECTED_KEY);
- if (testExecutionExpected) {
+ if (Boolean.valueOf(testExecutionExpected)) {
try (InputStream stream = getClass().getResourceAsStream("/org/jetbrains/plugins/gradle/java/addTestListener.groovy")) {
String addTestListenerScript = StreamUtil.readText(stream, StandardCharsets.UTF_8);
initScriptConsumer.consume(addTestListenerScript);
@@ -157,6 +162,46 @@ public class JavaGradleProjectResolver extends AbstractProjectResolverExtension
LOG.info(e);
}
}
+
+ String jvmParametersSetup = parameters.get(GradleProjectResolverExtension.JVM_PARAMETERS_SETUP_KEY);
+ enhanceTaskProcessing(taskNames, jvmParametersSetup, initScriptConsumer);
+ }
+
+ private String loadTestEventListenerDefinition() {
+ try(InputStream stream = getClass().getResourceAsStream("/org/jetbrains/plugins/gradle/IJTestLogger.groovy")) {
+ return StreamUtil.readText(stream, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ LOG.info(e);
+ }
+ return "";
+ }
+
+ @Override
+ public void enhanceTaskProcessing(@NotNull List taskNames,
+ @Nullable String jvmParametersSetup,
+ @NotNull Consumer initScriptConsumer) {
+ if (!StringUtil.isEmpty(jvmParametersSetup)) {
+ ForkedDebuggerConfiguration forkedDebuggerSetup = ForkedDebuggerConfiguration.parse(jvmParametersSetup);
+ if (forkedDebuggerSetup == null) {
+ final String names = "[\"" + StringUtil.join(taskNames, "\", \"") + "\"]";
+ final String jvmArgs = Arrays.stream(ParametersListUtil.parseToArray(jvmParametersSetup))
+ .map(s -> '\'' + s.trim().replace("\\", "\\\\") + '\'').collect(Collectors.joining(" << "));
+ final String[] lines = {
+ "gradle.taskGraph.beforeTask { Task task ->",
+ " if (task instanceof JavaForkOptions && (" + names + ".contains(task.name) || " + names + ".contains(task.path))) {",
+ " def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
+ " jvmArgs << " + jvmArgs,
+ " task.jvmArgs = jvmArgs",
+ " }" +
+ "}",
+ };
+ final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
+ initScriptConsumer.consume(script);
+ }
+ }
+
+ final String testEventListenerDefinition = loadTestEventListenerDefinition();
+ initScriptConsumer.consume(testEventListenerDefinition);
}
@NotNull
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleRunConfiguration.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleRunConfiguration.java
index ac2874550623..2b25c6fd3129 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleRunConfiguration.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleRunConfiguration.java
@@ -15,6 +15,7 @@ import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.WriteExternalException;
import org.jdom.Element;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.GradleIdeManager;
@@ -25,6 +26,12 @@ public class GradleRunConfiguration extends ExternalSystemRunConfiguration imple
public static final String DEBUG_FLAG_NAME = "GradleScriptDebugEnabled";
public static final Key DEBUG_FLAG_KEY = Key.create("DEBUG_GRADLE_SCRIPT");
+
+ @ApiStatus.Internal
+ public static final Key DEBUGGER_DISPATCH_PORT_KEY = Key.create("DEBUGGER_DISPATCH_PORT");
+ @ApiStatus.Internal
+ public static final Key DEBUGGER_PARAMETERS_KEY = Key.create("DEBUGGER_PARAMETERS");
+
private boolean isScriptDebugEnabled = true;
public GradleRunConfiguration(Project project, ConfigurationFactory factory, String name) {
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
index 46adc3f6891a..6b475c7ee8cc 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
@@ -6,6 +6,7 @@ import com.google.gson.GsonBuilder;
import com.intellij.execution.configurations.SimpleJavaParameters;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.externalSystem.debugger.DebuggerBackendExtension;
import com.intellij.openapi.externalSystem.model.ConfigurationDataImpl;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
@@ -837,69 +838,30 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
public void enhanceTaskProcessing(@NotNull List taskNames,
@Nullable String jvmParametersSetup,
@NotNull Consumer initScriptConsumer) {
- if (!StringUtil.isEmpty(jvmParametersSetup)) {
- ForkedDebuggerConfiguration forkedDebuggerSetup = ForkedDebuggerConfiguration.parse(jvmParametersSetup);
- if (forkedDebuggerSetup != null) {
- setupDebugForAllJvmForkedTasks(initScriptConsumer, forkedDebuggerSetup.getForkSocketPort());
- }
- else {
- final String names = "[\"" + StringUtil.join(taskNames, "\", \"") + "\"]";
- final String jvmArgs = Arrays.stream(ParametersListUtil.parseToArray(jvmParametersSetup))
- .map(s -> '\'' + s.trim().replace("\\", "\\\\") + '\'').collect(Collectors.joining(" << "));
- final String[] lines = {
- "gradle.taskGraph.beforeTask { Task task ->",
- " if (task instanceof JavaForkOptions && (" + names + ".contains(task.name) || " + names + ".contains(task.path))) {",
- " def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
- " jvmArgs << " + jvmArgs,
- " task.jvmArgs = jvmArgs",
- " }" +
- "}",
- };
- final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
- initScriptConsumer.consume(script);
- }
- }
-
- final String testEventListenerDefinition = loadTestEventListenerDefinition();
- initScriptConsumer.consume(testEventListenerDefinition);
}
- private String loadTestEventListenerDefinition() {
- try (InputStream stream = getClass().getResourceAsStream("/org/jetbrains/plugins/gradle/IJTestLogger.groovy")) {
- return StreamUtil.readText(stream, StandardCharsets.UTF_8);
+ @Override
+ public void enhanceTaskProcessing(@NotNull List taskNames,
+ @NotNull Consumer initScriptConsumer,
+ @NotNull Map parameters) {
+ String dispatchPort = parameters.get(GradleProjectResolverExtension.DEBUG_DISPATCH_PORT_KEY);
+ if (dispatchPort == null) {
+ return;
}
- catch (IOException e) {
- LOG.info(e);
- }
- return "";
- }
- public void setupDebugForAllJvmForkedTasks(@NotNull Consumer super String> initScriptConsumer, int debugPort) {
- // external-system-rt.jar
+ String debugOptions = parameters.get(GradleProjectResolverExtension.DEBUG_OPTIONS_KEY);
+ if (debugOptions == null) {
+ debugOptions = "";
+ }
+ List lines = new ArrayList<>();
+
String esRtJarPath = PathUtil.getCanonicalPath(PathManager.getJarPathForClass(ExternalSystemSourceType.class));
- final String[] lines = {
- "initscript {",
- " dependencies {",
- " classpath files(\"" + esRtJarPath + "\")",
- " }",
- "}",
- "gradle.taskGraph.beforeTask { Task task ->",
- " if (task instanceof org.gradle.api.tasks.testing.Test) {",
- " task.maxParallelForks = 1",
- " task.forkEvery = 0",
- " }",
- " if (task instanceof JavaForkOptions) {",
- " def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
- " jvmArgs << com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.setupDebugger(task.path, " + debugPort + ")",
- " task.jvmArgs = jvmArgs",
- " }",
- "}",
- "gradle.taskGraph.afterTask { Task task ->",
- " if (task instanceof JavaForkOptions) {",
- " com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.processFinished(task.path, " + debugPort + ")",
- " }",
- "}",
- };
+ lines.add("initscript { dependencies { classpath files(\""+ esRtJarPath + "\") } }"); // bring external-system-rt.jar
+
+ for (DebuggerBackendExtension extension: DebuggerBackendExtension.EP_NAME.getExtensionList()) {
+ lines.addAll(extension.initializationCode(dispatchPort, debugOptions));
+ }
+
final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
initScriptConsumer.consume(script);
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java
index 7bfa34de62de..1e5f53254ecb 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java
@@ -40,10 +40,7 @@ import org.jetbrains.plugins.gradle.GradleManager;
import org.jetbrains.plugins.gradle.model.ModelsHolder;
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
/**
* Allows to enhance {@link GradleProjectResolver} processing.
@@ -205,18 +202,30 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer {
*/
void enhanceTaskProcessing(@NotNull List taskNames, @Nullable String jvmParametersSetup, @NotNull Consumer initScriptConsumer);
+ // jvm configuration that will be applied to Gradle jvm
+ String JVM_PARAMETERS_SETUP_KEY = "JVM_PARAMETERS_SETUP";
+
+ // flag that shows if tasks will be treated as tests invocation by the IDE (e.g., test events are expected)
+ String TEST_EXECUTION_EXPECTED_KEY = "TEST_EXECUTION_EXPECTED";
+
+ // port for callbacks which Gradle tasks communicate to IDE
+ String DEBUG_DISPATCH_PORT_KEY = "DEBUG_DISPATCH_PORT";
+
+ // options passed from project to Gradle
+ String DEBUG_OPTIONS_KEY = "DEBUG_OPTIONS";
+
/**
* Allows extension to contribute to init script
* @param taskNames gradle task names to be executed
* @param jvmParametersSetup jvm configuration that will be applied to Gradle jvm
* @param initScriptConsumer consumer of init script text. Must be called to add script txt
- * @param testExecutionExpected flag that shows if tasks will be treated as tests invocation by the IDE (e.g., test events are expected)
+ * @param parameters storage for passing optional named parameters
*/
@ApiStatus.Experimental
default void enhanceTaskProcessing(@NotNull List taskNames,
- @Nullable String jvmParametersSetup,
- @NotNull Consumer initScriptConsumer,
- boolean testExecutionExpected) {
+ @NotNull Consumer initScriptConsumer,
+ @NotNull Map parameters) {
+ String jvmParametersSetup = parameters.get(JVM_PARAMETERS_SETUP_KEY);
enhanceTaskProcessing(taskNames, jvmParametersSetup, initScriptConsumer);
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
index aa34391449c6..817234b00d2a 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
@@ -84,8 +84,11 @@ public class GradleTaskManager extends BaseExternalSystemTaskManager enhancementParameters = new HashMap<>();
+ enhancementParameters.put(GradleProjectResolverExtension.JVM_PARAMETERS_SETUP_KEY, jvmParametersSetup);
+
+ String isTestExecution = String.valueOf(Boolean.TRUE == effectiveSettings.getUserData(GradleConstants.RUN_TASK_AS_TEST));
+ enhancementParameters.put(GradleProjectResolverExtension.TEST_EXECUTION_EXPECTED_KEY, isTestExecution);
+
+ Integer debugDispatchPort = effectiveSettings.getUserData(GradleRunConfiguration.DEBUGGER_DISPATCH_PORT_KEY);
+
+ if (debugDispatchPort != null) {
+ enhancementParameters.put(GradleProjectResolverExtension.DEBUG_DISPATCH_PORT_KEY, String.valueOf(debugDispatchPort));
+ String debugOptions = effectiveSettings.getUserData(GradleRunConfiguration.DEBUGGER_PARAMETERS_KEY);
+ enhancementParameters.put(GradleProjectResolverExtension.DEBUG_OPTIONS_KEY, debugOptions);
+ }
+
+
+ resolverExtension.enhanceTaskProcessing(taskNames, initScriptConsumer, enhancementParameters);
}
if (!initScripts.isEmpty()) {