diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/BuildToolDelegate.java b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/BuildToolDelegate.java index 8679e0440..997eb2b5b 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/BuildToolDelegate.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/BuildToolDelegate.java @@ -179,7 +179,7 @@ public static BuildToolDelegate[] getDelegates() { return delegates; } - RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration); + RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration, boolean debug); /** * Add project import listener. diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/gradle/AbstractGradleToolDelegate.java b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/gradle/AbstractGradleToolDelegate.java index fb4e7f9cf..ab3a8d596 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/gradle/AbstractGradleToolDelegate.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/gradle/AbstractGradleToolDelegate.java @@ -358,12 +358,12 @@ private ProjectImportProvider getGradleProjectImportProvider() { } @Override - public RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration) { + public RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration, boolean debug) { RunnerAndConfigurationSettings settings = RunManager.getInstance(module.getProject()).createConfiguration(module.getName() + " Quarkus (Gradle)", GradleExternalTaskConfigurationType.class); GradleRunConfiguration gradleConfiguration = (GradleRunConfiguration) settings.getConfiguration(); gradleConfiguration.getSettings().getTaskNames().add("quarkusDev"); gradleConfiguration.getSettings().setEnv(configuration.getEnv()); - String parameters = "-Ddebug=" + configuration.getPort(); + String parameters = debug ? "-Ddebug=" + configuration.getPort() : ""; if (StringUtils.isNotBlank(configuration.getProfile())) { parameters += " -Dquarkus.profile=" + configuration.getProfile(); } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java index b6b61d15d..fbc3f12ff 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/buildtool/maven/MavenToolDelegate.java @@ -39,7 +39,6 @@ import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.server.MavenEmbedderWrapper; -import org.jetbrains.idea.maven.utils.MavenProcessCanceledException; import org.jetbrains.idea.maven.utils.MavenUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -260,7 +259,7 @@ private MavenEmbedderWrapper createEmbedderWrapper(Project project, String worki } @Override - public RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration) { + public RunnerAndConfigurationSettings getConfigurationDelegate(Module module, QuarkusRunConfiguration configuration, boolean debug) { RunnerAndConfigurationSettings settings = RunManager.getInstance(module.getProject()).createConfiguration(module.getName() + " Quarkus (Maven)", MavenRunConfigurationType.class); MavenRunConfiguration mavenConfiguration = (MavenRunConfiguration) settings.getConfiguration(); mavenConfiguration.getRunnerParameters().setResolveToWorkspace(true); @@ -271,7 +270,9 @@ public RunnerAndConfigurationSettings getConfigurationDelegate(Module module, Qu if (StringUtils.isNotBlank(configuration.getProfile())) { mavenConfiguration.getRunnerSettings().getMavenProperties().put("quarkus.profile", configuration.getProfile()); } - mavenConfiguration.getRunnerSettings().getMavenProperties().put("debug", Integer.toString(configuration.getPort())); + if (debug) { + mavenConfiguration.getRunnerSettings().getMavenProperties().put("debug", Integer.toString(configuration.getPort())); + } mavenConfiguration.setBeforeRunTasks(configuration.getBeforeRunTasks()); return settings; } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerExecutionListener.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerExecutionListener.java new file mode 100644 index 000000000..6059949df --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerExecutionListener.java @@ -0,0 +1,38 @@ +package com.redhat.devtools.intellij.quarkus.run; + +import com.intellij.execution.ExecutionListener; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.executors.DefaultDebugExecutor; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.process.ProcessListener; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; + +import static com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration.QUARKUS_CONFIGURATION; + +class AttachDebuggerExecutionListener implements ExecutionListener { + + private final @NotNull Project project; + + AttachDebuggerExecutionListener(@NotNull Project project) { + this.project = project; + } + + public void processStarting(@NotNull String executorId, + @NotNull ExecutionEnvironment env, + @NotNull ProcessHandler handler) { + if (!DefaultDebugExecutor.EXECUTOR_ID.equals(executorId)) { + return; + } + RunnerAndConfigurationSettings settings = env.getRunnerAndConfigurationSettings(); + if (settings != null && settings.getConfiguration() instanceof QuarkusRunConfiguration) { + handler.addProcessListener(new AttachDebuggerProcessListener(project, env)); + } + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerProcessListener.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerProcessListener.java new file mode 100644 index 000000000..4b1359bd3 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/AttachDebuggerProcessListener.java @@ -0,0 +1,91 @@ +package com.redhat.devtools.intellij.quarkus.run; + +import com.intellij.execution.DefaultExecutionTarget; +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.executors.DefaultDebugExecutor; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessListener; +import com.intellij.execution.remote.RemoteConfiguration; +import com.intellij.execution.remote.RemoteConfigurationType; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ExecutionUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +import static com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration.QUARKUS_CONFIGURATION; + +class AttachDebuggerProcessListener implements ProcessListener { + + private static final String JWDP_HANDSHAKE = "JDWP-Handshake"; + + private final Project project; + private final ExecutionEnvironment env; + private boolean connected; + + AttachDebuggerProcessListener(@NotNull Project project, + @NotNull ExecutionEnvironment env) { + this.project = project; + this.env = env; + } + + @Override + public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { + String message = event.getText(); + if (!connected && message.startsWith("Listening for transport dt_socket at address: ")) { + connected = true; + String s = message.substring("Listening for transport dt_socket at address: ".length(), message.length()).trim(); + int port = Integer.valueOf(s); + ProgressManager.getInstance().run(new Task.Backgroundable(project, QUARKUS_CONFIGURATION, false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + String name = env.getRunProfile().getName(); + createRemoteConfiguration(indicator, port,name); + } + }); + } + } + + private void createRemoteConfiguration(ProgressIndicator indicator, int port, String name) { + indicator.setText("Connecting Java debugger to port " + port); + try { + waitForPortAvailable(port, indicator); + RunnerAndConfigurationSettings settings = RunManager.getInstance(project).createConfiguration(name + " (Remote)", RemoteConfigurationType.class); + RemoteConfiguration remoteConfiguration = (RemoteConfiguration) settings.getConfiguration(); + remoteConfiguration.PORT = Integer.toString(port); + long groupId = ExecutionEnvironment.getNextUnusedExecutionId(); + ExecutionUtil.runConfiguration(settings, DefaultDebugExecutor.getDebugExecutorInstance(), DefaultExecutionTarget.INSTANCE, groupId); + } catch (IOException e) { + ApplicationManager.getApplication() + .invokeLater(() -> Messages.showErrorDialog("Can' t connector to port " + port, "Quarkus")); + } + } + + private void waitForPortAvailable(int port, ProgressIndicator monitor) throws IOException { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < 120_000 && !monitor.isCanceled()) { + try (Socket socket = new Socket("localhost", port)) { + socket.getOutputStream().write(JWDP_HANDSHAKE.getBytes(StandardCharsets.US_ASCII)); + return; + } catch (ConnectException e) { + try { + Thread.sleep(1000L); + } catch (InterruptedException e1) { + throw new IOException(e1); + } + } + } + throw new IOException("Can't connect remote debuger to port " + port); + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusExternalSystemTaskDebugRunner.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusExternalSystemTaskDebugRunner.java new file mode 100644 index 000000000..f85d7ac62 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusExternalSystemTaskDebugRunner.java @@ -0,0 +1,28 @@ +package com.redhat.devtools.intellij.quarkus.run; + +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.executors.DefaultDebugExecutor; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskDebugRunner; +import com.redhat.devtools.intellij.quarkus.buildtool.BuildToolDelegate; +import com.redhat.devtools.intellij.quarkus.buildtool.maven.MavenToolDelegate; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QuarkusExternalSystemTaskDebugRunner extends ExternalSystemTaskDebugRunner { + + private static final Logger log = LoggerFactory.getLogger(QuarkusExternalSystemTaskDebugRunner.class); + + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { + if (!DefaultDebugExecutor.EXECUTOR_ID.equals(executorId)) { + return false; + } + if (profile instanceof QuarkusRunConfiguration quarkusRunConfiguration) { + BuildToolDelegate delegate = BuildToolDelegate.getDelegate(quarkusRunConfiguration.getModule()); + return !(delegate instanceof MavenToolDelegate); + } + return false; + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java index fdadf6c1f..b1c7b1e81 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java @@ -18,6 +18,9 @@ import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.execution.executors.DefaultDebugExecutor; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.process.ProcessListener; import com.intellij.execution.remote.RemoteConfiguration; import com.intellij.execution.remote.RemoteConfigurationType; import com.intellij.execution.runners.ExecutionEnvironment; @@ -25,6 +28,7 @@ import com.intellij.execution.runners.ExecutionUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunnableState; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.progress.ProgressIndicator; @@ -32,6 +36,7 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Key; import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; import com.redhat.devtools.intellij.quarkus.buildtool.BuildToolDelegate; import com.redhat.devtools.intellij.quarkus.telemetry.TelemetryEventName; @@ -53,13 +58,12 @@ import static com.intellij.execution.runners.ExecutionUtil.createEnvironment; public class QuarkusRunConfiguration extends ModuleBasedConfiguration { + private final static Logger LOGGER = LoggerFactory.getLogger(QuarkusRunConfiguration.class); - private static final String QUARKUS_CONFIGURATION = "Quarkus Configuration"; + static final String QUARKUS_CONFIGURATION = "Quarkus Configuration"; private int port = 5005; - private static final String JWDP_HANDSHAKE = "JDWP-Handshake"; - public QuarkusRunConfiguration(Project project, ConfigurationFactory factory, String name) { super(name, getRunConfigurationModule(project), factory); } @@ -132,9 +136,11 @@ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEn RunProfileState state = null; if (toolDelegate != null) { telemetryData.put("tool", toolDelegate.getDisplay()); + boolean debug = DefaultDebugExecutor.EXECUTOR_ID.equals(executor.getId()); // Create a Gradle or Maven run configuration in memory - RunnerAndConfigurationSettings settings = toolDelegate.getConfigurationDelegate(module, this); + RunnerAndConfigurationSettings settings = toolDelegate.getConfigurationDelegate(module, this, debug); if (settings != null) { + QuarkusRunConfigurationManager.getInstance(module.getProject()); // to be sure that Quarkus execution listener is registered long groupId = ExecutionEnvironment.getNextUnusedExecutionId(); state = doRunConfiguration(settings, executor, DefaultExecutionTarget.INSTANCE, groupId, null); } @@ -143,49 +149,9 @@ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEn } // Send "run-run" telemetry event TelemetryManager.instance().send(TelemetryEventName.RUN_RUN, telemetryData); - - if (executor.getId().equals(DefaultDebugExecutor.EXECUTOR_ID)) { - ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), QUARKUS_CONFIGURATION, false) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - createRemoteConfiguration(indicator); - } - }); - } return state; } - private void waitForPortAvailable(int port, ProgressIndicator monitor) throws IOException { - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < 60_000 && !monitor.isCanceled()) { - try (Socket socket = new Socket("localhost", port)) { - socket.getOutputStream().write(JWDP_HANDSHAKE.getBytes(StandardCharsets.US_ASCII)); - return; - } catch (ConnectException e) { - try { - Thread.sleep(1000L); - } catch (InterruptedException e1) { - throw new IOException(e1); - } - } - } - throw new IOException("Can't connect remote debuger to port " + port); - } - - private void createRemoteConfiguration(ProgressIndicator indicator) { - indicator.setText("Connecting Java debugger to port " + getPort()); - try { - waitForPortAvailable(getPort(), indicator); - RunnerAndConfigurationSettings settings = RunManager.getInstance(getProject()).createConfiguration(getName() + " (Remote)", RemoteConfigurationType.class); - RemoteConfiguration remoteConfiguration = (RemoteConfiguration) settings.getConfiguration(); - remoteConfiguration.PORT = Integer.toString(getPort()); - long groupId = ExecutionEnvironment.getNextUnusedExecutionId(); - ExecutionUtil.runConfiguration(settings, DefaultDebugExecutor.getDebugExecutorInstance(), DefaultExecutionTarget.INSTANCE, groupId); - } catch (IOException e) { - ApplicationManager.getApplication().invokeLater(() -> Messages.showErrorDialog("Can' t connector to port " + getPort(), "Quarkus")); - } - } - public String getProfile() { return getOptions().getProfile(); } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfigurationManager.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfigurationManager.java index 5d04f9b05..f127dd174 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfigurationManager.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfigurationManager.java @@ -13,6 +13,7 @@ *******************************************************************************/ package com.redhat.devtools.intellij.quarkus.run; +import com.intellij.execution.ExecutionManager; import com.intellij.execution.RunManager; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.dashboard.RunDashboardManager; @@ -56,6 +57,7 @@ public static QuarkusRunConfigurationManager getInstance(Project project) { public QuarkusRunConfigurationManager(Project project) { this.project = project; connection = addProjectImportListener(project); + connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new AttachDebuggerExecutionListener(project)); } public @Nullable RunnerAndConfigurationSettings findExistingConfigurationFor(@NotNull Module module) { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 825c697de..28446669c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -376,6 +376,7 @@ +