Upgrade to maven 3.9.1 and 4.0.0-alpha-5 and resolver 1.9.7 (#821)

This commit is contained in:
Guillaume Nodet
2023-03-20 13:28:07 +01:00
committed by GitHub
parent a59c7cd51c
commit 56435a05f6
6 changed files with 4 additions and 888 deletions

View File

@@ -73,7 +73,6 @@ import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.plugin.ExtensionRealmCache;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.PluginArtifactsCache;
import org.apache.maven.plugin.PluginRealmCache;
import org.apache.maven.plugin.version.PluginVersionResolver;
@@ -111,7 +110,6 @@ import org.mvndaemon.mvnd.logging.smart.BuildEventListener;
import org.mvndaemon.mvnd.logging.smart.LoggingExecutionListener;
import org.mvndaemon.mvnd.logging.smart.LoggingOutputStream;
import org.mvndaemon.mvnd.plugin.CachingPluginVersionResolver;
import org.mvndaemon.mvnd.plugin.CliMavenPluginManager;
import org.mvndaemon.mvnd.transfer.DaemonMavenTransferListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
@@ -239,7 +237,6 @@ public class DaemonMavenCli implements DaemonCli {
toolchains(cliRequest);
populateRequest(cliRequest);
encryption(cliRequest);
repository(cliRequest);
return execute(cliRequest);
} catch (ExitException e) {
return e.exitCode;
@@ -534,7 +531,6 @@ public class DaemonMavenCli implements DaemonCli {
bind(PluginArtifactsCache.class).to(InvalidatingPluginArtifactsCache.class);
bind(PluginRealmCache.class).to(InvalidatingPluginRealmCache.class);
bind(ProjectArtifactsCache.class).to(InvalidatingProjectArtifactsCache.class);
bind(MavenPluginManager.class).to(CliMavenPluginManager.class);
bind(PluginVersionResolver.class).to(CachingPluginVersionResolver.class);
}
});
@@ -680,13 +676,6 @@ public class DaemonMavenCli implements DaemonCli {
}
}
private void repository(CliRequest cliRequest) throws Exception {
if (cliRequest.commandLine.hasOption(CLIManager.LEGACY_LOCAL_REPOSITORY)
|| Boolean.getBoolean("maven.legacyLocalRepo")) {
cliRequest.request.setUseLegacyLocalRepository(true);
}
}
private void environment(String workingDir, Map<String, String> clientEnv) {
EnvHelper.environment(workingDir, clientEnv);
}

View File

