Skip to content

Commit

Permalink
fix: Debug run config invalid with Gradle
Browse files Browse the repository at this point in the history
Fixes #1311

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Sep 16, 2024
1 parent e246f7f commit b487f48
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
******************************************************************************/
package com.redhat.devtools.intellij.quarkus.buildtool;

import com.intellij.execution.Executor;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
Expand All @@ -21,6 +22,7 @@
import com.intellij.util.messages.MessageBusConnection;
import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.model.MavenId;

import java.io.File;
Expand Down Expand Up @@ -179,7 +181,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.
Expand All @@ -189,4 +191,9 @@ public static BuildToolDelegate[] getDelegates() {
* @param listener the project import listener.
*/
void addProjectImportListener(@NotNull Project project, @NotNull MessageBusConnection connection, @NotNull ProjectImportListener listener);

@Nullable
default Executor getOverridedExecutor() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
******************************************************************************/
package com.redhat.devtools.intellij.quarkus.buildtool.gradle;

import com.intellij.execution.Executor;
import com.intellij.execution.ExecutorRegistry;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
Expand Down Expand Up @@ -38,6 +40,7 @@
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.projectImport.ProjectImportBuilder;
import com.intellij.projectImport.ProjectImportProvider;
import com.intellij.util.concurrency.NonUrgentExecutor;
Expand Down Expand Up @@ -358,12 +361,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();
}
Expand Down Expand Up @@ -407,4 +410,9 @@ private static boolean isValidGradleModule(Module module) {
String name = module.getName();
return !(name.endsWith(".integrationTest") || name.endsWith(".native-test") || name.endsWith(".test"));
}

@Override
public @Nullable Executor getOverridedExecutor() {
return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.RUN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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);
}
});
}
}

@Override
public void processTerminated(@NotNull ProcessEvent event) {
event.getProcessHandler().removeProcessListener(this);
}

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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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.redhat.devtools.intellij.quarkus.run;

import com.intellij.build.BuildView;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.runners.RunContentBuilder;
import com.intellij.execution.testframework.HistoryTestRunnableState;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunnableState;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.redhat.devtools.intellij.quarkus.buildtool.BuildToolDelegate;
import com.redhat.devtools.intellij.quarkus.buildtool.maven.MavenToolDelegate;
import org.jetbrains.concurrency.Promises;

public class QuarkusExternalSystemTaskRunner implements ProgramRunner<RunnerSettings> {

@Override
public String getRunnerId() {
return ExternalSystemConstants.RUNNER_ID;
}

@Override
public boolean canRun(String executorId, 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;
}

@Override
public void execute(ExecutionEnvironment environment) throws ExecutionException {
RunProfileState state = environment.getState();
if (state == null) {
return;
}
ExecutionManager.getInstance(environment.getProject()).startRunProfile(environment, () -> {
try {
return Promises.resolvedPromise(doExecute(state, environment));
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
});
}

private RunContentDescriptor doExecute(RunProfileState state, ExecutionEnvironment environment) throws ExecutionException {
if (!(state instanceof ExternalSystemRunnableState) && !(state instanceof HistoryTestRunnableState)) {
return null;
}

RunContentDescriptor runContentDescriptor;
ExecutionResult executionResult = state.execute(environment.getExecutor(), this);
if (executionResult == null) {
return null;
}
runContentDescriptor = new RunContentBuilder(executionResult, environment).showRunContent(environment.getContentToReuse());
if (runContentDescriptor == null) {
return null;
}

if (state instanceof HistoryTestRunnableState) {
return runContentDescriptor;
}

((ExternalSystemRunnableState) state).setContentDescriptor(runContentDescriptor);

if (executionResult.getExecutionConsole() instanceof BuildView) {
return runContentDescriptor;
}

RunContentDescriptor descriptor = new RunContentDescriptor(
runContentDescriptor.getExecutionConsole(),
runContentDescriptor.getProcessHandler(),
runContentDescriptor.getComponent(),
runContentDescriptor.getDisplayName(),
runContentDescriptor.getIcon(),
null,
runContentDescriptor.getRestartActions()
) {
@Override
public boolean isHiddenContent() {
return true;
}
};
descriptor.setRunnerLayoutUi(runContentDescriptor.getRunnerLayoutUi());
return descriptor;
}
}
Loading

0 comments on commit b487f48

Please sign in to comment.