| /* |
| * 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.project; |
| |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.apache.maven.RepositoryUtils; |
| import org.apache.maven.artifact.Artifact; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.DependencyManagement; |
| import org.apache.maven.model.Exclusion; |
| 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.ArtifactType; |
| import org.eclipse.aether.artifact.ArtifactTypeRegistry; |
| 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.resolution.ArtifactResult; |
| import org.eclipse.aether.resolution.DependencyRequest; |
| import org.eclipse.aether.util.artifact.ArtifactIdUtils; |
| import org.eclipse.aether.util.artifact.JavaScopes; |
| import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| */ |
| @Named |
| @Singleton |
| public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver { |
| private final Logger logger = LoggerFactory.getLogger(getClass()); |
| private final RepositorySystem repoSystem; |
| private final List<RepositorySessionDecorator> decorators; |
| |
| @Inject |
| public DefaultProjectDependenciesResolver( |
| RepositorySystem repoSystem, List<RepositorySessionDecorator> decorators) { |
| this.repoSystem = repoSystem; |
| this.decorators = decorators; |
| } |
| |
| public DependencyResolutionResult resolve(DependencyResolutionRequest request) |
| throws DependencyResolutionException { |
| final RequestTrace trace = RequestTrace.newChild(null, request); |
| |
| final DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult(); |
| |
| final MavenProject project = request.getMavenProject(); |
| final DependencyFilter filter = request.getResolutionFilter(); |
| RepositorySystemSession session = request.getRepositorySession(); |
| ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); |
| |
| if (logger.isDebugEnabled() |
| && session.getConfigProperties().get(DependencyManagerUtils.CONFIG_PROP_VERBOSE) == null) { |
| DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession(session); |
| verbose.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE); |
| session = verbose; |
| } |
| |
| for (RepositorySessionDecorator decorator : decorators) { |
| RepositorySystemSession decorated = decorator.decorate(project, session); |
| if (decorated != null) { |
| session = decorated; |
| } |
| } |
| |
| CollectRequest collect = new CollectRequest(); |
| collect.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact())); |
| collect.setRequestContext("project"); |
| collect.setRepositories(project.getRemoteProjectRepositories()); |
| |
| if (project.getDependencyArtifacts() == null) { |
| for (Dependency dependency : project.getDependencies()) { |
| if (dependency.getGroupId() == null |
| || dependency.getGroupId().isEmpty() |
| || dependency.getArtifactId() == null |
| || dependency.getArtifactId().isEmpty() |
| || dependency.getVersion() == null |
| || dependency.getVersion().isEmpty()) { |
| // guard against case where best-effort resolution for invalid models is requested |
| continue; |
| } |
| collect.addDependency(RepositoryUtils.toDependency(dependency, stereotypes)); |
| } |
| } else { |
| Map<String, Dependency> dependencies = new HashMap<>(); |
| for (Dependency dependency : project.getDependencies()) { |
| String classifier = dependency.getClassifier(); |
| if (classifier == null) { |
| ArtifactType type = stereotypes.get(dependency.getType()); |
| if (type != null) { |
| classifier = type.getClassifier(); |
| } |
| } |
| String key = ArtifactIdUtils.toVersionlessId( |
| dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(), classifier); |
| dependencies.put(key, dependency); |
| } |
| for (Artifact artifact : project.getDependencyArtifacts()) { |
| String key = artifact.getDependencyConflictId(); |
| Dependency dependency = dependencies.get(key); |
| Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null; |
| org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency(artifact, exclusions); |
| if (!JavaScopes.SYSTEM.equals(dep.getScope()) |
| && dep.getArtifact().getFile() != null) { |
| // enable re-resolution |
| org.eclipse.aether.artifact.Artifact art = dep.getArtifact(); |
| art = art.setFile(null).setVersion(art.getBaseVersion()); |
| dep = dep.setArtifact(art); |
| } |
| collect.addDependency(dep); |
| } |
| } |
| |
| DependencyManagement depMgmt = project.getDependencyManagement(); |
| if (depMgmt != null) { |
| for (Dependency dependency : depMgmt.getDependencies()) { |
| collect.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes)); |
| } |
| } |
| |
| DependencyRequest depRequest = new DependencyRequest(collect, filter); |
| depRequest.setTrace(trace); |
| |
| DependencyNode node; |
| try { |
| collect.setTrace(RequestTrace.newChild(trace, depRequest)); |
| node = repoSystem.collectDependencies(session, collect).getRoot(); |
| result.setDependencyGraph(node); |
| } catch (DependencyCollectionException e) { |
| result.setDependencyGraph(e.getResult().getRoot()); |
| result.setCollectionErrors(e.getResult().getExceptions()); |
| |
| throw new DependencyResolutionException( |
| result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e); |
| } |
| |
| depRequest.setRoot(node); |
| |
| if (logger.isWarnEnabled()) { |
| for (DependencyNode child : node.getChildren()) { |
| if (!child.getRelocations().isEmpty()) { |
| org.eclipse.aether.artifact.Artifact relocated = |
| child.getDependency().getArtifact(); |
| String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact |
| ? ((org.apache.maven.repository.internal.RelocatedArtifact) relocated).getMessage() |
| : null; |
| logger.warn("The artifact " + child.getRelocations().get(0) + " has been relocated to " + relocated |
| + (message != null ? ": " + message : "")); |
| } |
| } |
| } |
| |
| if (logger.isDebugEnabled()) { |
| node.accept(new GraphLogger(project)); |
| } |
| |
| try { |
| process(result, repoSystem.resolveDependencies(session, depRequest).getArtifactResults()); |
| } catch (org.eclipse.aether.resolution.DependencyResolutionException e) { |
| process(result, e.getResult().getArtifactResults()); |
| |
| throw new DependencyResolutionException( |
| result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e); |
| } |
| |
| return result; |
| } |
| |
| private void process(DefaultDependencyResolutionResult result, Collection<ArtifactResult> results) { |
| for (ArtifactResult ar : results) { |
| DependencyNode node = ar.getRequest().getDependencyNode(); |
| if (ar.isResolved()) { |
| result.addResolvedDependency(node.getDependency()); |
| } else { |
| result.setResolutionErrors(node.getDependency(), ar.getExceptions()); |
| } |
| } |
| } |
| |
| // Keep this class in sync with org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver.GraphLogger |
| class GraphLogger implements DependencyVisitor { |
| |
| private final MavenProject project; |
| |
| private String indent = ""; |
| |
| GraphLogger(MavenProject project) { |
| this.project = project; |
| } |
| |
| 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(')'); |
| } |
| } else { |
| buffer.append(project.getGroupId()); |
| buffer.append(':').append(project.getArtifactId()); |
| buffer.append(':').append(project.getPackaging()); |
| buffer.append(':').append(project.getVersion()); |
| } |
| |
| logger.debug(buffer.toString()); |
| indent += " "; |
| return true; |
| } |
| |
| public boolean visitLeave(DependencyNode node) { |
| indent = indent.substring(0, indent.length() - 3); |
| return true; |
| } |
| } |
| } |