From 7d25f0adbb258e1f26ece0264a5886457eda4bd9 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 23 Nov 2022 10:36:36 +0100 Subject: [PATCH 01/12] [MNG-7586] Update Maven Resolver to 1.9.2 Updates resolver to latest release. --- https://issues.apache.org/jira/browse/MNG-7586 --- .../mvnd/plugin/CliMavenPluginManager.java | 65 +++++++++++-------- ...onNamedLockFactoryAdapterFactoryImpl.java} | 19 +++--- pom.xml | 5 +- 3 files changed, 51 insertions(+), 38 deletions(-) rename daemon/src/main/java/org/mvndaemon/mvnd/syncontext/{DaemonNamedLockFactorySelector.java => DaemonNamedLockFactoryAdapterFactoryImpl.java} (64%) diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java index 9e3b7f836..8294e38f9 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Objects; import java.util.jar.JarFile; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import javax.inject.Inject; import javax.inject.Named; @@ -52,6 +53,7 @@ import org.apache.maven.plugin.ExtensionRealmCache; import org.apache.maven.plugin.InvalidPluginDescriptorException; import org.apache.maven.plugin.MavenPluginManager; +import org.apache.maven.plugin.MavenPluginPrerequisitesChecker; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoNotFoundException; @@ -79,7 +81,6 @@ 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; @@ -162,9 +163,6 @@ public class CliMavenPluginManager implements MavenPluginManager { @Inject private PluginDependenciesResolver pluginDependenciesResolver; - @Inject - private RuntimeInformation runtimeInformation; - @Inject private ExtensionRealmCache extensionRealmCache; @@ -174,6 +172,9 @@ public class CliMavenPluginManager implements MavenPluginManager { @Inject private PluginArtifactsCache pluginArtifactsCache; + @Inject + private List prerequisitesCheckers; + private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); @@ -183,18 +184,19 @@ public PluginDescriptor getPluginDescriptor( 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); + PluginDescriptor pluginDescriptor = + pluginDescriptorCache.get(cacheKey, (InvalidatingPluginDescriptorCache.PluginDescriptorSupplier) () -> { + org.eclipse.aether.artifact.Artifact artifact = + pluginDependenciesResolver.resolve(plugin, repositories, session); - Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact); + Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact); - PluginDescriptor descriptor = extractPluginDescriptor(pluginArtifact, plugin); + PluginDescriptor descriptor = extractPluginDescriptor(pluginArtifact, plugin); - descriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null)); + descriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null)); - return descriptor; - }); + return descriptor; + }); pluginDescriptor.setPlugin(plugin); @@ -294,19 +296,25 @@ public MojoDescriptor getMojoDescriptor( return mojoDescriptor; } - public void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { - String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion(); - if (StringUtils.isNotBlank(requiredMavenVersion)) { + @Override + public void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { + List prerequisiteExceptions = new ArrayList(); + this.prerequisitesCheckers.forEach((c) -> { 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()); + c.accept(pluginDescriptor); + } catch (IllegalStateException var4) { + prerequisiteExceptions.add(var4); } + }); + if (!prerequisiteExceptions.isEmpty()) { + String messages = + prerequisiteExceptions.stream().map(Throwable::getMessage).collect(Collectors.joining(", ")); + PluginIncompatibleException pie = new PluginIncompatibleException( + pluginDescriptor.getPlugin(), + "The plugin " + pluginDescriptor.getId() + " has unmet prerequisites: " + messages, + (Throwable) prerequisiteExceptions.get(0)); + prerequisiteExceptions.stream().skip(1L).forEach(pie::addSuppressed); + throw pie; } } @@ -351,11 +359,12 @@ public void setupPluginRealm( project.getRemotePluginRepositories(), session.getRepositorySession()); - PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get(cacheKey, () -> { - createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter); - return new PluginRealmCache.CacheRecord( - pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts()); - }); + PluginRealmCache.CacheRecord cacheRecord = + pluginRealmCache.get(cacheKey, (InvalidatingPluginRealmCache.PluginRealmSupplier) () -> { + createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter); + return new PluginRealmCache.CacheRecord( + pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts()); + }); if (cacheRecord != null) { pluginDescriptor.setClassRealm(cacheRecord.getRealm()); diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactorySelector.java b/daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactoryAdapterFactoryImpl.java similarity index 64% rename from daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactorySelector.java rename to daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactoryAdapterFactoryImpl.java index c6f73bac5..64ec7e0fe 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactorySelector.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/syncontext/DaemonNamedLockFactoryAdapterFactoryImpl.java @@ -22,24 +22,27 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import org.eclipse.aether.internal.impl.synccontext.named.FileGAVNameMapper; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; -import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelectorSupport; +import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl; +import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider; import org.eclipse.aether.named.NamedLockFactory; import org.eclipse.aether.named.providers.FileLockNamedLockFactory; import org.eclipse.sisu.Priority; /** - * Mvnd selector implementation: it differs from - * {@link org.eclipse.aether.internal.impl.synccontext.named.SimpleNamedLockFactorySelector} only by default values. + * Mvnd named lock factory implementation: it differs from + * {@link org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl} only by default values. */ @Singleton @Named @Priority(10) -public final class DaemonNamedLockFactorySelector extends NamedLockFactorySelectorSupport { +public final class DaemonNamedLockFactoryAdapterFactoryImpl extends NamedLockFactoryAdapterFactoryImpl { @Inject - public DaemonNamedLockFactorySelector( - final Map factories, final Map nameMappers) { - super(factories, FileLockNamedLockFactory.NAME, nameMappers, FileGAVNameMapper.NAME); + public DaemonNamedLockFactoryAdapterFactoryImpl( + final Map factories, + final Map nameMappers, + final RepositorySystemLifecycle lifecycle) { + super(factories, FileLockNamedLockFactory.NAME, nameMappers, FileGAVNameMapperProvider.NAME, lifecycle); } } diff --git a/pom.xml b/pom.xml index ba2439773..6fe472179 100644 --- a/pom.xml +++ b/pom.xml @@ -83,8 +83,9 @@ 3.21.0 5.9.1 1.2.11 - 4.0.0-alpha-2 - 1.8.2 + 4.0.0-alpha-3-SNAPSHOT + + 1.9.2-SNAPSHOT 1.7.35 0.3.5 From 591ab4fc701f81f8030bc8bd9463ca02f3bb0a88 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 23 Nov 2022 10:53:43 +0100 Subject: [PATCH 02/12] Remove CliMavenPluginManager which has the changed needed in alpha-3 --- .../org/apache/maven/cli/DaemonMavenCli.java | 3 - .../mvnd/plugin/CliMavenPluginManager.java | 831 ------------------ .../ValidatingConfigurationListener.java | 81 -- 3 files changed, 915 deletions(-) delete mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java delete mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java index 8108bb75f..57545bb7c 100644 --- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java +++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java @@ -70,7 +70,6 @@ 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; @@ -105,7 +104,6 @@ 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; @@ -527,7 +525,6 @@ protected void configure() { 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); } }); diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java deleted file mode 100644 index 8294e38f9..000000000 --- a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java +++ /dev/null @@ -1,831 +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.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.Reader; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.jar.JarFile; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -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.plugin.ContextEnabled; -import org.apache.maven.plugin.DebugConfigurationListener; -import org.apache.maven.plugin.ExtensionRealmCache; -import org.apache.maven.plugin.InvalidPluginDescriptorException; -import org.apache.maven.plugin.MavenPluginManager; -import org.apache.maven.plugin.MavenPluginPrerequisitesChecker; -import org.apache.maven.plugin.Mojo; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoNotFoundException; -import org.apache.maven.plugin.PluginArtifactsCache; -import org.apache.maven.plugin.PluginConfigurationException; -import org.apache.maven.plugin.PluginContainerException; -import org.apache.maven.plugin.PluginDescriptorCache; -import org.apache.maven.plugin.PluginDescriptorParsingException; -import org.apache.maven.plugin.PluginIncompatibleException; -import org.apache.maven.plugin.PluginManagerException; -import org.apache.maven.plugin.PluginParameterException; -import org.apache.maven.plugin.PluginParameterExpressionEvaluator; -import org.apache.maven.plugin.PluginRealmCache; -import org.apache.maven.plugin.PluginResolutionException; -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.MojoLogWrapper; -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.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.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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/* - * 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 { - - /** - *