@@ -42,11 +42,6 @@ import org.mvndaemon.mvnd.cache.CacheFactory;
@Priority(10)
public class InvalidatingPluginRealmCache extends DefaultPluginRealmCache {
@FunctionalInterface
public interface PluginRealmSupplier {
CacheRecord load() throws PluginResolutionException, PluginContainerException;
}
protected static class Record implements org.mvndaemon.mvnd.cache.CacheRecord {
final CacheRecord record;
@@ -85,6 +80,7 @@ public class InvalidatingPluginRealmCache extends DefaultPluginRealmCache {
return r != null ? r.record : null;
}
@Override
public CacheRecord get(Key key, PluginRealmSupplier supplier)
throws PluginResolutionException, PluginContainerException {
try {

View File

@@ -1,779 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.mvndaemon.mvnd.plugin;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.model.Plugin;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.*;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.plugin.internal.PluginDependenciesResolver;
import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
import org.apache.maven.plugin.version.PluginVersionRequest;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.plugin.version.PluginVersionResolver;
import org.apache.maven.project.ExtensionDescriptor;
import org.apache.maven.project.ExtensionDescriptorBuilder;
import org.apache.maven.project.MavenProject;
import org.apache.maven.rtinfo.RuntimeInformation;
import org.apache.maven.session.scope.internal.SessionScopeModule;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.ComponentConfigurator;
import org.codehaus.plexus.component.configurator.ConfigurationListener;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.configuration.PlexusConfigurationException;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.LoggerManager;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.util.filter.AndDependencyFilter;
import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
import org.eclipse.sisu.Priority;
import org.eclipse.sisu.Typed;
import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginDescriptorCache;
import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginRealmCache;
/*
* gnodet: This file is based on maven DefaultMavenPluginManager and changed in order
* to better support parallel builds. See https://github.com/apache/maven-mvnd/issues/310
*/
/**
* Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such
* that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build
* plugins as well as special purpose plugins like reports.
*
* @author Benjamin Bentmann
* @since 3.0
*/
@Singleton
@Named
@Priority(10)
@Typed(MavenPluginManager.class)
public class CliMavenPluginManager implements MavenPluginManager {
/**
* <p>
* PluginId =&gt; ExtensionRealmCache.CacheRecord map MavenProject context value key. The map is used to ensure the
* same class realm is used to load build extensions and load mojos for extensions=true plugins.
* </p>
* <strong>Note:</strong> This is part of internal implementation and may be changed or removed without notice
*
* @since 3.3.0
*/
public static final String KEY_EXTENSIONS_REALMS = CliMavenPluginManager.class.getName() + "/extensionsRealms";
@Inject
private Logger logger;
@Inject
private LoggerManager loggerManager;
@Inject
private PlexusContainer container;
@Inject
private ClassRealmManager classRealmManager;
@Inject
private InvalidatingPluginDescriptorCache pluginDescriptorCache;
@Inject
private InvalidatingPluginRealmCache pluginRealmCache;
@Inject
private PluginDependenciesResolver pluginDependenciesResolver;
@Inject
private RuntimeInformation runtimeInformation;
@Inject
private ExtensionRealmCache extensionRealmCache;
@Inject
private PluginVersionResolver pluginVersionResolver;
@Inject
private PluginArtifactsCache pluginArtifactsCache;
private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder();
private PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
public PluginDescriptor getPluginDescriptor(
Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException {
PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session);
PluginDescriptor pluginDescriptor = pluginDescriptorCache.get(cacheKey, () -> {
org.eclipse.aether.artifact.Artifact artifact =
pluginDependenciesResolver.resolve(plugin, repositories, session);
Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact);
PluginDescriptor descriptor = extractPluginDescriptor(pluginArtifact, plugin);
descriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null));
return descriptor;
});
pluginDescriptor.setPlugin(plugin);
return pluginDescriptor;
}
private PluginDescriptor extractPluginDescriptor(Artifact pluginArtifact, Plugin plugin)
throws PluginDescriptorParsingException, InvalidPluginDescriptorException {
PluginDescriptor pluginDescriptor = null;
File pluginFile = pluginArtifact.getFile();
try {
if (pluginFile.isFile()) {
try (JarFile pluginJar = new JarFile(pluginFile, false)) {
ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getPluginDescriptorLocation());
if (pluginDescriptorEntry != null) {
InputStream is = pluginJar.getInputStream(pluginDescriptorEntry);
pluginDescriptor = parsePluginDescriptor(is, plugin, pluginFile.getAbsolutePath());
}
}
} else {
File pluginXml = new File(pluginFile, getPluginDescriptorLocation());
if (pluginXml.isFile()) {
try (InputStream is = new BufferedInputStream(new FileInputStream(pluginXml))) {
pluginDescriptor = parsePluginDescriptor(is, plugin, pluginXml.getAbsolutePath());
}
}
}
if (pluginDescriptor == null) {
throw new IOException("No plugin descriptor found at " + getPluginDescriptorLocation());
}
} catch (IOException e) {
throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e);
}
MavenPluginValidator validator = new MavenPluginValidator(pluginArtifact);
validator.validate(pluginDescriptor);
if (validator.hasErrors()) {
throw new InvalidPluginDescriptorException(
"Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", validator.getErrors());
}
pluginDescriptor.setPluginArtifact(pluginArtifact);
return pluginDescriptor;
}
private String getPluginDescriptorLocation() {
return "META-INF/maven/plugin.xml";
}
private PluginDescriptor parsePluginDescriptor(InputStream is, Plugin plugin, String descriptorLocation)
throws PluginDescriptorParsingException {
try {
Reader reader = ReaderFactory.newXmlReader(is);
PluginDescriptor pluginDescriptor = builder.build(reader, descriptorLocation);
return pluginDescriptor;
} catch (IOException | PlexusConfigurationException e) {
throw new PluginDescriptorParsingException(plugin, descriptorLocation, e);
}
}
public MojoDescriptor getMojoDescriptor(
Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
InvalidPluginDescriptorException {
PluginDescriptor pluginDescriptor = getPluginDescriptor(plugin, repositories, session);
MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal);
if (mojoDescriptor == null) {
throw new MojoNotFoundException(goal, pluginDescriptor);
}
return mojoDescriptor;
}
public void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException {
String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion();
if (StringUtils.isNotBlank(requiredMavenVersion)) {
try {
if (!runtimeInformation.isMavenVersion(requiredMavenVersion)) {
throw new PluginIncompatibleException(
pluginDescriptor.getPlugin(),
"The plugin " + pluginDescriptor.getId() + " requires Maven version "
+ requiredMavenVersion);
}
} catch (RuntimeException e) {
logger.warn("Could not verify plugin's Maven prerequisite: " + e.getMessage());
}
}
}
public void setupPluginRealm(
PluginDescriptor pluginDescriptor,
MavenSession session,
ClassLoader parent,
List<String> imports,
DependencyFilter filter)
throws PluginResolutionException, PluginContainerException {
Plugin plugin = pluginDescriptor.getPlugin();
MavenProject project = session.getCurrentProject();
if (plugin.isExtensions()) {
ExtensionRealmCache.CacheRecord extensionRecord;
try {
RepositorySystemSession repositorySession = session.getRepositorySession();
extensionRecord = setupExtensionsRealm(project, plugin, repositorySession);
} catch (PluginManagerException e) {
// extensions realm is expected to be fully setup at this point
// any exception means a problem in maven code, not a user error
throw new IllegalStateException(e);
}
ClassRealm pluginRealm = extensionRecord.getRealm();
List<Artifact> pluginArtifacts = extensionRecord.getArtifacts();
for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
componentDescriptor.setRealm(pluginRealm);
}
pluginDescriptor.setClassRealm(pluginRealm);
pluginDescriptor.setArtifacts(pluginArtifacts);
} else {
Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports);
PluginRealmCache.Key cacheKey = pluginRealmCache.createKey(
plugin,
parent,
foreignImports,
filter,
project.getRemotePluginRepositories(),
session.getRepositorySession());
PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get(cacheKey, () -> {
createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter);
return new PluginRealmCache.CacheRecord(
pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts());
});
if (cacheRecord != null) {
pluginDescriptor.setClassRealm(cacheRecord.getRealm());
pluginDescriptor.setArtifacts(new ArrayList<>(cacheRecord.getArtifacts()));
for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
componentDescriptor.setRealm(cacheRecord.getRealm());
}
}
pluginRealmCache.register(project, cacheKey, cacheRecord);
}
}
private void createPluginRealm(
PluginDescriptor pluginDescriptor,
MavenSession session,
ClassLoader parent,
Map<String, ClassLoader> foreignImports,
DependencyFilter filter)
throws PluginResolutionException, PluginContainerException {
Plugin plugin = Objects.requireNonNull(pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null");
Artifact pluginArtifact = Objects.requireNonNull(
pluginDescriptor.getPluginArtifact(), "pluginDescriptor.pluginArtifact cannot be null");
MavenProject project = session.getCurrentProject();
final ClassRealm pluginRealm;
final List<Artifact> pluginArtifacts;
RepositorySystemSession repositorySession = session.getRepositorySession();
DependencyFilter dependencyFilter = project.getExtensionDependencyFilter();
dependencyFilter = AndDependencyFilter.newInstance(dependencyFilter, filter);
DependencyNode root = pluginDependenciesResolver.resolve(
plugin,
RepositoryUtils.toArtifact(pluginArtifact),
dependencyFilter,
project.getRemotePluginRepositories(),
repositorySession);
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
root.accept(nlg);
pluginArtifacts = toMavenArtifacts(root, nlg);
if (parent == null) {
parent = new URLClassLoader(new URL[0]);
}
pluginRealm = classRealmManager.createPluginRealm(
plugin, parent, null, foreignImports, toAetherArtifacts(pluginArtifacts));
discoverPluginComponents(pluginRealm, plugin, pluginDescriptor);
pluginDescriptor.setClassRealm(pluginRealm);
pluginDescriptor.setArtifacts(pluginArtifacts);
}
private void discoverPluginComponents(
final ClassRealm pluginRealm, Plugin plugin, PluginDescriptor pluginDescriptor)
throws PluginContainerException {
try {
if (pluginDescriptor != null) {
for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
componentDescriptor.setRealm(pluginRealm);
container.addComponentDescriptor(componentDescriptor);
}
}
((DefaultPlexusContainer) container)
.discoverComponents(
pluginRealm, new SessionScopeModule(container), new MojoExecutionScopeModule(container));
} catch (ComponentLookupException | CycleDetectedInComponentGraphException e) {
throw new PluginContainerException(
plugin,
pluginRealm,
"Error in component graph of plugin " + plugin.getId() + ": " + e.getMessage(),
e);
}
}
private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) {
return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
}
private List<Artifact> toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) {
List<Artifact> artifacts = new ArrayList<>(nlg.getNodes().size());
RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.<String>emptyList(), null);
for (Iterator<Artifact> it = artifacts.iterator(); it.hasNext(); ) {
Artifact artifact = it.next();
if (artifact.getFile() == null) {
it.remove();
}
}
return Collections.unmodifiableList(artifacts);
}
private Map<String, ClassLoader> calcImports(MavenProject project, ClassLoader parent, List<String> imports) {
Map<String, ClassLoader> foreignImports = new HashMap<>();
ClassLoader projectRealm = project.getClassRealm();
if (projectRealm != null) {
foreignImports.put("", projectRealm);
} else {
foreignImports.put("", classRealmManager.getMavenApiRealm());
}
if (parent != null && imports != null) {
for (String parentImport : imports) {
foreignImports.put(parentImport, parent);
}
}
return foreignImports;
}
public <T> T getConfiguredMojo(Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution)
throws PluginConfigurationException, PluginContainerException {
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
if (logger.isDebugEnabled()) {
logger.debug("Configuring mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm);
}
// We are forcing the use of the plugin realm for all lookups that might occur during
// the lifecycle that is part of the lookup. Here we are specifically trying to keep
// lookups that occur in contextualize calls in line with the right realm.
ClassRealm oldLookupRealm = container.setLookupRealm(pluginRealm);
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(pluginRealm);
try {
T mojo;
try {
mojo = container.lookup(mojoInterface, mojoDescriptor.getRoleHint());
} catch (ComponentLookupException e) {
Throwable cause = e.getCause();
while (cause != null
&& !(cause instanceof LinkageError)
&& !(cause instanceof ClassNotFoundException)) {
cause = cause.getCause();
}
if ((cause instanceof NoClassDefFoundError) || (cause instanceof ClassNotFoundException)) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
+ pluginDescriptor.getId() + "'. A required class is missing: "
+ cause.getMessage());
pluginRealm.display(ps);
throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
} else if (cause instanceof LinkageError) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
+ pluginDescriptor.getId() + "' due to an API incompatibility: "
+ e.getClass().getName() + ": " + cause.getMessage());
pluginRealm.display(ps);
throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
}
throw new PluginContainerException(
mojoDescriptor,
pluginRealm,
"Unable to load the mojo '" + mojoDescriptor.getGoal()
+ "' (or one of its required components) from the plugin '"
+ pluginDescriptor.getId() + "'",
e);
}
if (mojo instanceof ContextEnabled) {
MavenProject project = session.getCurrentProject();
Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
if (pluginContext != null) {
pluginContext.put("project", project);
pluginContext.put("pluginDescriptor", pluginDescriptor);
((ContextEnabled) mojo).setPluginContext(pluginContext);
}
}
if (mojo instanceof Mojo) {
Logger mojoLogger = loggerManager.getLoggerForComponent(mojoDescriptor.getImplementation());
((Mojo) mojo).setLog(new DefaultLog(mojoLogger));
}
Xpp3Dom dom = mojoExecution.getConfiguration();
PlexusConfiguration pomConfiguration;
if (dom == null) {
pomConfiguration = new XmlPlexusConfiguration("configuration");
} else {
pomConfiguration = new XmlPlexusConfiguration(dom);
}
ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
populatePluginFields(mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator);
return mojo;
} finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
container.setLookupRealm(oldLookupRealm);
}
}
private void populatePluginFields(
Object mojo,
MojoDescriptor mojoDescriptor,
ClassRealm pluginRealm,
PlexusConfiguration configuration,
ExpressionEvaluator expressionEvaluator)
throws PluginConfigurationException {
ComponentConfigurator configurator = null;
String configuratorId = mojoDescriptor.getComponentConfigurator();
if (StringUtils.isEmpty(configuratorId)) {
configuratorId = "basic";
}
try {
// TODO could the configuration be passed to lookup and the configurator known to plexus via the descriptor
// so that this method could entirely be handled by a plexus lookup?
configurator = container.lookup(ComponentConfigurator.class, configuratorId);
ConfigurationListener listener = new DebugConfigurationListener(logger);
ValidatingConfigurationListener validator =
new ValidatingConfigurationListener(mojo, mojoDescriptor, listener);
logger.debug(
"Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId + " configurator -->");
configurator.configureComponent(mojo, configuration, expressionEvaluator, pluginRealm, validator);
logger.debug("-- end configuration --");
Collection<Parameter> missingParameters = validator.getMissingParameters();
if (!missingParameters.isEmpty()) {
if ("basic".equals(configuratorId)) {
throw new PluginParameterException(mojoDescriptor, new ArrayList<>(missingParameters));
} else {
/*
* NOTE: Other configurators like the map-oriented one don't call into the listener, so do it the
* hard way.
*/
validateParameters(mojoDescriptor, configuration, expressionEvaluator);
}
}
} catch (ComponentConfigurationException e) {
String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
if (e.getFailedConfiguration() != null) {
message += " for parameter " + e.getFailedConfiguration().getName();
}
message += ": " + e.getMessage();
throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), message, e);
} catch (ComponentLookupException e) {
throw new PluginConfigurationException(
mojoDescriptor.getPluginDescriptor(),
"Unable to retrieve component configurator " + configuratorId + " for configuration of mojo "
+ mojoDescriptor.getId(),
e);
} catch (NoClassDefFoundError e) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
+ e.getMessage());
pluginRealm.display(ps);
throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
} catch (LinkageError e) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId()
+ ": " + e.getClass().getName() + ": " + e.getMessage());
pluginRealm.display(ps);
throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
} finally {
if (configurator != null) {
try {
container.release(configurator);
} catch (ComponentLifecycleException e) {
logger.debug("Failed to release mojo configurator - ignoring.");
}
}
}
}
private void validateParameters(
MojoDescriptor mojoDescriptor, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator)
throws ComponentConfigurationException, PluginParameterException {
if (mojoDescriptor.getParameters() == null) {
return;
}
List<Parameter> invalidParameters = new ArrayList<>();
for (Parameter parameter : mojoDescriptor.getParameters()) {
if (!parameter.isRequired()) {
continue;
}
Object value = null;
PlexusConfiguration config = configuration.getChild(parameter.getName(), false);
if (config != null) {
String expression = config.getValue(null);
try {
value = expressionEvaluator.evaluate(expression);
if (value == null) {
value = config.getAttribute("default-value", null);
}
} catch (ExpressionEvaluationException e) {
String msg = "Error evaluating the expression '" + expression + "' for configuration value '"
+ configuration.getName() + "'";
throw new ComponentConfigurationException(configuration, msg, e);
}
}
if (value == null && (config == null || config.getChildCount() <= 0)) {
invalidParameters.add(parameter);
}
}
if (!invalidParameters.isEmpty()) {
throw new PluginParameterException(mojoDescriptor, invalidParameters);
}
}
public void releaseMojo(Object mojo, MojoExecution mojoExecution) {
if (mojo != null) {
try {
container.release(mojo);
} catch (ComponentLifecycleException e) {
String goalExecId = mojoExecution.getGoal();
if (mojoExecution.getExecutionId() != null) {
goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
}
logger.debug("Error releasing mojo for " + goalExecId, e);
}
}
}
public ExtensionRealmCache.CacheRecord setupExtensionsRealm(
MavenProject project, Plugin plugin, RepositorySystemSession session) throws PluginManagerException {
@SuppressWarnings("unchecked")
Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
(Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue(KEY_EXTENSIONS_REALMS);
if (pluginRealms == null) {
pluginRealms = new HashMap<>();
project.setContextValue(KEY_EXTENSIONS_REALMS, pluginRealms);
}
final String pluginKey = plugin.getId();
ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get(pluginKey);
if (extensionRecord != null) {
return extensionRecord;
}
final List<RemoteRepository> repositories = project.getRemotePluginRepositories();
// resolve plugin version as necessary
if (plugin.getVersion() == null) {
PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(plugin, session, repositories);
try {
plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
} catch (PluginVersionResolutionException e) {
throw new PluginManagerException(plugin, e.getMessage(), e);
}
}
// resolve plugin artifacts
List<Artifact> artifacts;
PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey(plugin, null, repositories, session);
PluginArtifactsCache.CacheRecord recordArtifacts;
try {
recordArtifacts = pluginArtifactsCache.get(cacheKey);
} catch (PluginResolutionException e) {
throw new PluginManagerException(plugin, e.getMessage(), e);
}
if (recordArtifacts != null) {
artifacts = recordArtifacts.getArtifacts();
} else {
try {
artifacts = resolveExtensionArtifacts(plugin, repositories, session);
recordArtifacts = pluginArtifactsCache.put(cacheKey, artifacts);
} catch (PluginResolutionException e) {
pluginArtifactsCache.put(cacheKey, e);
pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
throw new PluginManagerException(plugin, e.getMessage(), e);
}
}
pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
// create and cache extensions realms
final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey(artifacts);
extensionRecord = extensionRealmCache.get(extensionKey);
if (extensionRecord == null) {
ClassRealm extensionRealm = classRealmManager.createExtensionRealm(plugin, toAetherArtifacts(artifacts));
// TODO figure out how to use the same PluginDescriptor when running mojos
PluginDescriptor pluginDescriptor = null;
if (plugin.isExtensions() && !artifacts.isEmpty()) {
// ignore plugin descriptor parsing errors at this point
// these errors will reported during calculation of project build execution plan
try {
pluginDescriptor = extractPluginDescriptor(artifacts.get(0), plugin);
} catch (PluginDescriptorParsingException | InvalidPluginDescriptorException e) {
// ignore, see above
}
}
discoverPluginComponents(extensionRealm, plugin, pluginDescriptor);
ExtensionDescriptor extensionDescriptor = null;
Artifact extensionArtifact = artifacts.get(0);
try {
extensionDescriptor = extensionDescriptorBuilder.build(extensionArtifact.getFile());
} catch (IOException e) {
String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
if (logger.isDebugEnabled()) {
logger.error(message, e);
} else {
logger.error(message);
}
}
extensionRecord = extensionRealmCache.put(extensionKey, extensionRealm, extensionDescriptor, artifacts);
}
extensionRealmCache.register(project, extensionKey, extensionRecord);
pluginRealms.put(pluginKey, extensionRecord);
return extensionRecord;
}
private List<Artifact> resolveExtensionArtifacts(
Plugin extensionPlugin, List<RemoteRepository> repositories, RepositorySystemSession session)
throws PluginResolutionException {
DependencyNode root = pluginDependenciesResolver.resolve(extensionPlugin, null, null, repositories, session);
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
root.accept(nlg);
return toMavenArtifacts(root, nlg);
}
}

