Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiements with new build connection from plexus-build-extension #1940

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -13,22 +13,23 @@

package org.eclipse.m2e.internal.launch;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener2;

import org.codehaus.plexus.build.connect.TcpBuildConnection;
import org.codehaus.plexus.build.connect.TcpBuildConnection.ServerConnection;

import org.eclipse.m2e.core.embedder.ArtifactKey;
import org.eclipse.m2e.core.internal.launch.MavenEmbeddedRuntime;
import org.eclipse.m2e.internal.launch.MavenRuntimeLaunchSupport.VMArguments;
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge;
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenBuildConnection;
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenProjectBuildData;

@@ -70,23 +71,50 @@ public void launchesChanged(ILaunch[] launches) { // ignore

static void openListenerConnection(ILaunch launch, VMArguments arguments) {
try {
if(MavenLaunchUtils.getMavenRuntime(launch.getLaunchConfiguration()) instanceof MavenEmbeddedRuntime) {

Map<ArtifactKey, MavenProjectBuildData> projects = new ConcurrentHashMap<>();

MavenBuildConnection connection = M2EMavenBuildDataBridge.prepareConnection(
launch.getLaunchConfiguration().getName(),
d -> projects.put(new ArtifactKey(d.groupId, d.artifactId, d.version, null), d));

if(LAUNCH_PROJECT_DATA.putIfAbsent(launch, new MavenBuildConnectionData(projects, connection)) != null) {
connection.close();
throw new IllegalStateException(
"Maven bridge already created for launch of" + launch.getLaunchConfiguration().getName());
}
arguments.append(connection.getMavenVMArguments());
// if(MavenLaunchUtils.getMavenRuntime(launch.getLaunchConfiguration()) instanceof MavenEmbeddedRuntime) {
//
// Map<ArtifactKey, MavenProjectBuildData> projects = new ConcurrentHashMap<>();
//
// MavenBuildConnection connection = M2EMavenBuildDataBridge.prepareConnection(
// launch.getLaunchConfiguration().getName(),
// d -> projects.put(new ArtifactKey(d.groupId, d.artifactId, d.version, null), d));
//
// if(LAUNCH_PROJECT_DATA.putIfAbsent(launch, new MavenBuildConnectionData(projects, connection)) != null) {
// connection.close();
// throw new IllegalStateException(
// "Maven bridge already created for launch of" + launch.getLaunchConfiguration().getName());
// }
//
// arguments.append(connection.getMavenVMArguments());
// } else {
MavenRunState state = new MavenRunState();
ServerConnection con = TcpBuildConnection.createServer(msg -> {
System.out.println(msg);
return state.handleMessage(msg);
});
state.getProject(new ArtifactKey("test", "me", "0.0.1-SNAPSHOT", null)).thenAccept(rp -> rp.onStart(() -> {
System.out.println("project is started!!");
}));
File location = getJarLocation();
if(location != null) {
//TODO see bug https://issues.apache.org/jira/browse/MNG-8112
arguments.appendProperty("maven.ext.class.path", location.getAbsolutePath());
}
} catch(CoreException | IOException ex) { // ignore
con.setupProcess(arguments::appendProperty);
// }
} catch(Exception ex) { // ignore
ex.printStackTrace();
}
}

private static File getJarLocation() {
try {
return new File(TcpBuildConnection.class.getProtectionDomain().getCodeSource().getLocation().toURI());
} catch(Exception e) {
}
//TODO better way to find it?!?
//Maybe just consume as a (wrapped) bundle as we only need it to start the server not on the maven classpath!
return null;
}

static MavenProjectBuildData getBuildProject(ILaunch launch, String groupId, String artifactId, String version) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/********************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
********************************************************************************/

package org.eclipse.m2e.internal.launch;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

import org.codehaus.plexus.build.connect.Configuration;
import org.codehaus.plexus.build.connect.messages.InitMessage;
import org.codehaus.plexus.build.connect.messages.Message;
import org.codehaus.plexus.build.connect.messages.MojoMessage;
import org.codehaus.plexus.build.connect.messages.ProjectMessage;
import org.codehaus.plexus.build.connect.messages.ProjectsMessage;
import org.codehaus.plexus.build.connect.messages.SessionMessage;

import org.eclipse.m2e.core.embedder.ArtifactKey;


/**
* Captures the run state of a maven process
*/
public class MavenRunState {

private String mavenName;

private String mavenBuildNumber;

private String mavenVersion;

private String workingDirectory;

private final Map<ArtifactKey, CompletableFuture<RemoteMavenProject>> projects = new ConcurrentHashMap<>();

Map<String, String> handleMessage(Message msg) {
if(msg instanceof InitMessage init) {
this.mavenName = init.getProperty("versionProperties.distributionName");
this.mavenBuildNumber = init.getProperty("versionProperties.buildNumber");
this.mavenVersion = init.getProperty("versionProperties.version");
this.workingDirectory = init.getProperty("workingDirectory");
Map<String, String> config = new HashMap<String, String>();
config.put(Configuration.CONFIG_SEND_PROJECTS, "true");
return config;
}
if(msg instanceof ProjectsMessage projects) {
projects.projects().forEach(pi -> {
RemoteMavenProject project = new RemoteMavenProject(pi);
getProject(project.getArtifactKey()).complete(project);
});
}
if(msg instanceof ProjectMessage project) {
ArtifactKey key = new ArtifactKey(project.getGroupId(), project.getArtifactId(), project.getVersion(), null);
getProject(key).thenAccept(rp -> rp.handleEvent(project));
System.out.println("--- " + project.getType() + " --- " + key);
System.out.println();
System.out.println(project.getBaseDir());
return null;
}
if(msg instanceof MojoMessage mojo) {
System.out.println("--- " + mojo.getType() + " ---");
System.out.println(mojo.getGroupId() + ":" + mojo.getArtifactId() + ":" + mojo.getVersion() + " - "
+ mojo.getLifecyclePhase() + " [" + mojo.getExecutionId() + "] " + mojo.getGoal());
return null;
}
if(msg instanceof SessionMessage session) {
if(!session.isSessionStart()) {
projects.values().forEach(cf -> {
cf.thenAccept(rp -> rp.cancel());
cf.cancel(true);
});
projects.clear();
}
}
return null;
}

public CompletableFuture<RemoteMavenProject> getProject(ArtifactKey key) {
CompletableFuture<RemoteMavenProject> computeIfAbsent = projects.computeIfAbsent(key,
nil -> new CompletableFuture<>());
return computeIfAbsent;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/********************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
********************************************************************************/

package org.eclipse.m2e.internal.launch;

import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

import org.codehaus.plexus.build.connect.messages.ProjectMessage;
import org.codehaus.plexus.build.connect.messages.ProjectMessage.EventType;
import org.codehaus.plexus.build.connect.messages.ProjectsMessage.ProjectInfo;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.DefaultModelReader;

import org.eclipse.m2e.core.embedder.ArtifactKey;


/**
* Represents a maven project from a remote maven launch
*/
public class RemoteMavenProject {

private ArtifactKey artifactKey;

private Path baseDir;

private String modelString;

private Model model;

private CompletableFuture<?> starting = new CompletableFuture<>();

private CompletableFuture<Result> finished = new CompletableFuture<>();

RemoteMavenProject(ProjectInfo projectInfo) {
artifactKey = new ArtifactKey(projectInfo.getGroupId(), projectInfo.getArtifactId(), projectInfo.getVersion(),
null);
this.baseDir = projectInfo.getBaseDir();
this.modelString = projectInfo.getModel();
}

/**
* @return the artifactKey
*/
public ArtifactKey getArtifactKey() {
return this.artifactKey;
}

/**
* @return the baseDir
*/
public Path getBaseDir() {
return this.baseDir;
}

public synchronized Model getModel() {
if(model != null) {
return model;
}
try {
if(modelString == null) {
return model = new Model();
}
try {
return model = new DefaultModelReader().read(new StringReader(modelString), null);
} catch(IOException ex) {
return model = new Model();
}
} finally {
model = null;
}
}

public CompletableFuture<Void> onStart(Runnable runnable) {
return starting.thenAcceptAsync(nil -> runnable.run());
}

public CompletableFuture<Void> onFinish(Consumer<Result> consumer) {
return finished.thenAcceptAsync(result -> consumer.accept(result));
}

void handleEvent(ProjectMessage project) {
if(project.getType() == EventType.ProjectStarted) {
starting.complete(null);
} else if(project.getType() == EventType.ProjectSucceeded) {
finished.complete(Result.SUCCESS);
} else if(project.getType() == EventType.ProjectSkipped) {
finished.complete(Result.SKIPPED);
} else if(project.getType() == EventType.ProjectFailed) {
finished.complete(Result.FAILED);
}
}

void cancel() {
starting.cancel(true);
finished.cancel(true);
}

public static enum Result {
SUCCESS, FAILED, SKIPPED;
}

}
4 changes: 2 additions & 2 deletions org.eclipse.m2e.maven.runtime/pom.xml
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@
</parent>

<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
<version>3.9.900-SNAPSHOT</version>
<version>3.9.901-SNAPSHOT</version>
<packaging>jar</packaging>

<name>M2E Embedded Maven Runtime (includes Incubating components)</name>
@@ -30,7 +30,7 @@
<!-- maven core version -->
<maven-core.version>3.9.9</maven-core.version>
<!-- below are m2e-specific addons -->
<plexus-build-api.version>1.2.0</plexus-build-api.version>
<plexus-build-api.version>1.2.1-SNAPSHOT</plexus-build-api.version>
<jars.directory>target/jars</jars.directory>
<outputDirectory.sources>${project.build.directory}/classes-source</outputDirectory.sources>
<failIfMacSigningFailed>false</failIfMacSigningFailed>
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@
<dependency>
<groupId>org.eclipse.m2e</groupId>
<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
<version>3.9.900-SNAPSHOT</version>
<version>3.9.901-SNAPSHOT</version>
</dependency>
</dependencies>

Loading