IDEA-CR-65504: Retrieve runtime module path for JavaForkOptions Gradle tasks.
authorVladimir Ilmov <vladimir.ilmov@jetbrains.com>
Mon, 27 Jul 2020 09:03:42 +0000 (11:03 +0200)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Wed, 29 Jul 2020 10:27:36 +0000 (10:27 +0000)
 relates to #KT-39196

GitOrigin-RevId: 398e6bb0566c663dbe39c3720f4f6f4d6c516cc0

java/execution/impl/src/com/intellij/openapi/externalSystem/service/execution/ForkedDebuggerThread.java
platform/external-system-api/src/com/intellij/openapi/externalSystem/debugger/DebuggerBackendExtension.java
platform/external-system-rt/src/com/intellij/openapi/externalSystem/rt/execution/ForkedDebuggerHelper.java
platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironment.java
platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironmentBuilder.kt
plugins/gradle/java/src/service/debugger/GradleJvmDebuggerBackend.kt

index 01c71c2acfa8d63934d833052d1bf6f69e22c20c..9dac7e91a2a9d581e5d1a006007baa2188525356 100644 (file)
@@ -11,6 +11,7 @@ import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
 import com.intellij.execution.ExecutionException;
 import com.intellij.execution.ProgramRunnerUtil;
 import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.configurations.RunConfiguration;
 import com.intellij.execution.executors.DefaultDebugExecutor;
 import com.intellij.execution.impl.ConsoleViewImpl;
 import com.intellij.execution.impl.EditorHyperlinkSupport;
@@ -33,6 +34,7 @@ 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.UserDataHolder;
 import com.intellij.openapi.util.io.StreamUtil;
 import com.intellij.openapi.wm.ToolWindowId;
 import com.intellij.openapi.wm.ToolWindowManager;