View File

@@ -1,82 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.mvndaemon.mvnd.plugin;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
import org.codehaus.plexus.component.configurator.ConfigurationListener;
/**
* A configuration listener to help validate the plugin configuration. For instance, check for required but missing
* parameters.
*
* @author Benjamin Bentmann
*/
class ValidatingConfigurationListener implements ConfigurationListener {
private final Object mojo;
private final ConfigurationListener delegate;
private final Map<String, Parameter> missingParameters;
ValidatingConfigurationListener(Object mojo, MojoDescriptor mojoDescriptor, ConfigurationListener delegate) {
this.mojo = mojo;
this.delegate = delegate;
this.missingParameters = new HashMap<>();
if (mojoDescriptor.getParameters() != null) {
for (Parameter param : mojoDescriptor.getParameters()) {
if (param.isRequired()) {
missingParameters.put(param.getName(), param);
}
}
}
}
public Collection<Parameter> getMissingParameters() {
return missingParameters.values();
}
public void notifyFieldChangeUsingSetter(String fieldName, Object value, Object target) {
delegate.notifyFieldChangeUsingSetter(fieldName, value, target);
if (mojo == target) {
notify(fieldName, value);
}
}
public void notifyFieldChangeUsingReflection(String fieldName, Object value, Object target) {
delegate.notifyFieldChangeUsingReflection(fieldName, value, target);
if (mojo == target) {
notify(fieldName, value);
}
}
private void notify(String fieldName, Object value) {
if (value != null) {
missingParameters.remove(fieldName);
}
}
}

