mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[maven][IDEA-373161] maven compatibility with maven 4 rc
(cherry picked from commit cbbf16794fac04ac4b00e74072568afc28ad377d) IJ-CR-166737 GitOrigin-RevId: e2c45eaa8fade4c3e7cdf48fc342f2488d3c30bb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a1c7c5b229
commit
791ef44df3
@@ -0,0 +1,6 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40;
|
||||
|
||||
public interface InvokerWithoutCoreExtensions {
|
||||
void disableCoreExtensions();
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40;
|
||||
|
||||
import com.intellij.maven.server.m40.compat.Maven40InvokerRequestFactory;
|
||||
import com.intellij.maven.server.m40.utils.*;
|
||||
import com.intellij.maven.server.telemetry.MavenServerOpenTelemetry;
|
||||
import com.intellij.openapi.util.text.StringUtilRt;
|
||||
import org.apache.maven.*;
|
||||
import org.apache.maven.api.*;
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.Logger;
|
||||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||
import org.apache.maven.api.services.ArtifactResolver;
|
||||
import org.apache.maven.api.services.ArtifactResolverResult;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
@@ -21,7 +22,6 @@ import org.apache.maven.artifact.factory.ArtifactFactory;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.bridge.MavenRepositorySystem;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvokerRequest;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
||||
import org.apache.maven.execution.*;
|
||||
import org.apache.maven.internal.impl.DefaultSessionFactory;
|
||||
@@ -61,6 +61,7 @@ import org.jetbrains.idea.maven.server.*;
|
||||
import org.jetbrains.idea.maven.server.security.MavenToken;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
@@ -71,7 +72,7 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.maven.server.m40.utils.Maven40ModelConverter.convertRemoteRepositories;
|
||||
import static org.apache.maven.cling.invoker.Utils.getCanonicalPath;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase {
|
||||
private final @NotNull Maven40Invoker myMavenInvoker;
|
||||
@@ -171,22 +172,6 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase {
|
||||
.build();
|
||||
|
||||
MavenParser mavenParser = new MavenParser() {
|
||||
@Override
|
||||
public MavenInvokerRequest getInvokerRequest(LocalContext context) {
|
||||
return new Maven40InvokerRequest(
|
||||
context.parserRequest,
|
||||
context.parsingFailed,
|
||||
context.cwd,
|
||||
context.installationDirectory,
|
||||
context.userHomeDirectory,
|
||||
context.userProperties,
|
||||
context.systemProperties,
|
||||
context.topDirectory,
|
||||
context.rootDirectory,
|
||||
context.extensions,
|
||||
(MavenOptions)context.options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getRootDirectory(LocalContext context) {
|
||||
Path rootDir = super.getRootDirectory(context);
|
||||
@@ -201,7 +186,7 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase {
|
||||
InvokerRequest invokerRequest;
|
||||
List<Logger.Entry> entries = new ArrayList<>();
|
||||
try {
|
||||
invokerRequest = mavenParser.parseInvocation(parserRequest);
|
||||
invokerRequest = Maven40InvokerRequestFactory.createProxy(mavenParser.parseInvocation(parserRequest));
|
||||
entries.addAll(invokerRequest.parserRequest().logger().drain());
|
||||
myContainer = myMavenInvoker.invokeAndGetContext(invokerRequest).lookup;
|
||||
}
|
||||
@@ -217,6 +202,7 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase {
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if(myContainer == null) throw new IllegalStateException("Cannot create maven container");
|
||||
|
||||
myAlwaysUpdateSnapshots = commandLineOptions.contains("-U") || commandLineOptions.contains("--update-snapshots");
|
||||
|
||||
@@ -1135,4 +1121,15 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase {
|
||||
throw wrapToSerializableRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Path getCanonicalPath(Path path) {
|
||||
requireNonNull(path, "path");
|
||||
try {
|
||||
return path.toRealPath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return getCanonicalPath(path.getParent()).resolve(path.getFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40.compat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
|
||||
/**
|
||||
* Resident invoker implementation, specialization of Maven Invoker, but keeps Maven instance resident. This implies, that
|
||||
* things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure
|
||||
* that subsequent call is right for the resident instance (ie no env change or different extension needed).
|
||||
* This implementation "pre-populates" MavenContext with pre-existing stuff (except for very first call)
|
||||
* and does not let DI container to be closed.
|
||||
*/
|
||||
public class CompatResidentMavenInvoker extends MavenInvoker {
|
||||
|
||||
private final ConcurrentHashMap<String, MavenContext> residentContext;
|
||||
|
||||
public CompatResidentMavenInvoker(Lookup protoLookup) {
|
||||
super(protoLookup, null);
|
||||
this.residentContext = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws InvokerException {
|
||||
ArrayList<Exception> exceptions = new ArrayList<>();
|
||||
for (MavenContext context : residentContext.values()) {
|
||||
try {
|
||||
context.doCloseContainer();
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
if (!exceptions.isEmpty()) {
|
||||
InvokerException exception = new InvokerException("Could not cleanly shut down context pool");
|
||||
exceptions.forEach(exception::addSuppressed);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MavenContext createContext(InvokerRequest invokerRequest) {
|
||||
// TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more)
|
||||
// and allow multiple instances per JVM, this may become a pool? derive key based in invokerRequest?
|
||||
MavenContext result = residentContext.computeIfAbsent(
|
||||
"resident",
|
||||
k -> MavenContextFactory.createMavenContext(invokerRequest));
|
||||
return copyIfDifferent(result, invokerRequest);
|
||||
}
|
||||
|
||||
protected MavenContext copyIfDifferent(MavenContext mavenContext, InvokerRequest invokerRequest) {
|
||||
if (invokerRequest == mavenContext.invokerRequest) {
|
||||
return mavenContext;
|
||||
}
|
||||
MavenContext shadow = MavenContextFactory.createMavenContext(invokerRequest);
|
||||
|
||||
// we carry over only "resident" things
|
||||
shadow.containerCapsule = mavenContext.containerCapsule;
|
||||
shadow.lookup = mavenContext.lookup;
|
||||
shadow.eventSpyDispatcher = mavenContext.eventSpyDispatcher;
|
||||
shadow.maven = mavenContext.maven;
|
||||
|
||||
return shadow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40.compat;
|
||||
|
||||
import com.intellij.maven.server.m40.InvokerWithoutCoreExtensions;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Maven40InvokerRequestFactory {
|
||||
|
||||
private static final Map<String, Method> INVOKER_METHODS = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Method m : InvokerRequest.class.getMethods()) {
|
||||
INVOKER_METHODS.put(m.getName(), m);
|
||||
}
|
||||
}
|
||||
|
||||
public static InvokerRequest createProxy(InvokerRequest invokerRequest) {
|
||||
return (InvokerRequest)Proxy.newProxyInstance(
|
||||
Maven40InvokerRequestFactory.class.getClassLoader(),
|
||||
new Class[]{InvokerRequest.class, InvokerWithoutCoreExtensions.class},
|
||||
new InvokerProxyHandler(invokerRequest)
|
||||
);
|
||||
}
|
||||
|
||||
private static class InvokerProxyHandler implements InvocationHandler {
|
||||
|
||||
private final InvokerRequest myInvokerRequest;
|
||||
private boolean coreExtensionsDisabled = false;
|
||||
|
||||
|
||||
public InvokerProxyHandler(InvokerRequest invoker) {
|
||||
myInvokerRequest = invoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("disableCoreExtensions")) {
|
||||
coreExtensionsDisabled = true;
|
||||
return null;
|
||||
}
|
||||
else if (method.getName().equals("coreExtensions")) {
|
||||
if (coreExtensionsDisabled) return Optional.empty();
|
||||
return myInvokerRequest.coreExtensions();
|
||||
}
|
||||
else if (method.getName().equals("toString")) {
|
||||
return "[Proxy]:" + myInvokerRequest.toString();
|
||||
}
|
||||
else if (method.getName().equals("hashCode")) {
|
||||
return myInvokerRequest.hashCode();
|
||||
}
|
||||
else {
|
||||
Method realMethod = Maven40InvokerRequestFactory.INVOKER_METHODS.get(method.getName());
|
||||
if (realMethod == null || (args != null && args.length > 0)) {
|
||||
throw new UnsupportedOperationException(method.getName() + " is not supported in this IDEA version");
|
||||
}
|
||||
return realMethod.invoke(myInvokerRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40.compat;
|
||||
|
||||
import com.intellij.util.text.VersionComparatorUtil;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.Options;
|
||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.jetbrains.idea.maven.server.MavenServerEmbedder.MAVEN_EMBEDDER_VERSION;
|
||||
|
||||
public class MavenContextFactory {
|
||||
public static MavenContext createMavenContext(InvokerRequest invokerRequest) {
|
||||
String mavenVersion = System.getProperty(MAVEN_EMBEDDER_VERSION);
|
||||
if (VersionComparatorUtil.compare(mavenVersion, "4.0.0-rc-3") == 0) {
|
||||
return new MavenContext(invokerRequest, false);
|
||||
}
|
||||
else {
|
||||
Constructor<?>[] constructors = MavenContext.class.getConstructors();
|
||||
if (constructors.length != 1) throw new UnsupportedOperationException("MavenContext incompatibility with current IDEA version");
|
||||
try {
|
||||
MavenOptions options = getOptions(invokerRequest);
|
||||
return (MavenContext)constructors[0].newInstance(invokerRequest, false, options);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new UnsupportedOperationException("MavenContext incompatibility with current IDEA version", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable MavenOptions getOptions(InvokerRequest invokerRequest) {
|
||||
try {
|
||||
Method method = InvokerRequest.class.getMethod("options");
|
||||
Optional<Options> options = (Optional<Options>)method.invoke(invokerRequest);
|
||||
return (MavenOptions)options.orElse(null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new UnsupportedOperationException("MavenContext incompatibility with current IDEA version", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,8 +277,8 @@ public final class Maven40ApiModelConverter {
|
||||
public static MavenArtifact convertArtifactAndPath(Artifact artifact, Path artifactPath, File localRepository) {
|
||||
return new MavenArtifact(artifact.getGroupId(),
|
||||
artifact.getArtifactId(),
|
||||
artifact.getVersion().asString(),
|
||||
artifact.getVersion().asString(),
|
||||
artifact.getVersion().toString(),
|
||||
artifact.getVersion().toString(),
|
||||
"", //artifact.getType(),
|
||||
artifact.getClassifier(),
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40.utils;
|
||||
|
||||
import com.intellij.maven.server.m40.compat.CompatResidentMavenInvoker;
|
||||
import com.intellij.maven.server.m40.InvokerWithoutCoreExtensions;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
import org.apache.maven.cling.invoker.mvn.resident.ResidentMavenInvoker;
|
||||
import org.apache.maven.execution.MavenExecutionRequest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.server.MavenServerGlobals;
|
||||
|
||||
public class Maven40Invoker extends ResidentMavenInvoker {
|
||||
public class Maven40Invoker extends CompatResidentMavenInvoker {
|
||||
MavenContext myContext = null;
|
||||
|
||||
public Maven40Invoker(ProtoLookup protoLookup) {
|
||||
@@ -28,10 +29,11 @@ public class Maven40Invoker extends ResidentMavenInvoker {
|
||||
activateLogging(context);
|
||||
helpOrVersionAndMayExit(context);
|
||||
preCommands(context);
|
||||
//noinspection CastToIncompatibleInterface
|
||||
tryRunAndRetryOnFailure(
|
||||
"container",
|
||||
() -> container(context),
|
||||
() -> ((Maven40InvokerRequest)context.invokerRequest).disableCoreExtensions()
|
||||
() -> ((InvokerWithoutCoreExtensions)context.invokerRequest).disableCoreExtensions()
|
||||
);
|
||||
postContainer(context);
|
||||
pushUserProperties(context); // after PropertyContributor SPI
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.maven.server.m40.utils;
|
||||
|
||||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.api.cli.extensions.CoreExtension;
|
||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvokerRequest;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Maven40InvokerRequest extends MavenInvokerRequest {
|
||||
public Maven40InvokerRequest(ParserRequest parserRequest,
|
||||
boolean parseFailed,
|
||||
Path cwd,
|
||||
Path installationDirectory,
|
||||
Path userHomeDirectory,
|
||||
Map<String, String> userProperties,
|
||||
Map<String, String> systemProperties,
|
||||
Path topDirectory,
|
||||
Path rootDirectory,
|
||||
List<CoreExtension> coreExtensions,
|
||||
MavenOptions options) {
|
||||
super(parserRequest, parseFailed, cwd, installationDirectory, userHomeDirectory, userProperties, systemProperties, topDirectory,
|
||||
rootDirectory, coreExtensions, options);
|
||||
}
|
||||
|
||||
private boolean coreExtensionsDisabled = false;
|
||||
|
||||
public void disableCoreExtensions() {
|
||||
coreExtensionsDisabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<CoreExtension>> coreExtensions() {
|
||||
if (coreExtensionsDisabled) return Optional.empty();
|
||||
return super.coreExtensions();
|
||||
}
|
||||
}
|
||||
@@ -1384,6 +1384,7 @@ class DependenciesImportingTest : MavenMultiVersionImportingTestCase() {
|
||||
|
||||
@Test
|
||||
fun testPropertyInTheManagedModuleDependencyVersionOfPomType() = runBlocking {
|
||||
// Registry.get("maven.server.debug").setValue(true, testRootDisposable)
|
||||
createProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
@@ -1899,6 +1900,7 @@ class DependenciesImportingTest : MavenMultiVersionImportingTestCase() {
|
||||
|
||||
@Test
|
||||
fun testDoNoRemoveUnusedLibraryIfItWasChanged() = runBlocking {
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user