@@ -48,6 +50,10 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.intellij.openapi.externalSystem.debugger.DebuggerBackendExtension.RUNTIME_MODULE_DIR_KEY;
 
 /**
  * @author Vladislav.Soroka
@@ -208,11 +214,12 @@ class ForkedDebuggerThread extends Thread {
   private static void runDebugConfiguration(@NotNull RunnerAndConfigurationSettings runSettings, ProgramRunner.Callback callback) {
     try {
       runSettings.setActivateToolWindowBeforeRun(false);
-      ExecutionEnvironment environment = ExecutionEnvironmentBuilder.create(DefaultDebugExecutor.getDebugExecutorInstance(), runSettings)
+      ExecutionEnvironmentBuilder builder = ExecutionEnvironmentBuilder.create(DefaultDebugExecutor.getDebugExecutorInstance(), runSettings)
         .contentToReuse(null)
         .dataContext(null)
-        .activeTarget()
-        .build();
+        .activeTarget();
+      buildWithRuntimeModuleDir(runSettings, builder);
+      ExecutionEnvironment environment = builder.build();
       ApplicationManager.getApplication().invokeAndWait(() -> {
         ProgramRunnerUtil.executeConfigurationAsync(environment, true, true, callback);
       });
@@ -222,6 +229,15 @@ class ForkedDebuggerThread extends Thread {
     }
   }
 
+  private static void buildWithRuntimeModuleDir(@NotNull RunnerAndConfigurationSettings runSettings, ExecutionEnvironmentBuilder builder) {
+    RunConfiguration configuration = runSettings.getConfiguration();
+    if (configuration instanceof UserDataHolder) {
+      String moduleDir = ((UserDataHolder)configuration).getUserData(RUNTIME_MODULE_DIR_KEY);
+      if (moduleDir != null)
+        builder.modulePath(moduleDir);
+    }
+  }
+
   private class MyForkedProcessListener extends ProcessAdapter {
     @NotNull private final RunContentDescriptor myDescriptor;
     @NotNull private final String myProcessName;
index e31bee86feb9dee7741c269b992602bd6ea029b7..b98cb243a71e48a749735325e691133deace25e0 100644 (file)
@@ -5,6 +5,7 @@ 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 com.intellij.openapi.util.Key;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
@@ -16,6 +17,7 @@ import java.util.List;
  */
 public interface DebuggerBackendExtension {
   ExtensionPointName<DebuggerBackendExtension> EP_NAME = ExtensionPointName.create("com.intellij.externalSystem.debuggerBackend");
+  public static final Key<String> RUNTIME_MODULE_DIR_KEY  = Key.create("RUNTIME_MODULE_DIR_KEY");
 
   String id();
 
index e2c8997d1416bcab436d0ba08c409824bd3d304e..c9e90504434131b748bc6ba961c94adb76f7f8e1 100644 (file)
@@ -15,25 +15,26 @@ public final class ForkedDebuggerHelper {
   public static final String DEBUG_FORK_SOCKET_PARAM = "-forkSocket";
 
   public static final String DEBUG_SERVER_PORT_KEY = "DEBUG_SERVER_PORT";
+  public static final String RUNTIME_MODULE_DIR_KEY = "MODULE_DIR";
   public static final String PARAMETERS_SEPARATOR = ";";
 
   public static final String FINISH_PARAMS = "FINISH_PARAMS";
   public static final String DISPATCH_PORT_SYS_PROP = "idea.debugger.dispatch.port";
 
   // returns port at which debugger is supposed to communicate with debuggee process
-  public static int setupDebugger(String debuggerId, String processName, String processParameters) {
-    return setupDebugger(debuggerId, processName, processParameters, getPortFromProperty());
+  public static int setupDebugger(String debuggerId, String processName, String processParameters, String moduleDir) {
+    return setupDebugger(debuggerId, processName, processParameters, getPortFromProperty(), moduleDir);
   }
 
-  public static int setupDebugger(String debuggerId, String processName, String processParameters, int dispatchPort) {
+  public static int setupDebugger(String debuggerId, String processName, String processParameters, int dispatchPort, String moduleDir) {
     int port = 0;
     try {
       port = findAvailableSocketPort();
       processParameters = (processParameters == null || processParameters.isEmpty()) ? "" : processParameters + PARAMETERS_SEPARATOR;
-      processParameters = processParameters + DEBUG_SERVER_PORT_KEY + "=" + port;
+      processParameters = processParameters + DEBUG_SERVER_PORT_KEY + "=" + port + PARAMETERS_SEPARATOR;
+      processParameters = processParameters + RUNTIME_MODULE_DIR_KEY + "=" + moduleDir;
       send(debuggerId, processName, processParameters, dispatchPort);
-    }
-    catch (IOException e) {
+    } catch (IOException e) {
       //noinspection CallToPrintStackTrace
       e.printStackTrace();
     }
index 0441728b1c50ecac24db38326cafe9f4199761dc..32251ed7410db30d215ba44694e7acbe26086b01 100644 (file)
@@ -44,6 +44,7 @@ public final class ExecutionEnvironment extends UserDataHolderBase implements Di
   private final ProgramRunner<?> myRunner;
   private long myExecutionId = 0;
   @Nullable private DataContext myDataContext;
+  @Nullable private String myModulePath;
 
   @Nullable
   private ProgramRunner.Callback callback;
@@ -262,6 +263,16 @@ public final class ExecutionEnvironment extends UserDataHolderBase implements Di
     return myDataContext;
   }
 
+
+  void setModulePath(@NotNull String modulePath) {
+    this.myModulePath = modulePath;
+  }
+
+  @Nullable
+  public String getModulePath() {
+    return myModulePath;
+  }
+
   private static final class CachingDataContext implements DataContext {
     private static final DataKey[] keys = {PROJECT, PROJECT_FILE_DIRECTORY, EDITOR, VIRTUAL_FILE, MODULE, PSI_FILE};
     private final Map<String, Object> values = new HashMap<>();
index 538ba65b71c8571f6052c18e209897fcb4604586..a3de706e7e983b5fcf6f49da4fde787f4864fddc 100644 (file)
@@ -23,6 +23,7 @@ class ExecutionEnvironmentBuilder(private val project: Project, private var exec
   private var executionId: Long? = null
   private var dataContext: DataContext? = null
   private val userData = UserDataHolderBase()
+  private var modulePath: String? = null
 
   /**
    * Creates an execution environment builder initialized with a copy of the specified environment.
@@ -138,6 +139,11 @@ class ExecutionEnvironmentBuilder(private val project: Project, private var exec
     return this
   }
 
+  fun modulePath(modulePath: String): ExecutionEnvironmentBuilder {
+    this.modulePath = modulePath
+    return this
+  }
+
   @JvmOverloads
   fun build(callback: ProgramRunner.Callback? = null): ExecutionEnvironment {
     var environment: ExecutionEnvironment? = null
@@ -166,6 +172,9 @@ class ExecutionEnvironmentBuilder(private val project: Project, private var exec
     if (dataContext != null) {
       environment.setDataContext(dataContext!!)
     }
+    if (modulePath != null) {
+      environment.setModulePath(modulePath!!)
+    }
     userData.copyUserDataTo(environment)
     return environment
   }
index 144e92e00e8c69c94c28006ba90db27a7f8fd5e7..b3f71cc2fa6268530b43303770baf83f0472a662 100644 (file)
@@ -6,6 +6,7 @@ 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.debugger.DebuggerBackendExtension.RUNTIME_MODULE_DIR_KEY
 import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper
 import com.intellij.openapi.project.Project
 
@@ -23,29 +24,33 @@ class GradleJvmDebuggerBackend : DebuggerBackendExtension {
     configuration.PORT = description[ForkedDebuggerHelper.DEBUG_SERVER_PORT_KEY]
     configuration.USE_SOCKET_TRANSPORT = true
     configuration.SERVER_MODE = true
-
+    configuration.putUserData(RUNTIME_MODULE_DIR_KEY, description[ForkedDebuggerHelper.RUNTIME_MODULE_DIR_KEY])
     return runSettings
   }
 
-  override fun initializationCode(dispatchPort: String, parameters: String) = listOf(
-    "import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper",
-    "gradle.taskGraph.whenReady { taskGraph ->",
-    "  taskGraph.allTasks.each { Task task ->",
-    "    if (task instanceof org.gradle.api.tasks.testing.Test) {",
-    "      task.maxParallelForks = 1",
-    "      task.forkEvery = 0",
-    "    }",
-    "    if (task instanceof JavaForkOptions) {",
-    "      task.doFirst {",
-    "        def debugPort = ForkedDebuggerHelper.setupDebugger('${id()}', task.path, '$parameters')",
-    "        def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}",
-    "        jvmArgs << ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX + debugPort",
-    "        task.jvmArgs = jvmArgs",
-    "      }",
-    "      task.doLast {",
-    "        ForkedDebuggerHelper.signalizeFinish('${id()}', task.path)",
-    "      }",
-    "    }",
-    "  }" +
-    "}")
+  override fun initializationCode(dispatchPort: String, parameters: String) =
+    //language=Gradle
+    """
+    import com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper
+    gradle.taskGraph.whenReady { taskGraph ->
+      taskGraph.allTasks.each { Task task ->
+        if (task instanceof org.gradle.api.tasks.testing.Test) {
+          task.maxParallelForks = 1
+          task.forkEvery = 0
+        }
+        if (task instanceof JavaForkOptions) {
+          task.doFirst {
+            def moduleDir = task.project.projectDir.path
+            def debugPort = ForkedDebuggerHelper.setupDebugger('${id()}', task.path, '$parameters', moduleDir)
+            def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}
+            jvmArgs << ForkedDebuggerHelper.JVM_DEBUG_SETUP_PREFIX + debugPort
+            task.jvmArgs = jvmArgs
+          }
+          task.doLast {
+              ForkedDebuggerHelper.signalizeFinish('${id()}', task.path)
+          }
+        }
+      }
+    }
+    """.trimIndent().split("\n")
 }
\ No newline at end of file