View File

@@ -226,7 +226,6 @@ public class DaemonMavenCli implements DaemonCli {
toolchains(cliRequest);
populateRequest(cliRequest);
encryption(cliRequest);
repository(cliRequest);
return execute(cliRequest);
} catch (ExitException e) {
return e.exitCode;
@@ -662,13 +661,6 @@ public class DaemonMavenCli implements DaemonCli {
}
}
private void repository(CliRequest cliRequest) throws Exception {
if (cliRequest.commandLine.hasOption(CLIManager.LEGACY_LOCAL_REPOSITORY)
|| Boolean.getBoolean("maven.legacyLocalRepo")) {
cliRequest.request.setUseLegacyLocalRepository(true);
}
}
private void environment(String workingDir, Map<String, String> clientEnv) {
EnvHelper.environment(workingDir, clientEnv);
}

View File

@@ -88,11 +88,11 @@
<jline.version>3.23.0</jline.version>
<junit.jupiter.version>5.9.2</junit.jupiter.version>
<logback.version>1.2.11</logback.version>
<maven.version>4.0.0-alpha-4</maven.version>
<maven3.version>3.9.0</maven3.version>
<maven.version>4.0.0-alpha-5</maven.version>
<maven3.version>3.9.1</maven3.version>
<maven4.version>${maven.version}</maven4.version>
<!-- Keep in sync with Maven -->
<maven.resolver.version>1.9.4</maven.resolver.version>
<maven.resolver.version>1.9.7</maven.resolver.version>
<slf4j.version>1.7.36</slf4j.version>
<sisu.version>0.9.0.M1</sisu.version>