IDEA-189973 maven - support for debugging of exec:exec maven run configurations

This commit is contained in:
Ivan Bessonov
2018-06-27 13:04:39 +03:00
parent 5803867015
commit a823e5ceda
2 changed files with 130 additions and 13 deletions
@@ -147,7 +147,7 @@ public class MavenApplicationConfigurationExecutionEnvironmentProvider implement
mavenRunConfiguration.setShowConsoleOnStdErr(applicationConfiguration.isShowConsoleOnStdErr());
}
private static List<String> patchVmParameters(ParametersList vmParameters) {
public static List<String> patchVmParameters(ParametersList vmParameters) {
List<String> patchedVmParameters = new ArrayList<>(vmParameters.getList());
for (Iterator<String> iterator = patchedVmParameters.iterator(); iterator.hasNext(); ) {
String parameter = iterator.next();
@@ -3,6 +3,8 @@
*/
package org.jetbrains.idea.maven.execution;
import com.intellij.debugger.impl.DebuggerManagerImpl;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.diagnostic.logging.LogConfigurationPanel;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
@@ -11,18 +13,35 @@ import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.MavenDomUtil;
import org.jetbrains.idea.maven.dom.MavenPropertyResolver;
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.project.*;
import java.io.File;
import java.util.List;
import java.util.regex.Pattern;
import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
import static com.intellij.util.containers.ContainerUtil.indexOf;
import static org.jetbrains.idea.maven.execution.MavenApplicationConfigurationExecutionEnvironmentProvider.patchVmParameters;
public class MavenRunConfiguration extends LocatableConfigurationBase implements ModuleRunProfile {
private MavenSettings mySettings;
@@ -127,18 +146,7 @@ public class MavenRunConfiguration extends LocatableConfigurationBase implements
@NotNull
public RemoteConnectionCreator createRemoteConnectionCreator(JavaParameters javaParameters) {
return new RemoteConnectionCreator() {
@Nullable
@Override
public RemoteConnection createRemoteConnection(ExecutionEnvironment environment) {
return null; //TODO IDEA-189973 filter and patch exec goals to support debug
}
@Override
public boolean isPollConnection() {
return true;
}
};
return new ExecRemoteConnectionCreator(javaParameters, this);
}
private void updateProjectsFolders() {
@@ -223,4 +231,113 @@ public class MavenRunConfiguration extends LocatableConfigurationBase implements
return new MavenSettings(myGeneralSettings, myRunnerSettings, myRunnerParameters);
}
}
private static class ExecRemoteConnectionCreator implements RemoteConnectionCreator {
private static final Pattern EXEC_MAVEN_PLUGIN_PATTERN = Pattern.compile("org[.]codehaus[.]mojo:exec-maven-plugin(:[\\d.]+)?:exec");
private final JavaParameters myJavaParameters;
private final MavenRunConfiguration myRunConfiguration;
public ExecRemoteConnectionCreator(JavaParameters javaParameters, MavenRunConfiguration runConfiguration) {
myJavaParameters = javaParameters;
myRunConfiguration = runConfiguration;
}
@Nullable
@Override
public RemoteConnection createRemoteConnection(ExecutionEnvironment environment) {
ParametersList programParametersList = myJavaParameters.getProgramParametersList();
boolean execGoal = programParametersList.getList().stream().anyMatch(parameter ->
parameter.equals("exec:exec") || EXEC_MAVEN_PLUGIN_PATTERN.matcher(parameter).matches()
);
if (!execGoal) {
return null;
}
Project project = myRunConfiguration.getProject();
MavenRunnerParameters runnerParameters = myRunConfiguration.getRunnerParameters();
JavaParameters parameters = new JavaParameters();
RemoteConnection connection;
try {
// there's no easy and reliable way to know the version of target JRE, but without it there won't be any debugger agent settings
parameters.setJdk(JavaParametersUtil.createProjectJdk(project, null));
connection = DebuggerManagerImpl.createDebugParameters(
parameters, false, DebuggerSettings.getInstance().DEBUGGER_TRANSPORT, "", false);
}
catch (ExecutionException e) {
throw new RuntimeException("Cannot create debug connection", e);
}
String execArgsStr;
String execArgsPrefix = "-Dexec.args=";
int execArgsIndex = indexOf(programParametersList.getList(), (Condition<String>)s -> s.startsWith(execArgsPrefix));
if (execArgsIndex != -1) {
execArgsStr = programParametersList.get(execArgsIndex).substring(execArgsPrefix.length());
}
else {
execArgsStr = getExecArgsFromPomXml(project, runnerParameters);
}
ParametersList execArgs = new ParametersList();
execArgs.addAll(patchVmParameters(parameters.getVMParametersList()));
execArgs.addParametersString(execArgsStr);
String classPath = toSystemDependentName(parameters.getClassPath().getPathsString());
if (StringUtil.isNotEmpty(classPath)) {
appendToClassPath(execArgs, classPath);
}
String execArgsCommandLineArg = execArgsPrefix + execArgs.getParametersString();
if (execArgsIndex != -1) {
programParametersList.set(execArgsIndex, execArgsCommandLineArg);
}
else {
programParametersList.add(execArgsCommandLineArg);
}
return connection;
}
@Override
public boolean isPollConnection() {
return true;
}
private static String getExecArgsFromPomXml(Project project, MavenRunnerParameters runnerParameters) {
VirtualFile workingDir = VfsUtil.findFileByIoFile(runnerParameters.getWorkingDirFile(), false);
if (workingDir != null) {
String pomFileName = StringUtil.defaultIfEmpty(runnerParameters.getPomFileName(), MavenConstants.POM_XML);
VirtualFile pomFile = workingDir.findChild(pomFileName);
if (pomFile != null) {
MavenDomProjectModel projectModel = MavenDomUtil.getMavenDomProjectModel(project, pomFile);
if (projectModel != null) {
return StringUtil.notNullize(MavenPropertyResolver.resolve("${exec.args}", projectModel));
}
}
}
return "";
}
private static void appendToClassPath(ParametersList execArgs, String classPath) {
List<String> execArgsList = execArgs.getList();
int classPathIndex = execArgsList.indexOf("-classpath");
if (classPathIndex == -1) {
classPathIndex = execArgsList.indexOf("-cp");
}
if (classPathIndex == -1) {
execArgs.prependAll("-classpath", "%classpath" + File.pathSeparator + classPath);
}
else if (classPathIndex + 1 == execArgsList.size()) { // invalid command line, but we still have to patch it
execArgs.add("%classpath" + File.pathSeparator + classPath);
}
else {
String oldClassPath = execArgs.get(classPathIndex + 1);
execArgs.set(classPathIndex + 1, oldClassPath + File.pathSeparator + classPath);
}
}
}
}