- * PluginId => 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. - *

- * Note: 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"; - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @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 ExtensionRealmCache extensionRealmCache; - - @Inject - private PluginVersionResolver pluginVersionResolver; - - @Inject - private PluginArtifactsCache pluginArtifactsCache; - - @Inject - private List prerequisitesCheckers; - - private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); - - private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); - - public PluginDescriptor getPluginDescriptor( - Plugin plugin, List repositories, RepositorySystemSession session) - throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException { - PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session); - - PluginDescriptor pluginDescriptor = - pluginDescriptorCache.get(cacheKey, (InvalidatingPluginDescriptorCache.PluginDescriptorSupplier) () -> { - 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); - } - - List errors = new ArrayList<>(); - validate(pluginArtifact, pluginDescriptor, errors); - - if (!errors.isEmpty()) { - throw new InvalidPluginDescriptorException( - "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors); - } - - pluginDescriptor.setPluginArtifact(pluginArtifact); - - return pluginDescriptor; - } - - private void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List errors) { - if (!pluginArtifact.getGroupId().equals(pluginDescriptor.getGroupId())) { - errors.add("Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId()); - } - - if (!pluginArtifact.getArtifactId().equals(pluginDescriptor.getArtifactId())) { - errors.add("Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId()); - } - - if (!pluginArtifact.getBaseVersion().equals(pluginDescriptor.getVersion())) { - errors.add("Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion()); - } - } - - 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 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; - } - - @Override - public void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { - List prerequisiteExceptions = new ArrayList(); - this.prerequisitesCheckers.forEach((c) -> { - try { - c.accept(pluginDescriptor); - } catch (IllegalStateException var4) { - prerequisiteExceptions.add(var4); - } - }); - if (!prerequisiteExceptions.isEmpty()) { - String messages = - prerequisiteExceptions.stream().map(Throwable::getMessage).collect(Collectors.joining(", ")); - PluginIncompatibleException pie = new PluginIncompatibleException( - pluginDescriptor.getPlugin(), - "The plugin " + pluginDescriptor.getId() + " has unmet prerequisites: " + messages, - (Throwable) prerequisiteExceptions.get(0)); - prerequisiteExceptions.stream().skip(1L).forEach(pie::addSuppressed); - throw pie; - } - } - - public void setupPluginRealm( - PluginDescriptor pluginDescriptor, - MavenSession session, - ClassLoader parent, - List 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 pluginArtifacts = extensionRecord.getArtifacts(); - - for (ComponentDescriptor componentDescriptor : pluginDescriptor.getComponents()) { - componentDescriptor.setRealm(pluginRealm); - } - - pluginDescriptor.setClassRealm(pluginRealm); - pluginDescriptor.setArtifacts(pluginArtifacts); - } else { - Map foreignImports = calcImports(project, parent, imports); - - PluginRealmCache.Key cacheKey = pluginRealmCache.createKey( - plugin, - parent, - foreignImports, - filter, - project.getRemotePluginRepositories(), - session.getRepositorySession()); - - PluginRealmCache.CacheRecord cacheRecord = - pluginRealmCache.get(cacheKey, (InvalidatingPluginRealmCache.PluginRealmSupplier) () -> { - 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 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 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 toAetherArtifacts(final List pluginArtifacts) { - return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts)); - } - - private List toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) { - List artifacts = new ArrayList<>(nlg.getNodes().size()); - RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.emptyList(), null); - for (Iterator it = artifacts.iterator(); it.hasNext(); ) { - Artifact artifact = it.next(); - if (artifact.getFile() == null) { - it.remove(); - } - } - return Collections.unmodifiableList(artifacts); - } - - private Map calcImports(MavenProject project, ClassLoader parent, List imports) { - Map 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 getConfiguredMojo(Class 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 pluginContext = session.getPluginContext(pluginDescriptor, project); - - if (pluginContext != null) { - pluginContext.put("project", project); - - pluginContext.put("pluginDescriptor", pluginDescriptor); - - ((ContextEnabled) mojo).setPluginContext(pluginContext); - } - } - - if (mojo instanceof Mojo) { - org.slf4j.Logger mojoLogger = LoggerFactory.getLogger(mojoDescriptor.getImplementation()); - ((Mojo) mojo).setLog(new MojoLogWrapper(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 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 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 pluginRealms = - (Map) 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 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 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 resolveExtensionArtifacts( - Plugin extensionPlugin, List 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); - } -} diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java deleted file mode 100644 index a7aa258b8..000000000 --- a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java +++ /dev/null @@ -1,81 +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 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 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); - } - } -} From 7bb71727c9dba9dba4bf1b31d942ccf6b5c7503e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 23 Nov 2022 11:28:15 +0100 Subject: [PATCH 03/12] Align slf4j api with maven --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6fe472179..eb5f1ee96 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 4.0.0-alpha-3-SNAPSHOT 1.9.2-SNAPSHOT - 1.7.35 + 1.7.36 0.3.5 From f77e697cc1334ed6180b991960746c13dc7ae945 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 23 Nov 2022 15:18:44 +0100 Subject: [PATCH 04/12] Make sure the invoker being called from IT reuses the settings from the invoker running the IT --- integration-tests/src/test/projects/invoker/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/src/test/projects/invoker/pom.xml b/integration-tests/src/test/projects/invoker/pom.xml index f65cc1a14..013832596 100644 --- a/integration-tests/src/test/projects/invoker/pom.xml +++ b/integration-tests/src/test/projects/invoker/pom.xml @@ -89,6 +89,7 @@ ${project.build.directory}/it ${project.build.directory}/local-repo verify + ${project.basedir}/../settings.xml From e49707a4cb1695afabb6ddb6844abb3a50a5d8ab Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 24 Nov 2022 16:33:27 +0100 Subject: [PATCH 05/12] Revert "Remove CliMavenPluginManager which has the changed needed in alpha-3" This reverts commit 591ab4fc701f81f8030bc8bd9463ca02f3bb0a88. --- .../org/apache/maven/cli/DaemonMavenCli.java | 3 + .../mvnd/plugin/CliMavenPluginManager.java | 831 ++++++++++++++++++ .../ValidatingConfigurationListener.java | 81 ++ 3 files changed, 915 insertions(+) create mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java create mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java index 57545bb7c..8108bb75f 100644 --- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java +++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java @@ -70,6 +70,7 @@ 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; @@ -104,6 +105,7 @@ 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; @@ -525,6 +527,7 @@ protected void configure() { 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); } }); diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java new file mode 100644 index 000000000..8294e38f9 --- /dev/null +++ b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java @@ -0,0 +1,831 @@ +/* + * 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.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.Reader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.jar.JarFile; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +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.plugin.ContextEnabled; +import org.apache.maven.plugin.DebugConfigurationListener; +import org.apache.maven.plugin.ExtensionRealmCache; +import org.apache.maven.plugin.InvalidPluginDescriptorException; +import org.apache.maven.plugin.MavenPluginManager; +import org.apache.maven.plugin.MavenPluginPrerequisitesChecker; +import org.apache.maven.plugin.Mojo; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoNotFoundException; +import org.apache.maven.plugin.PluginArtifactsCache; +import org.apache.maven.plugin.PluginConfigurationException; +import org.apache.maven.plugin.PluginContainerException; +import org.apache.maven.plugin.PluginDescriptorCache; +import org.apache.maven.plugin.PluginDescriptorParsingException; +import org.apache.maven.plugin.PluginIncompatibleException; +import org.apache.maven.plugin.PluginManagerException; +import org.apache.maven.plugin.PluginParameterException; +import org.apache.maven.plugin.PluginParameterExpressionEvaluator; +import org.apache.maven.plugin.PluginRealmCache; +import org.apache.maven.plugin.PluginResolutionException; +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.MojoLogWrapper; +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.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.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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * 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 { + + /** + *

+ * PluginId => 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. + *

+ * Note: 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"; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @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 ExtensionRealmCache extensionRealmCache; + + @Inject + private PluginVersionResolver pluginVersionResolver; + + @Inject + private PluginArtifactsCache pluginArtifactsCache; + + @Inject + private List prerequisitesCheckers; + + private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); + + private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); + + public PluginDescriptor getPluginDescriptor( + Plugin plugin, List repositories, RepositorySystemSession session) + throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException { + PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session); + + PluginDescriptor pluginDescriptor = + pluginDescriptorCache.get(cacheKey, (InvalidatingPluginDescriptorCache.PluginDescriptorSupplier) () -> { + 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); + } + + List errors = new ArrayList<>(); + validate(pluginArtifact, pluginDescriptor, errors); + + if (!errors.isEmpty()) { + throw new InvalidPluginDescriptorException( + "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors); + } + + pluginDescriptor.setPluginArtifact(pluginArtifact); + + return pluginDescriptor; + } + + private void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List errors) { + if (!pluginArtifact.getGroupId().equals(pluginDescriptor.getGroupId())) { + errors.add("Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId()); + } + + if (!pluginArtifact.getArtifactId().equals(pluginDescriptor.getArtifactId())) { + errors.add("Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId()); + } + + if (!pluginArtifact.getBaseVersion().equals(pluginDescriptor.getVersion())) { + errors.add("Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion()); + } + } + + 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 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; + } + + @Override + public void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { + List prerequisiteExceptions = new ArrayList(); + this.prerequisitesCheckers.forEach((c) -> { + try { + c.accept(pluginDescriptor); + } catch (IllegalStateException var4) { + prerequisiteExceptions.add(var4); + } + }); + if (!prerequisiteExceptions.isEmpty()) { + String messages = + prerequisiteExceptions.stream().map(Throwable::getMessage).collect(Collectors.joining(", ")); + PluginIncompatibleException pie = new PluginIncompatibleException( + pluginDescriptor.getPlugin(), + "The plugin " + pluginDescriptor.getId() + " has unmet prerequisites: " + messages, + (Throwable) prerequisiteExceptions.get(0)); + prerequisiteExceptions.stream().skip(1L).forEach(pie::addSuppressed); + throw pie; + } + } + + public void setupPluginRealm( + PluginDescriptor pluginDescriptor, + MavenSession session, + ClassLoader parent, + List 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 pluginArtifacts = extensionRecord.getArtifacts(); + + for (ComponentDescriptor componentDescriptor : pluginDescriptor.getComponents()) { + componentDescriptor.setRealm(pluginRealm); + } + + pluginDescriptor.setClassRealm(pluginRealm); + pluginDescriptor.setArtifacts(pluginArtifacts); + } else { + Map foreignImports = calcImports(project, parent, imports); + + PluginRealmCache.Key cacheKey = pluginRealmCache.createKey( + plugin, + parent, + foreignImports, + filter, + project.getRemotePluginRepositories(), + session.getRepositorySession()); + + PluginRealmCache.CacheRecord cacheRecord = + pluginRealmCache.get(cacheKey, (InvalidatingPluginRealmCache.PluginRealmSupplier) () -> { + 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 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 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 toAetherArtifacts(final List pluginArtifacts) { + return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts)); + } + + private List toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) { + List artifacts = new ArrayList<>(nlg.getNodes().size()); + RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.emptyList(), null); + for (Iterator it = artifacts.iterator(); it.hasNext(); ) { + Artifact artifact = it.next(); + if (artifact.getFile() == null) { + it.remove(); + } + } + return Collections.unmodifiableList(artifacts); + } + + private Map calcImports(MavenProject project, ClassLoader parent, List imports) { + Map 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 getConfiguredMojo(Class 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 pluginContext = session.getPluginContext(pluginDescriptor, project); + + if (pluginContext != null) { + pluginContext.put("project", project); + + pluginContext.put("pluginDescriptor", pluginDescriptor); + + ((ContextEnabled) mojo).setPluginContext(pluginContext); + } + } + + if (mojo instanceof Mojo) { + org.slf4j.Logger mojoLogger = LoggerFactory.getLogger(mojoDescriptor.getImplementation()); + ((Mojo) mojo).setLog(new MojoLogWrapper(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 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 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 pluginRealms = + (Map) 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 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 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 resolveExtensionArtifacts( + Plugin extensionPlugin, List 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); + } +} diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java new file mode 100644 index 000000000..a7aa258b8 --- /dev/null +++ b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java @@ -0,0 +1,81 @@ +/* + * 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 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 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); + } + } +} From 0d24ad783aa43e10b12a40bd8550cb543a0ffa51 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 29 Nov 2022 08:33:54 +0100 Subject: [PATCH 06/12] Upgrade to released version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eb5f1ee96..d5bf452af 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ 1.2.11 4.0.0-alpha-3-SNAPSHOT - 1.9.2-SNAPSHOT + 1.9.2 1.7.36 0.3.5 From 8622ffbe5ac507f3679d8929dc1d543d69152ee9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 1 Dec 2022 16:46:10 +0100 Subject: [PATCH 07/12] Fix IT when mrm is disabled --- .../src/test/projects/invoker/pom.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/projects/invoker/pom.xml b/integration-tests/src/test/projects/invoker/pom.xml index 013832596..f118dc94f 100644 --- a/integration-tests/src/test/projects/invoker/pom.xml +++ b/integration-tests/src/test/projects/invoker/pom.xml @@ -89,7 +89,7 @@ ${project.build.directory}/it ${project.build.directory}/local-repo verify - ${project.basedir}/../settings.xml + ${settingsFile} @@ -104,4 +104,18 @@ + + + + settings + + + ${project.basedir}/../settings.xml + + + + ${project.basedir}/../settings.xml + + + \ No newline at end of file From dc4b5c71ac6ce3328c1515b96237f7f84f08554f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 23 Nov 2022 10:53:43 +0100 Subject: [PATCH 08/12] Remove CliMavenPluginManager which has the changed needed in alpha-3 --- .../org/apache/maven/cli/DaemonMavenCli.java | 3 - .../mvnd/plugin/CliMavenPluginManager.java | 831 ------------------ .../ValidatingConfigurationListener.java | 81 -- 3 files changed, 915 deletions(-) delete mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java delete mode 100644 daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java index 8108bb75f..57545bb7c 100644 --- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java +++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java @@ -70,7 +70,6 @@ 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; @@ -105,7 +104,6 @@ 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; @@ -527,7 +525,6 @@ protected void configure() { 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); } }); diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java deleted file mode 100644 index 8294e38f9..000000000 --- a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/CliMavenPluginManager.java +++ /dev/null @@ -1,831 +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.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.Reader; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.jar.JarFile; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -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.plugin.ContextEnabled; -import org.apache.maven.plugin.DebugConfigurationListener; -import org.apache.maven.plugin.ExtensionRealmCache; -import org.apache.maven.plugin.InvalidPluginDescriptorException; -import org.apache.maven.plugin.MavenPluginManager; -import org.apache.maven.plugin.MavenPluginPrerequisitesChecker; -import org.apache.maven.plugin.Mojo; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoNotFoundException; -import org.apache.maven.plugin.PluginArtifactsCache; -import org.apache.maven.plugin.PluginConfigurationException; -import org.apache.maven.plugin.PluginContainerException; -import org.apache.maven.plugin.PluginDescriptorCache; -import org.apache.maven.plugin.PluginDescriptorParsingException; -import org.apache.maven.plugin.PluginIncompatibleException; -import org.apache.maven.plugin.PluginManagerException; -import org.apache.maven.plugin.PluginParameterException; -import org.apache.maven.plugin.PluginParameterExpressionEvaluator; -import org.apache.maven.plugin.PluginRealmCache; -import org.apache.maven.plugin.PluginResolutionException; -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.MojoLogWrapper; -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.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.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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/* - * 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 { - - /** - *

- * PluginId => 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. - *

- * Note: 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"; - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @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 ExtensionRealmCache extensionRealmCache; - - @Inject - private PluginVersionResolver pluginVersionResolver; - - @Inject - private PluginArtifactsCache pluginArtifactsCache; - - @Inject - private List prerequisitesCheckers; - - private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); - - private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); - - public PluginDescriptor getPluginDescriptor( - Plugin plugin, List repositories, RepositorySystemSession session) - throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException { - PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session); - - PluginDescriptor pluginDescriptor = - pluginDescriptorCache.get(cacheKey, (InvalidatingPluginDescriptorCache.PluginDescriptorSupplier) () -> { - 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); - } - - List errors = new ArrayList<>(); - validate(pluginArtifact, pluginDescriptor, errors); - - if (!errors.isEmpty()) { - throw new InvalidPluginDescriptorException( - "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors); - } - - pluginDescriptor.setPluginArtifact(pluginArtifact); - - return pluginDescriptor; - } - - private void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List errors) { - if (!pluginArtifact.getGroupId().equals(pluginDescriptor.getGroupId())) { - errors.add("Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId()); - } - - if (!pluginArtifact.getArtifactId().equals(pluginDescriptor.getArtifactId())) { - errors.add("Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId()); - } - - if (!pluginArtifact.getBaseVersion().equals(pluginDescriptor.getVersion())) { - errors.add("Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion()); - } - } - - 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 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; - } - - @Override - public void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { - List prerequisiteExceptions = new ArrayList(); - this.prerequisitesCheckers.forEach((c) -> { - try { - c.accept(pluginDescriptor); - } catch (IllegalStateException var4) { - prerequisiteExceptions.add(var4); - } - }); - if (!prerequisiteExceptions.isEmpty()) { - String messages = - prerequisiteExceptions.stream().map(Throwable::getMessage).collect(Collectors.joining(", ")); - PluginIncompatibleException pie = new PluginIncompatibleException( - pluginDescriptor.getPlugin(), - "The plugin " + pluginDescriptor.getId() + " has unmet prerequisites: " + messages, - (Throwable) prerequisiteExceptions.get(0)); - prerequisiteExceptions.stream().skip(1L).forEach(pie::addSuppressed); - throw pie; - } - } - - public void setupPluginRealm( - PluginDescriptor pluginDescriptor, - MavenSession session, - ClassLoader parent, - List 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 pluginArtifacts = extensionRecord.getArtifacts(); - - for (ComponentDescriptor componentDescriptor : pluginDescriptor.getComponents()) { - componentDescriptor.setRealm(pluginRealm); - } - - pluginDescriptor.setClassRealm(pluginRealm); - pluginDescriptor.setArtifacts(pluginArtifacts); - } else { - Map foreignImports = calcImports(project, parent, imports); - - PluginRealmCache.Key cacheKey = pluginRealmCache.createKey( - plugin, - parent, - foreignImports, - filter, - project.getRemotePluginRepositories(), - session.getRepositorySession()); - - PluginRealmCache.CacheRecord cacheRecord = - pluginRealmCache.get(cacheKey, (InvalidatingPluginRealmCache.PluginRealmSupplier) () -> { - 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 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 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 toAetherArtifacts(final List pluginArtifacts) { - return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts)); - } - - private List toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) { - List artifacts = new ArrayList<>(nlg.getNodes().size()); - RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.emptyList(), null); - for (Iterator it = artifacts.iterator(); it.hasNext(); ) { - Artifact artifact = it.next(); - if (artifact.getFile() == null) { - it.remove(); - } - } - return Collections.unmodifiableList(artifacts); - } - - private Map calcImports(MavenProject project, ClassLoader parent, List imports) { - Map 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 getConfiguredMojo(Class 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 pluginContext = session.getPluginContext(pluginDescriptor, project); - - if (pluginContext != null) { - pluginContext.put("project", project); - - pluginContext.put("pluginDescriptor", pluginDescriptor); - - ((ContextEnabled) mojo).setPluginContext(pluginContext); - } - } - - if (mojo instanceof Mojo) { - org.slf4j.Logger mojoLogger = LoggerFactory.getLogger(mojoDescriptor.getImplementation()); - ((Mojo) mojo).setLog(new MojoLogWrapper(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 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 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 pluginRealms = - (Map) 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 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 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 resolveExtensionArtifacts( - Plugin extensionPlugin, List 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); - } -} diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java b/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java deleted file mode 100644 index a7aa258b8..000000000 --- a/daemon/src/main/java/org/mvndaemon/mvnd/plugin/ValidatingConfigurationListener.java +++ /dev/null @@ -1,81 +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 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 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); - } - } -} From 1a1616841cb5b27b2f5ea53e3ee16613fedd0cd9 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 10 Dec 2022 00:21:00 +0100 Subject: [PATCH 09/12] Fix IT --- .../test/java/org/mvndaemon/mvnd/it/SingleModuleNativeIT.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/org/mvndaemon/mvnd/it/SingleModuleNativeIT.java b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/SingleModuleNativeIT.java index 66a8b9d6a..ea4e71cf3 100644 --- a/integration-tests/src/test/java/org/mvndaemon/mvnd/it/SingleModuleNativeIT.java +++ b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/SingleModuleNativeIT.java @@ -90,7 +90,9 @@ protected void assertJVM(TestClientOutput o, Properties props) { } String mojoStartedLogMessage(Properties props, String pluginArtifactId, String mojo, String executionId) { - return "\\Q--- " + pluginArtifactId + ":" + props.getProperty(pluginArtifactId + ".version") + ":" + mojo + " (" + return "\\Q--- " + + pluginArtifactId.replace("maven-", "").replace("-plugin", "") + + ":" + props.getProperty(pluginArtifactId + ".version") + ":" + mojo + " (" + executionId + ") @ single-module ---\\E"; } } From a1854f5b33bf43caf07fdf47a975165a61b11c52 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 12 Dec 2022 10:48:59 +0100 Subject: [PATCH 10/12] Fix InvalidingPluginRealmCache --- .../cache/invalidating/InvalidatingPluginRealmCache.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/cache/invalidating/InvalidatingPluginRealmCache.java b/daemon/src/main/java/org/mvndaemon/mvnd/cache/invalidating/InvalidatingPluginRealmCache.java index 6817d8541..d832f27bc 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/cache/invalidating/InvalidatingPluginRealmCache.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/cache/invalidating/InvalidatingPluginRealmCache.java @@ -40,11 +40,6 @@ @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; @@ -83,6 +78,7 @@ public CacheRecord get(Key key) { return r != null ? r.record : null; } + @Override public CacheRecord get(Key key, PluginRealmSupplier supplier) throws PluginResolutionException, PluginContainerException { try { From 658cf8152a8a50d394145bcf8d849b15ab4aefc8 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 12 Dec 2022 23:36:49 +0100 Subject: [PATCH 11/12] Switch to released 4.0.0-alpha-3 (currently under vote) --- pom.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d5bf452af..0a7cc4986 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 3.21.0 5.9.1 1.2.11 - 4.0.0-alpha-3-SNAPSHOT + 4.0.0-alpha-3 1.9.2 1.7.36 @@ -319,6 +319,13 @@ + + + staging-alpha-3 + https://repository.apache.org/content/repositories/maven-1835/ + + + From 55deaf64ad5062d026a7cdd90cebe4b89aa8a6e3 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 15 Dec 2022 19:07:40 +0100 Subject: [PATCH 12/12] Remove staging repo --- pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pom.xml b/pom.xml index 0a7cc4986..7ce06724d 100644 --- a/pom.xml +++ b/pom.xml @@ -319,13 +319,6 @@ - - - staging-alpha-3 - https://repository.apache.org/content/repositories/maven-1835/ - - -