Runtime environments: call TargetEnvironmentFactory.prepareRemoteEnvironment with...
authorAnna.Kozlova <anna.kozlova@jetbrains.com>
Mon, 3 Feb 2020 11:05:44 +0000 (12:05 +0100)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Mon, 3 Feb 2020 11:39:23 +0000 (11:39 +0000)
GitOrigin-RevId: c408ad75d4df5c0c7241d33b2b1cda97879d1dc0

java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java
java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java
java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java
platform/execution-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.kt
platform/lang-api/src/com/intellij/execution/ExecutionManager.kt
platform/lang-api/src/com/intellij/execution/target/TargetEnvironment.java
platform/lang-api/src/com/intellij/execution/target/TargetEnvironmentAwareRunProfileState.java [new file with mode: 0644]
platform/lang-api/src/com/intellij/execution/target/local/LocalTargetEnvironment.java

index c331a0b3495b1da5bd3303f5eef2544bb02f8c41..c6ba4df2820e610ad257eac1f438af15192cf571 100644 (file)
@@ -27,10 +27,11 @@ import com.intellij.xdebugger.XDebuggerManager;
 import com.intellij.xdebugger.impl.XDebugSessionImpl;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.concurrency.Promises;
 
 import java.util.Objects;
 
+import static org.jetbrains.concurrency.Promises.resolvedPromise;
+
 public class GenericDebuggerRunner implements JvmPatchableProgramRunner<GenericDebuggerRunnerSettings> {
   @Override
   public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) {
@@ -51,9 +52,14 @@ public class GenericDebuggerRunner implements JvmPatchableProgramRunner<GenericD
       return;
     }
 
-    ExecutionManager.getInstance(environment.getProject()).startRunProfile(environment, () -> {
-      return Promises.resolvedPromise(doExecute(state, environment));
-    });
+    ExecutionManager executionManager = ExecutionManager.getInstance(environment.getProject());
+    executionManager
+      .executePreparationTasks(environment, state)
+      .onSuccess(preparedEnvironment -> {
+        executionManager.startRunProfile(environment, () -> {
+          return resolvedPromise(doExecute(state, environment));
+        });
+      });
   }
 
   // used externally
index adfb8437eb1e8ccebc75052ebf5f2987eab1a1a0..bbc1eaaaa258836f9d8193489da6e0f51ec81661 100644 (file)
@@ -16,6 +16,7 @@ import com.intellij.execution.target.local.LocalTargetEnvironmentFactory;
 import com.intellij.execution.util.JavaParametersUtil;
 import com.intellij.openapi.application.Experiments;
 import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.projectRoots.JavaSdkVersion;
 import com.intellij.openapi.projectRoots.JdkUtil;
 import com.intellij.openapi.util.text.StringUtil;
@@ -27,12 +28,13 @@ import java.util.Map;
 import java.util.Optional;
 
 public abstract class BaseJavaApplicationCommandLineState<T extends RunConfigurationBase & CommonJavaRunConfigurationParameters>
