diff --git a/m2e-maven-runtime/pom.xml b/m2e-maven-runtime/pom.xml
index 1df18714d3..fae76d80a0 100644
--- a/m2e-maven-runtime/pom.xml
+++ b/m2e-maven-runtime/pom.xml
@@ -68,7 +68,7 @@
<_nodefaultversion>true
<_snapshot>qualifier
- ${project.artifactId};singleton:=false
+ ${project.artifactId};singleton:=true
JavaSE-11
${project.name}
Eclipse.org - m2e
diff --git a/org.eclipse.m2e.core.ui.tests/src/org/eclipse/m2e/core/ui/tests/ConsoleTest.java b/org.eclipse.m2e.core.ui.tests/src/org/eclipse/m2e/core/ui/tests/ConsoleTest.java
index b0c261389a..54a8cc76d8 100644
--- a/org.eclipse.m2e.core.ui.tests/src/org/eclipse/m2e/core/ui/tests/ConsoleTest.java
+++ b/org.eclipse.m2e.core.ui.tests/src/org/eclipse/m2e/core/ui/tests/ConsoleTest.java
@@ -177,7 +177,7 @@ private static void assertLinkActivationOpensPartWithTitle(ConsoleHyperlinkPosit
}
@Test
- public void testConsole_automaticDebuggerAttachment() throws Exception {
+ public void testConsole_automaticDebuggerAttachment_explicit() throws Exception {
importMavenProjectIntoWorkspace(SIMPLE_PROJECT);
@@ -187,6 +187,16 @@ public void testConsole_automaticDebuggerAttachment() throws Exception {
assertDebugeePrintOutAndDebuggerLaunch(document, SIMPLE_PROJECT);
}
+ @Test
+ public void testConsole_automaticDebuggerAttachment_fromDebugLaunch() throws Exception {
+
+ importMavenProjectIntoWorkspace(SIMPLE_PROJECT);
+
+ IDocument document = runMavenBuild(projectLocVariable(SIMPLE_PROJECT), ILaunchManager.DEBUG_MODE);
+
+ assertDebugeePrintOutAndDebuggerLaunch(document, SIMPLE_PROJECT);
+ }
+
private static void assertDebugeePrintOutAndDebuggerLaunch(IDocument document, String debugLaunchName)
throws CoreException {
// Check for Listening debugee print-out
diff --git a/org.eclipse.m2e.debug/.classpath b/org.eclipse.m2e.debug/.classpath
new file mode 100644
index 0000000000..e801ebfb46
--- /dev/null
+++ b/org.eclipse.m2e.debug/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/org.eclipse.m2e.debug/.project b/org.eclipse.m2e.debug/.project
new file mode 100644
index 0000000000..386170634e
--- /dev/null
+++ b/org.eclipse.m2e.debug/.project
@@ -0,0 +1,34 @@
+
+
+ org.eclipse.m2e.debug
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/org.eclipse.m2e.debug/.settings/org.eclipse.core.resources.prefs b/org.eclipse.m2e.debug/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/org.eclipse.m2e.debug/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.eclipse.m2e.debug/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.m2e.debug/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..052ee6edbe
--- /dev/null
+++ b/org.eclipse.m2e.debug/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,10 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/org.eclipse.m2e.debug/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.m2e.debug/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000000..f897a7f1cb
--- /dev/null
+++ b/org.eclipse.m2e.debug/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.m2e.debug/META-INF/MANIFEST.MF b/org.eclipse.m2e.debug/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..a3e1cdc960
--- /dev/null
+++ b/org.eclipse.m2e.debug/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: M2E Debug Support
+Bundle-SymbolicName: org.eclipse.m2e.debug;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: Eclipse.org - m2e
+Fragment-Host: org.eclipse.m2e.maven.runtime
+Automatic-Module-Name: org.eclipse.m2e.debug
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Import-Package: javax.inject;version="1.0.0"
+Require-Bundle: org.eclipse.m2e.launching,
+ org.eclipse.debug.core,
+ org.eclipse.equinox.common,
+ org.eclipse.m2e.core
diff --git a/org.eclipse.m2e.debug/META-INF/sisu/javax.inject.Named b/org.eclipse.m2e.debug/META-INF/sisu/javax.inject.Named
new file mode 100644
index 0000000000..bde4a9a1c5
--- /dev/null
+++ b/org.eclipse.m2e.debug/META-INF/sisu/javax.inject.Named
@@ -0,0 +1,2 @@
+org.eclipse.m2e.debug.runtime.DebugEventSpy
+org.eclipse.m2e.debug.runtime.DebugExecutionListener
diff --git a/org.eclipse.m2e.debug/build.properties b/org.eclipse.m2e.debug/build.properties
new file mode 100644
index 0000000000..e3023e14e9
--- /dev/null
+++ b/org.eclipse.m2e.debug/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ fragment.xml
diff --git a/org.eclipse.m2e.debug/fragment.xml b/org.eclipse.m2e.debug/fragment.xml
new file mode 100644
index 0000000000..8a80d5bfe0
--- /dev/null
+++ b/org.eclipse.m2e.debug/fragment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.m2e.debug/pom.xml b/org.eclipse.m2e.debug/pom.xml
new file mode 100644
index 0000000000..394f522f07
--- /dev/null
+++ b/org.eclipse.m2e.debug/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+
+ org.eclipse.m2e
+ m2e-core
+ 1.16.0-SNAPSHOT
+
+
+ org.eclipse.m2e.debug
+ 1.18.0-SNAPSHOT
+ eclipse-plugin
+
+ M2E Debug Support for Maven Build Processes
+
+
+
+
+ org.eclipse.sisu
+ sisu-maven-plugin
+ 0.3.4
+
+
+
+ index-project
+ prepare-package
+
+ index
+
+
+ ${project.basedir}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugEventSpy.java b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugEventSpy.java
new file mode 100644
index 0000000000..23af66ae80
--- /dev/null
+++ b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugEventSpy.java
@@ -0,0 +1,126 @@
+package org.eclipse.m2e.debug.runtime;
+
+import static java.util.Map.entry;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.function.UnaryOperator;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.eventspy.AbstractEventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+import org.apache.maven.execution.ExecutionEvent.Type;
+import org.apache.maven.plugin.MojoExecution;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Named
+@Singleton
+public class DebugEventSpy extends AbstractEventSpy {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DebugEventSpy.class);
+
+ private static final String DEBUG_PORT_VARIABLE = "${debugPort}";
+ public static final String DEBUG_DATA_PROPERTY = "m2e.debug.support"; //$NON-NLS-1$
+
+ public static String getEnableDebugProperty() {
+ return "-D" + DebugEventSpy.DEBUG_DATA_PROPERTY + "=" + "true";
+ }
+
+ // TODO: name this entire fragment m2e.debug.extension to reflect that it is an
+ // extension to the maven-runtime?
+
+ // TODO: specify the debug setup of the supported plug-ins at a more suitable
+ // location. Ideally within the Maven-plugins directly (like for lifecycle
+ // mappings) LifecycleMappingFactory.readMavenPluginEmbeddedMetadata(), or with
+ // life-cylce mappins/connectors
+ // TODO: specify properties per Goal!
+ private static final Map>> ID_2_CONFIGURATION_INJECTOR = Map.of(
+ "org.apache.maven.plugins:maven-surefire-plugin", //
+ entry("debugForkedProcess",
+ v -> "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + DEBUG_PORT_VARIABLE
+ + " -Xnoagent -Djava.compiler=NONE"), // TODO: use Java-9 approach: agentlib:jdwp ?
+ "org.eclipse.tycho:tycho-surefire-plugin", entry("debugPort", v -> DEBUG_PORT_VARIABLE),
+ "org.eclipse.tycho.extras:tycho-eclipserun-plugin", //
+ entry("argLine", // TODO: use not deprecated approach with nested elements in jvmArgs
+ v -> "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + DEBUG_PORT_VARIABLE
+ + " -Xnoagent")); // TODO: use Java-9 approach: agentlib:jdwp ?
+
+ private boolean isDebugLaunch = false;
+
+ @Override
+ public void init(Context context) throws Exception {
+ Map data = context.getData();
+ Object userProperties = data.get("userProperties");
+ if (userProperties instanceof Properties) {
+ Properties properties = (Properties) userProperties;
+ isDebugLaunch = Boolean.parseBoolean(properties.getProperty(DEBUG_DATA_PROPERTY, "false"));
+ }
+ if (isDebugLaunch) {
+ LOGGER.debug("M2E - Automatic debugging of forked VMs enabled");
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ isDebugLaunch = false;
+ }
+
+ @Override
+ public void onEvent(Object event) throws Exception {
+ if (isDebugLaunch && event instanceof ExecutionEvent) {
+ ExecutionEvent executionEvent = (ExecutionEvent) event;
+ if (executionEvent.getType() == Type.MojoStarted) {
+ MojoExecution mojoExecution = executionEvent.getMojoExecution();
+ String id = mojoExecution.getGroupId() + ":" + mojoExecution.getArtifactId();
+
+ Entry> injector = ID_2_CONFIGURATION_INJECTOR.get(id);
+ if (injector != null) {
+ Xpp3Dom configuration = mojoExecution.getConfiguration();
+ int debugPort = getFreeDebugPort();
+ String debugElementName = injector.getKey();
+ Xpp3Dom debugElement = getOrCreateChild(configuration, debugElementName);
+ injectDebugSetupIntoConfiguration(debugElement, injector.getValue(), debugPort);
+
+ LOGGER.debug("M2E - Injected debug-port {} into configuration element <{}>", debugPort,
+ debugElementName);
+ }
+ }
+ }
+ }
+
+ private void injectDebugSetupIntoConfiguration(Xpp3Dom debugElement, UnaryOperator valueComputer,
+ int debugPort) {
+ String enhancedValue = valueComputer.apply(debugElement.getValue());
+ enhancedValue = enhancedValue.replace(DEBUG_PORT_VARIABLE, Integer.toString(debugPort));
+ debugElement.setValue(enhancedValue);
+ // TODO: handle other cases
+ // - nested elements
+ // - set(but do not overwrite),
+ // - append (check if already contained?)
+ }
+
+ private static Xpp3Dom getOrCreateChild(Xpp3Dom configuration, String name) {
+ Xpp3Dom child = configuration.getChild(name);
+ if (child != null) {
+ child.setInputLocation(null); // disconnect from actual source
+ } else {
+ child = new Xpp3Dom(name);
+ configuration.addChild(child);
+ }
+ return child;
+ }
+
+ private static int getFreeDebugPort() {
+ try (ServerSocket socket = new ServerSocket(0)) {
+ return socket.getLocalPort();
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+}
diff --git a/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugExecutionListener.java b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugExecutionListener.java
new file mode 100644
index 0000000000..8dc6ea121d
--- /dev/null
+++ b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/runtime/DebugExecutionListener.java
@@ -0,0 +1,31 @@
+package org.eclipse.m2e.debug.runtime;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.execution.MojoExecutionEvent;
+import org.apache.maven.execution.MojoExecutionListener;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+@Named
+@Singleton
+public class DebugExecutionListener implements MojoExecutionListener {
+ // TODO: this class is likely not necessary anymore
+
+ @Override
+ public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
+ Mojo mojo = event.getMojo();
+ }
+
+ @Override
+ public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void afterExecutionFailure(MojoExecutionEvent event) {
+ // TODO Auto-generated method stub
+ }
+
+}
diff --git a/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/setup/DebugLaunchParticipant.java b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/setup/DebugLaunchParticipant.java
new file mode 100644
index 0000000000..8e327acc60
--- /dev/null
+++ b/org.eclipse.m2e.debug/src/org/eclipse/m2e/debug/setup/DebugLaunchParticipant.java
@@ -0,0 +1,42 @@
+package org.eclipse.m2e.debug.setup;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+import org.eclipse.m2e.core.internal.launch.MavenEmbeddedRuntime;
+import org.eclipse.m2e.debug.runtime.DebugEventSpy;
+import org.eclipse.m2e.internal.launch.IMavenLaunchParticipant;
+import org.eclipse.m2e.internal.launch.MavenLaunchUtils;
+
+@SuppressWarnings("restriction")
+public class DebugLaunchParticipant implements IMavenLaunchParticipant {
+
+ @Override
+ public String getProgramArguments(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor) {
+ try {
+ if (MavenLaunchUtils.getMavenRuntime(configuration) instanceof MavenEmbeddedRuntime) {
+ return DebugEventSpy.getEnableDebugProperty();
+ }
+ } catch (CoreException e) { // assume false
+ }
+ return null;
+ }
+
+ @Override
+ public String getVMArguments(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List getSourceLookupParticipants(ILaunchConfiguration configuration,
+ ILaunch launch, IProgressMonitor monitor) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.feature/feature.xml b/org.eclipse.m2e.feature/feature.xml
index 4827f36b17..06500f24e3 100644
--- a/org.eclipse.m2e.feature/feature.xml
+++ b/org.eclipse.m2e.feature/feature.xml
@@ -179,4 +179,12 @@
version="0.0.0"
unpack="false"/>
+
+
diff --git a/org.eclipse.m2e.launching/src/org/eclipse/m2e/actions/ExecutePomAction.java b/org.eclipse.m2e.launching/src/org/eclipse/m2e/actions/ExecutePomAction.java
index 74d5c8d166..1a751af1dc 100644
--- a/org.eclipse.m2e.launching/src/org/eclipse/m2e/actions/ExecutePomAction.java
+++ b/org.eclipse.m2e.launching/src/org/eclipse/m2e/actions/ExecutePomAction.java
@@ -215,10 +215,6 @@ private ILaunchConfiguration createLaunchConfiguration(IContainer basedir, Strin
if(path != null) {
workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, path.toPortableString());
}
-
- // TODO when launching Maven with debugger consider to add the following property
- // -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -Xnoagent -Djava.compiler=NONE"
-
return workingCopy;
} catch(CoreException ex) {
log.error(ex.getMessage(), ex);
diff --git a/pom.xml b/pom.xml
index 2ecab5ae0f..853c1d9327 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,7 @@
org.eclipse.m2e.pde
org.eclipse.m2e.pde.ui
org.eclipse.m2e.pde.connector
+ org.eclipse.m2e.debug
org.eclipse.m2e.tests.common