| /* |
| * 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.apache.maven.plugin.internal; |
| |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import java.util.Collection; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.apache.maven.RepositoryUtils; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.plugin.PluginResolutionException; |
| import org.eclipse.aether.DefaultRepositorySystemSession; |
| import org.eclipse.aether.RepositorySystem; |
| import org.eclipse.aether.RepositorySystemSession; |
| import org.eclipse.aether.RequestTrace; |
| import org.eclipse.aether.artifact.Artifact; |
| import org.eclipse.aether.artifact.DefaultArtifact; |
| import org.eclipse.aether.collection.CollectRequest; |
| import org.eclipse.aether.collection.DependencyCollectionException; |
| import org.eclipse.aether.graph.DependencyFilter; |
| import org.eclipse.aether.graph.DependencyNode; |
| import org.eclipse.aether.graph.DependencyVisitor; |
| import org.eclipse.aether.repository.RemoteRepository; |
| import org.eclipse.aether.resolution.ArtifactDescriptorException; |
| import org.eclipse.aether.resolution.ArtifactDescriptorRequest; |
| import org.eclipse.aether.resolution.ArtifactDescriptorResult; |
| import org.eclipse.aether.resolution.ArtifactRequest; |
| import org.eclipse.aether.resolution.ArtifactResolutionException; |
| import org.eclipse.aether.resolution.DependencyRequest; |
| import org.eclipse.aether.resolution.DependencyResolutionException; |
| import org.eclipse.aether.util.artifact.JavaScopes; |
| import org.eclipse.aether.util.filter.AndDependencyFilter; |
| import org.eclipse.aether.util.filter.ScopeDependencyFilter; |
| import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; |
| import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that |
| * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or |
| * deleted without prior notice. |
| * |
| * @since 3.0 |
| */ |
| @Named |
| @Singleton |
| public class DefaultPluginDependenciesResolver implements PluginDependenciesResolver { |
| private static final String REPOSITORY_CONTEXT = "plugin"; |
| |
| private final Logger logger = LoggerFactory.getLogger(getClass()); |
| |
| private final RepositorySystem repoSystem; |
| |
| private final List<MavenPluginDependenciesValidator> dependenciesValidators; |
| |
| @Inject |
| public DefaultPluginDependenciesResolver( |
| RepositorySystem repoSystem, List<MavenPluginDependenciesValidator> dependenciesValidators) { |
| this.repoSystem = repoSystem; |
| this.dependenciesValidators = dependenciesValidators; |
| } |
| |
| private Artifact toArtifact(Plugin plugin, RepositorySystemSession session) { |
| return new DefaultArtifact( |
| plugin.getGroupId(), |
| plugin.getArtifactId(), |
| null, |
| "jar", |
| plugin.getVersion(), |
| session.getArtifactTypeRegistry().get("maven-plugin")); |
| } |
| |
| public Artifact resolve(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session) |
| throws PluginResolutionException { |
| RequestTrace trace = RequestTrace.newChild(null, plugin); |
| |
| Artifact pluginArtifact = toArtifact(plugin, session); |
| |
| try { |
| DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session); |
| pluginSession.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, false)); |
| |
| ArtifactDescriptorRequest request = |
| new ArtifactDescriptorRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT); |
| request.setTrace(trace); |
| ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor(pluginSession, request); |
| |
| for (MavenPluginDependenciesValidator dependenciesValidator : dependenciesValidators) { |
| dependenciesValidator.validate(session, pluginArtifact, result); |
| } |
| |
| pluginArtifact = result.getArtifact(); |
| |
| if (logger.isWarnEnabled() && !result.getRelocations().isEmpty()) { |
| String message = pluginArtifact instanceof org.apache.maven.repository.internal.RelocatedArtifact |
| ? ": " + ((org.apache.maven.repository.internal.RelocatedArtifact) pluginArtifact).getMessage() |
| : ""; |
| logger.warn( |
| "The artifact {} has been relocated to {}{}", |
| result.getRelocations().get(0), |
| pluginArtifact, |
| message); |
| } |
| |
| String requiredMavenVersion = (String) result.getProperties().get("prerequisites.maven"); |
| if (requiredMavenVersion != null) { |
| Map<String, String> props = new LinkedHashMap<>(pluginArtifact.getProperties()); |
| props.put("requiredMavenVersion", requiredMavenVersion); |
| pluginArtifact = pluginArtifact.setProperties(props); |
| } |
| } catch (ArtifactDescriptorException e) { |
| throw new PluginResolutionException(plugin, e); |
| } |
| |
| try { |
| ArtifactRequest request = new ArtifactRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT); |
| request.setTrace(trace); |
| pluginArtifact = repoSystem.resolveArtifact(session, request).getArtifact(); |
| } catch (ArtifactResolutionException e) { |
| throw new PluginResolutionException(plugin, e); |
| } |
| |
| return pluginArtifact; |
| } |
| |
| /** |
| * @since 3.3.0 |
| */ |
| public DependencyNode resolveCoreExtension( |
| Plugin plugin, |
| DependencyFilter dependencyFilter, |
| List<RemoteRepository> repositories, |
| RepositorySystemSession session) |
| throws PluginResolutionException { |
| return resolveInternal(plugin, null /* pluginArtifact */, dependencyFilter, repositories, session); |
| } |
| |
| public DependencyNode resolve( |
| Plugin plugin, |
| Artifact pluginArtifact, |
| DependencyFilter dependencyFilter, |
| List<RemoteRepository> repositories, |
| RepositorySystemSession session) |
| throws PluginResolutionException { |
| return resolveInternal(plugin, pluginArtifact, dependencyFilter, repositories, session); |
| } |
| |
| private DependencyNode resolveInternal( |
| Plugin plugin, |
| Artifact pluginArtifact, |
| DependencyFilter dependencyFilter, |
| List<RemoteRepository> repositories, |
| RepositorySystemSession session) |
| throws PluginResolutionException { |
| RequestTrace trace = RequestTrace.newChild(null, plugin); |
| |
| if (pluginArtifact == null) { |
| pluginArtifact = toArtifact(plugin, session); |
| } |
| |
| DependencyFilter collectionFilter = new ScopeDependencyFilter("provided", "test"); |
| DependencyFilter resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, dependencyFilter); |
| |
| DependencyNode node; |
| |
| try { |
| DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session); |
| pluginSession.setDependencySelector(session.getDependencySelector()); |
| pluginSession.setDependencyGraphTransformer(session.getDependencyGraphTransformer()); |
| |
| CollectRequest request = new CollectRequest(); |
| request.setRequestContext(REPOSITORY_CONTEXT); |
| request.setRepositories(repositories); |
| request.setRoot(new org.eclipse.aether.graph.Dependency(pluginArtifact, null)); |
| for (Dependency dependency : plugin.getDependencies()) { |
| org.eclipse.aether.graph.Dependency pluginDep = |
| RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry()); |
| if (!JavaScopes.SYSTEM.equals(pluginDep.getScope())) { |
| pluginDep = pluginDep.setScope(JavaScopes.RUNTIME); |
| } |
| request.addDependency(pluginDep); |
| } |
| |
| DependencyRequest depRequest = new DependencyRequest(request, resolutionFilter); |
| depRequest.setTrace(trace); |
| |
| request.setTrace(RequestTrace.newChild(trace, depRequest)); |
| |
| node = repoSystem.collectDependencies(pluginSession, request).getRoot(); |
| |
| if (logger.isDebugEnabled()) { |
| node.accept(new GraphLogger()); |
| } |
| |
| depRequest.setRoot(node); |
| repoSystem.resolveDependencies(session, depRequest); |
| } catch (DependencyCollectionException e) { |
| throw new PluginResolutionException(plugin, e); |
| } catch (DependencyResolutionException e) { |
| throw new PluginResolutionException(plugin, e.getCause()); |
| } |
| |
| return node; |
| } |
| |
| // Keep this class in sync with org.apache.maven.project.DefaultProjectDependenciesResolver.GraphLogger |
| class GraphLogger implements DependencyVisitor { |
| |
| private String indent = ""; |
| |
| public boolean visitEnter(DependencyNode node) { |
| StringBuilder buffer = new StringBuilder(128); |
| buffer.append(indent); |
| org.eclipse.aether.graph.Dependency dep = node.getDependency(); |
| if (dep != null) { |
| org.eclipse.aether.artifact.Artifact art = dep.getArtifact(); |
| |
| buffer.append(art); |
| if (dep.getScope() != null && !dep.getScope().isEmpty()) { |
| buffer.append(':').append(dep.getScope()); |
| } |
| |
| if (dep.isOptional()) { |
| buffer.append(" (optional)"); |
| } |
| |
| // TODO We currently cannot tell which <dependencyManagement> section contained the management |
| // information. When the resolver provides this information, these log messages should be updated |
| // to contain it. |
| if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) { |
| final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node); |
| buffer.append(" (scope managed from "); |
| buffer.append(Objects.toString(premanagedScope, "default")); |
| buffer.append(')'); |
| } |
| |
| if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) { |
| final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node); |
| buffer.append(" (version managed from "); |
| buffer.append(Objects.toString(premanagedVersion, "default")); |
| buffer.append(')'); |
| } |
| |
| if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) { |
| final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node); |
| buffer.append(" (optionality managed from "); |
| buffer.append(Objects.toString(premanagedOptional, "default")); |
| buffer.append(')'); |
| } |
| |
| if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) { |
| final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions = |
| DependencyManagerUtils.getPremanagedExclusions(node); |
| |
| buffer.append(" (exclusions managed from "); |
| buffer.append(Objects.toString(premanagedExclusions, "default")); |
| buffer.append(')'); |
| } |
| |
| if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) { |
| final Map<String, String> premanagedProperties = |
| DependencyManagerUtils.getPremanagedProperties(node); |
| |
| buffer.append(" (properties managed from "); |
| buffer.append(Objects.toString(premanagedProperties, "default")); |
| buffer.append(')'); |
| } |
| } |
| |
| logger.debug(buffer.toString()); |
| indent += " "; |
| return true; |
| } |
| |
| public boolean visitLeave(DependencyNode node) { |
| indent = indent.substring(0, indent.length() - 3); |
| return true; |
| } |
| } |
| } |