-  extends JavaCommandLineState implements RemoteConnectionCreator {
+  extends JavaCommandLineState implements RemoteConnectionCreator, TargetEnvironmentAwareRunProfileState {
 
   @NotNull protected final T myConfiguration;
 
   @Nullable private TargetEnvironmentFactory myTargetEnvironmentFactory;
   @Nullable private RemoteConnection myRemoteConnection;
+  private TargetEnvironment myPreparedRemoteEnvironment;
 
   public BaseJavaApplicationCommandLineState(ExecutionEnvironment environment, @NotNull final T configuration) {
     super(environment);
@@ -101,8 +103,7 @@ public abstract class BaseJavaApplicationCommandLineState<T extends RunConfigura
   @Override
   protected OSProcessHandler startProcess() throws ExecutionException {
     //todo[remoteServers]: pull up and support all implementations of JavaCommandLineState
-    TargetEnvironmentFactory runner = getTargetEnvironmentFactory(getEnvironment());
-    TargetEnvironmentRequest request = runner.createRequest();
+    TargetEnvironmentRequest request = getPreparedRemoteEnvironment().getRequest();
     if (myRemoteConnection != null) {
       final int remotePort = StringUtil.parseInt(myRemoteConnection.getApplicationAddress(), -1);
       if (remotePort > 0) {
@@ -113,11 +114,10 @@ public abstract class BaseJavaApplicationCommandLineState<T extends RunConfigura
       }
     }
 
-    TargetedCommandLineBuilder targetedCommandLineBuilder = createTargetedCommandLine(request, runner.getTargetConfiguration());
+    TargetedCommandLineBuilder targetedCommandLineBuilder = createTargetedCommandLine(request, getTargetEnvironmentFactory(getEnvironment()).getTargetConfiguration());
     TargetedCommandLine targetedCommandLine = targetedCommandLineBuilder.build();
-    EmptyProgressIndicator indicator = new EmptyProgressIndicator();
-    TargetEnvironment remoteEnvironment = runner.prepareRemoteEnvironment(request, indicator);
-    Process process = remoteEnvironment.createProcess(targetedCommandLine, indicator);
+    TargetEnvironment remoteEnvironment = getPreparedRemoteEnvironment();
+    Process process = remoteEnvironment.createProcess(targetedCommandLine, new EmptyProgressIndicator());
 
     Map<String, String> content = targetedCommandLineBuilder.getUserData(JdkUtil.COMMAND_LINE_CONTENT);
     if (content != null) {
@@ -134,6 +134,20 @@ public abstract class BaseJavaApplicationCommandLineState<T extends RunConfigura
     return handler;
   }
 
+  @Override
+  public TargetEnvironment prepareEnvironment(final ProgressIndicator progressIndicator) {
+    TargetEnvironmentFactory factory = getTargetEnvironmentFactory(getEnvironment());
+    return myPreparedRemoteEnvironment = factory.prepareRemoteEnvironment(factory.createRequest(), progressIndicator);
+  }
+
+  protected TargetEnvironment getPreparedRemoteEnvironment() {
+    if (myPreparedRemoteEnvironment != null) {
+      return myPreparedRemoteEnvironment;
+    }
+    TargetEnvironmentFactory factory = getTargetEnvironmentFactory(getEnvironment());
+    return myPreparedRemoteEnvironment = factory.prepareRemoteEnvironment(factory.createRequest(), new EmptyProgressIndicator());
+  }
+
   @NotNull
   private TargetEnvironmentFactory getTargetEnvironmentFactory(@NotNull ExecutionEnvironment environment)
     throws ExecutionException {
index b968b341feddf155b84017b3ecf895db4d19ecd1..5919779bb9c4cabf9183614301a3111160480c12 100644 (file)
@@ -60,6 +60,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
+import static org.jetbrains.concurrency.Promises.resolvedPromise;
+
 public class DefaultJavaProgramRunner implements JvmPatchableProgramRunner<RunnerSettings> {
   private static final Logger LOG = Logger.getInstance(DefaultJavaProgramRunner.class);
   private final static String ourWiseThreadDumpProperty = "idea.java.run.wise.thread.dump";
@@ -85,9 +87,17 @@ public class DefaultJavaProgramRunner implements JvmPatchableProgramRunner<Runne
 
   @Override
   public void execute(@NotNull ExecutionEnvironment environment) throws ExecutionException {
-    ExecutionManager.getInstance(environment.getProject()).startRunProfile(environment, state -> {
-      return doExecute(state, environment);
-    });
+    RunProfileState currentState = environment.getState();
+    if (currentState == null) return;
+
+    ExecutionManager executionManager = ExecutionManager.getInstance(environment.getProject());
+    executionManager
+      .executePreparationTasks(environment, currentState)
+      .onSuccess(preparedEnvironment -> {
+        executionManager.startRunProfile(environment, () -> {
+          return resolvedPromise(doExecute(currentState, environment));
+        });
+      });
   }
 
   // cannot be final - overridden in YourKit plugin
index cfda40216b13c36f8ead238472d021d13a22d74f..25367b05643b511737abea23acf96bd636c2de63 100644 (file)
@@ -7,15 +7,18 @@ import com.intellij.execution.configuration.CompatibilityAwareRunProfile
 import com.intellij.execution.configurations.RunConfiguration
 import com.intellij.execution.configurations.RunConfiguration.RestartSingletonResult
 import com.intellij.execution.configurations.RunProfile
+import com.intellij.execution.configurations.RunProfileState
 import com.intellij.execution.executors.DefaultRunExecutor
+import com.intellij.execution.filters.TextConsoleBuilderFactory
 import com.intellij.execution.impl.statistics.RunConfigurationUsageTriggerCollector
-import com.intellij.execution.process.ProcessAdapter
-import com.intellij.execution.process.ProcessEvent
-import com.intellij.execution.process.ProcessHandler
+import com.intellij.execution.process.*
 import com.intellij.execution.runners.ExecutionEnvironment
 import com.intellij.execution.runners.ExecutionEnvironmentBuilder
 import com.intellij.execution.runners.ExecutionUtil
 import com.intellij.execution.runners.ProgramRunner
+import com.intellij.execution.target.TargetEnvironment
+import com.intellij.execution.target.TargetEnvironmentAwareRunProfile
+import com.intellij.execution.target.TargetEnvironmentAwareRunProfileState
 import com.intellij.execution.ui.RunContentDescriptor
 import com.intellij.execution.ui.RunContentManager
 import com.intellij.ide.SaveAndSyncHandler
@@ -23,11 +26,14 @@ import com.intellij.internal.statistic.IdeActivity
 import com.intellij.openapi.Disposable
 import com.intellij.openapi.actionSystem.impl.SimpleDataContext
 import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.Experiments
 import com.intellij.openapi.application.ModalityState
 import com.intellij.openapi.components.service
 import com.intellij.openapi.components.serviceIfCreated
 import com.intellij.openapi.diagnostic.logger
 import com.intellij.openapi.progress.ProcessCanceledException
+import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.progress.util.ProgressIndicatorBase
 import com.intellij.openapi.project.*
 import com.intellij.openapi.ui.DialogWrapper
 import com.intellij.openapi.ui.Messages
@@ -43,7 +49,10 @@ import com.intellij.util.containers.ContainerUtil
 import gnu.trove.THashSet
 import org.jetbrains.annotations.ApiStatus
 import org.jetbrains.annotations.TestOnly
+import org.jetbrains.concurrency.AsyncPromise
 import org.jetbrains.concurrency.Promise
+import org.jetbrains.concurrency.resolvedPromise
+import java.io.OutputStream
 import java.util.*
 import java.util.concurrent.atomic.AtomicBoolean
 import javax.swing.SwingUtilities
@@ -505,6 +514,65 @@ class ExecutionManagerImpl(private val project: Project) : ExecutionManager(), D
     }, 50)
   }
 
+  override fun executePreparationTasks(environment: ExecutionEnvironment,
+                                       currentState: RunProfileState): Promise<TargetEnvironment?> {
+    if (!(currentState is TargetEnvironmentAwareRunProfileState &&
+          environment.runProfile is TargetEnvironmentAwareRunProfile &&
+          Experiments.getInstance().isFeatureEnabled("runtime.environments"))) {
+      return resolvedPromise()
+    }
+    class MyProcessHandler : ProcessHandler() {
+      override fun destroyProcessImpl() {}
+      override fun detachProcessImpl() {}
+      override fun detachIsDefault(): Boolean {
+        return false
+      }
+
+      override fun getProcessInput(): OutputStream? {
+        return null
+      }
+
+      public override fun notifyProcessTerminated(exitCode: Int) {
+        super.notifyProcessTerminated(exitCode)
+      }
+    }
+
+    val processHandler = MyProcessHandler()
+    val consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(environment.project).console
+    ProcessTerminatedListener.attach(processHandler)
+    consoleView.attachToProcess(processHandler)
+    val executionResult = DefaultExecutionResult(consoleView, processHandler)
+    val descriptor = RunContentDescriptor(executionResult.executionConsole, executionResult.processHandler,
+                                          executionResult.executionConsole.component,
+                                          "Prepare " + environment.executionTarget.displayName)
+    val promise = AsyncPromise<TargetEnvironment>()
+    ApplicationManager.getApplication().executeOnPooledThread {
+      try {
+        executionResult.processHandler.startNotify()
+        val progressIndicator: ProgressIndicator = object : ProgressIndicatorBase() {
+          override fun setText(text: String) {
+            processHandler.notifyTextAvailable("$text\n", ProcessOutputType.STDOUT)
+          }
+  
+          override fun setText2(text: String) {
+            processHandler.notifyTextAvailable("$text\n", ProcessOutputType.STDOUT)
+          }
+        }
+        promise.setResult(currentState.prepareEnvironment(progressIndicator))
+      }
+      catch (t: Throwable) {
+        promise.setError(t)
+        processHandler.notifyTextAvailable(t.localizedMessage, ProcessOutputType.STDERR)
+      }
+      finally {
+        val exitCode = if (promise.isSucceeded) 0 else -1
+        processHandler.notifyProcessTerminated(exitCode)
+      }
+    }
+    RunContentManager.getInstance(environment.project).showRunContent(environment.executor, descriptor)
+    return promise
+  }
+  
   @ApiStatus.Internal
   fun executeConfiguration(environment: ExecutionEnvironment, showSettings: Boolean, assignNewId: Boolean = true) {
     val runnerAndConfigurationSettings = environment.runnerAndConfigurationSettings
index 72117e11743171515ffce84d14909a049a02e1e5..874e488e95ee876f438456ad33730646b0a7d673 100644 (file)
@@ -4,6 +4,7 @@ package com.intellij.execution
 import com.intellij.execution.configurations.RunProfileState
 import com.intellij.execution.process.ProcessHandler
 import com.intellij.execution.runners.ExecutionEnvironment
+import com.intellij.execution.target.TargetEnvironment
 import com.intellij.execution.ui.RunContentDescriptor
 import com.intellij.execution.ui.RunContentManager
 import com.intellij.openapi.project.Project
@@ -77,4 +78,8 @@ abstract class ExecutionManager {
 
   @ApiStatus.Internal
   abstract fun isStarting(executorId: String, runnerId: String): Boolean
+
+  @ApiStatus.Experimental
+  abstract fun executePreparationTasks(environment: ExecutionEnvironment,
+                                       currentState: RunProfileState): Promise<TargetEnvironment?>
 }
\ No newline at end of file
index a82fbdb8c40cf654c9e0c44e87f657718bb05619..2a3eca673e8cc9968bf405a44afe1d3b35e47ddc 100644 (file)
@@ -16,6 +16,8 @@ public interface TargetEnvironment {
   @NotNull
   Process createProcess(@NotNull TargetedCommandLine commandLine, @NotNull ProgressIndicator indicator) throws ExecutionException;
 
+  TargetEnvironmentRequest getRequest();
+
   @NotNull
   TargetPlatform getRemotePlatform();
 }
diff --git a/platform/lang-api/src/com/intellij/execution/target/TargetEnvironmentAwareRunProfileState.java b/platform/lang-api/src/com/intellij/execution/target/TargetEnvironmentAwareRunProfileState.java
new file mode 100644 (file)
index 0000000..40568d2
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.execution.target;
+
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.openapi.progress.ProgressIndicator;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Experimental
+public interface TargetEnvironmentAwareRunProfileState extends RunProfileState {
+  TargetEnvironment prepareEnvironment(final ProgressIndicator progressIndicator);
+}
\ No newline at end of file
index deeb52e528cb0c796887907fa58316da25c1aa4c..6fcc17df714be18439417ba10c51abe8532fb9c5 100644 (file)
@@ -21,6 +21,11 @@ public class LocalTargetEnvironment implements TargetEnvironment {
     myRequest = request;
   }
 
+  @Override
+  public TargetEnvironmentRequest getRequest() {
+    return myRequest;
+  }
+
   @NotNull
   @Override
   public TargetPlatform getRemotePlatform() {