Skip to content

Commit b50f897

Browse files
gnodetclaude
andcommitted
Extract shared session infrastructure into AbstractUpgradeStrategy
Move Maven session management (getSession, createMaven4Session, TransporterFactoryConfig, temp directory helpers, buildEffectiveModel) from PluginUpgradeStrategy into AbstractUpgradeStrategy to enable reuse across strategies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 17d7e46 commit b50f897

2 files changed

Lines changed: 139 additions & 198 deletions

File tree

impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/AbstractUpgradeStrategy.java

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,41 @@
1818
*/
1919
package org.apache.maven.cling.invoker.mvnup.goals;
2020

21+
import java.io.File;
22+
import java.nio.file.Files;
2123
import java.nio.file.Path;
24+
import java.util.Comparator;
2225
import java.util.HashMap;
2326
import java.util.HashSet;
27+
import java.util.List;
2428
import java.util.Map;
2529
import java.util.Set;
2630

2731
import eu.maveniverse.domtrip.Document;
2832
import eu.maveniverse.domtrip.Element;
2933
import eu.maveniverse.domtrip.maven.Coordinates;
3034
import eu.maveniverse.domtrip.maven.MavenPomElements;
35+
import org.apache.maven.api.RemoteRepository;
36+
import org.apache.maven.api.Session;
3137
import org.apache.maven.api.cli.mvnup.UpgradeOptions;
38+
import org.apache.maven.api.di.Named;
39+
import org.apache.maven.api.di.Provides;
40+
import org.apache.maven.api.model.Repository;
41+
import org.apache.maven.api.model.RepositoryPolicy;
42+
import org.apache.maven.api.services.ModelBuilder;
43+
import org.apache.maven.api.services.ModelBuilderRequest;
44+
import org.apache.maven.api.services.ModelBuilderResult;
45+
import org.apache.maven.api.services.RepositoryFactory;
46+
import org.apache.maven.api.services.Sources;
3247
import org.apache.maven.cling.invoker.mvnup.UpgradeContext;
48+
import org.apache.maven.impl.standalone.ApiRunner;
49+
import org.codehaus.plexus.components.secdispatcher.Dispatcher;
50+
import org.codehaus.plexus.components.secdispatcher.internal.dispatchers.LegacyDispatcher;
51+
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
52+
import org.eclipse.aether.spi.connector.transport.http.ChecksumExtractor;
53+
import org.eclipse.aether.spi.io.PathProcessor;
54+
import org.eclipse.aether.transport.file.FileTransporterFactory;
55+
import org.eclipse.aether.transport.jdk.JdkTransporterFactory;
3356

3457
import static eu.maveniverse.domtrip.maven.MavenPomElements.Elements.PARENT;
3558

@@ -47,6 +70,8 @@
4770
*/
4871
public abstract class AbstractUpgradeStrategy implements UpgradeStrategy {
4972

73+
private Session session;
74+
5075
/**
5176
* Template method that handles common logging and error handling.
5277
* Subclasses implement the actual upgrade logic in doApply().
@@ -185,4 +210,115 @@ public static Set<Coordinates> computeAllArtifactCoordinates(UpgradeContext cont
185210
context.info("Computed " + coordinatesByGAV.size() + " unique artifact(s) for inference");
186211
return new HashSet<>(coordinatesByGAV.values());
187212
}
213+
214+
protected Session getSession() {
215+
if (session == null) {
216+
session = createMaven4Session();
217+
}
218+
return session;
219+
}
220+
221+
private Session createMaven4Session() {
222+
Session session = ApiRunner.createSession(injector -> {
223+
injector.bindInstance(Dispatcher.class, new LegacyDispatcher());
224+
injector.bindImplicit(TransporterFactoryConfig.class);
225+
});
226+
227+
// TODO: we should read settings
228+
RemoteRepository central =
229+
session.createRemoteRepository(RemoteRepository.CENTRAL_ID, "https://repo.maven.apache.org/maven2");
230+
RemoteRepository snapshots = session.getService(RepositoryFactory.class)
231+
.createRemote(Repository.newBuilder()
232+
.id("apache-snapshots")
233+
.url("https://repository.apache.org/content/repositories/snapshots/")
234+
.releases(RepositoryPolicy.newBuilder().enabled("false").build())
235+
.snapshots(RepositoryPolicy.newBuilder().enabled("true").build())
236+
.build());
237+
238+
return session.withRemoteRepositories(List.of(central, snapshots));
239+
}
240+
241+
protected Path createTempProjectStructure(UpgradeContext context, Map<Path, Document> pomMap) throws Exception {
242+
Path tempDir = Files.createTempDirectory("mvnup-project-");
243+
context.debug("Created temp project directory: " + tempDir);
244+
245+
Path commonRoot = findCommonRoot(pomMap.keySet());
246+
context.debug("Common root: " + commonRoot);
247+
248+
for (Map.Entry<Path, Document> entry : pomMap.entrySet()) {
249+
Path originalPath = entry.getKey();
250+
Document document = entry.getValue();
251+
252+
Path relativePath = commonRoot.relativize(originalPath);
253+
Path tempPomPath = tempDir.resolve(relativePath);
254+
255+
Files.createDirectories(tempPomPath.getParent());
256+
Files.writeString(tempPomPath, document.toXml());
257+
context.debug("Wrote POM to temp location: " + tempPomPath);
258+
}
259+
260+
return tempDir;
261+
}
262+
263+
protected Path findCommonRoot(Set<Path> pomPaths) {
264+
Path commonRoot = null;
265+
for (Path pomPath : pomPaths) {
266+
Path parent = pomPath.getParent();
267+
if (parent == null) {
268+
parent = Path.of(".");
269+
}
270+
if (commonRoot == null) {
271+
commonRoot = parent;
272+
} else {
273+
while (!parent.startsWith(commonRoot)) {
274+
commonRoot = commonRoot.getParent();
275+
if (commonRoot == null) {
276+
break;
277+
}
278+
}
279+
}
280+
}
281+
return commonRoot;
282+
}
283+
284+
protected void cleanupTempDirectory(Path tempDir) {
285+
try {
286+
Files.walk(tempDir)
287+
.sorted(Comparator.reverseOrder())
288+
.map(Path::toFile)
289+
.forEach(File::delete);
290+
} catch (Exception e) {
291+
// Best effort cleanup
292+
}
293+
}
294+
295+
protected org.apache.maven.api.model.Model buildEffectiveModel(Path pomPath) {
296+
Session session = getSession();
297+
ModelBuilder modelBuilder = session.getService(ModelBuilder.class);
298+
299+
ModelBuilderRequest request = ModelBuilderRequest.builder()
300+
.session(session)
301+
.source(Sources.buildSource(pomPath))
302+
.requestType(ModelBuilderRequest.RequestType.BUILD_EFFECTIVE)
303+
.recursive(false)
304+
.build();
305+
306+
ModelBuilderResult result = modelBuilder.newSession().build(request);
307+
return result.getEffectiveModel();
308+
}
309+
310+
static class TransporterFactoryConfig {
311+
@Provides
312+
@Named(JdkTransporterFactory.NAME)
313+
static TransporterFactory jdkTransporterFactory(
314+
ChecksumExtractor checksumExtractor, PathProcessor pathProcessor) {
315+
return new JdkTransporterFactory(checksumExtractor, pathProcessor);
316+
}
317+
318+
@Provides
319+
@Named(FileTransporterFactory.NAME)
320+
static TransporterFactory fileTransporterFactory() {
321+
return new FileTransporterFactory();
322+
}
323+
}
188324
}

0 commit comments

Comments
 (0)