1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project;
20
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import javax.inject.Inject;
27 import javax.inject.Named;
28 import javax.inject.Singleton;
29 import org.apache.maven.RepositoryUtils;
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.model.Dependency;
32 import org.apache.maven.model.DependencyManagement;
33 import org.apache.maven.model.Exclusion;
34 import org.codehaus.plexus.util.StringUtils;
35 import org.eclipse.aether.DefaultRepositorySystemSession;
36 import org.eclipse.aether.RepositorySystem;
37 import org.eclipse.aether.RepositorySystemSession;
38 import org.eclipse.aether.RequestTrace;
39 import org.eclipse.aether.artifact.ArtifactType;
40 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
41 import org.eclipse.aether.collection.CollectRequest;
42 import org.eclipse.aether.collection.DependencyCollectionException;
43 import org.eclipse.aether.graph.DependencyFilter;
44 import org.eclipse.aether.graph.DependencyNode;
45 import org.eclipse.aether.graph.DependencyVisitor;
46 import org.eclipse.aether.resolution.ArtifactResult;
47 import org.eclipse.aether.resolution.DependencyRequest;
48 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
49 import org.eclipse.aether.util.artifact.JavaScopes;
50 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54
55
56
57 @Named
58 @Singleton
59 public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver {
60 private final Logger logger = LoggerFactory.getLogger(getClass());
61 private final RepositorySystem repoSystem;
62 private final List<RepositorySessionDecorator> decorators;
63
64 @Inject
65 public DefaultProjectDependenciesResolver(
66 RepositorySystem repoSystem, List<RepositorySessionDecorator> decorators) {
67 this.repoSystem = repoSystem;
68 this.decorators = decorators;
69 }
70
71 public DependencyResolutionResult resolve(DependencyResolutionRequest request)
72 throws DependencyResolutionException {
73 final RequestTrace trace = RequestTrace.newChild(null, request);
74
75 final DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
76
77 final MavenProject project = request.getMavenProject();
78 final DependencyFilter filter = request.getResolutionFilter();
79 RepositorySystemSession session = request.getRepositorySession();
80 ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
81
82 if (logger.isDebugEnabled()
83 && session.getConfigProperties().get(DependencyManagerUtils.CONFIG_PROP_VERBOSE) == null) {
84 DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession(session);
85 verbose.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE);
86 session = verbose;
87 }
88
89 for (RepositorySessionDecorator decorator : decorators) {
90 RepositorySystemSession decorated = decorator.decorate(project, session);
91 if (decorated != null) {
92 session = decorated;
93 }
94 }
95
96 CollectRequest collect = new CollectRequest();
97 collect.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
98 collect.setRequestContext("project");
99 collect.setRepositories(project.getRemoteProjectRepositories());
100
101 if (project.getDependencyArtifacts() == null) {
102 for (Dependency dependency : project.getDependencies()) {
103 if (StringUtils.isEmpty(dependency.getGroupId())
104 || StringUtils.isEmpty(dependency.getArtifactId())
105 || StringUtils.isEmpty(dependency.getVersion())) {
106
107 continue;
108 }
109 collect.addDependency(RepositoryUtils.toDependency(dependency, stereotypes));
110 }
111 } else {
112 Map<String, Dependency> dependencies = new HashMap<>();
113 for (Dependency dependency : project.getDependencies()) {
114 String classifier = dependency.getClassifier();
115 if (classifier == null) {
116 ArtifactType type = stereotypes.get(dependency.getType());
117 if (type != null) {
118 classifier = type.getClassifier();
119 }
120 }
121 String key = ArtifactIdUtils.toVersionlessId(
122 dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(), classifier);
123 dependencies.put(key, dependency);
124 }
125 for (Artifact artifact : project.getDependencyArtifacts()) {
126 String key = artifact.getDependencyConflictId();
127 Dependency dependency = dependencies.get(key);
128 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
129 org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency(artifact, exclusions);
130 if (!JavaScopes.SYSTEM.equals(dep.getScope())
131 && dep.getArtifact().getFile() != null) {
132
133 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
134 art = art.setFile(null).setVersion(art.getBaseVersion());
135 dep = dep.setArtifact(art);
136 }
137 collect.addDependency(dep);
138 }
139 }
140
141 DependencyManagement depMgmt = project.getDependencyManagement();
142 if (depMgmt != null) {
143 for (Dependency dependency : depMgmt.getDependencies()) {
144 collect.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes));
145 }
146 }
147
148 DependencyRequest depRequest = new DependencyRequest(collect, filter);
149 depRequest.setTrace(trace);
150
151 DependencyNode node;
152 try {
153 collect.setTrace(RequestTrace.newChild(trace, depRequest));
154 node = repoSystem.collectDependencies(session, collect).getRoot();
155 result.setDependencyGraph(node);
156 } catch (DependencyCollectionException e) {
157 result.setDependencyGraph(e.getResult().getRoot());
158 result.setCollectionErrors(e.getResult().getExceptions());
159
160 throw new DependencyResolutionException(
161 result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
162 }
163
164 depRequest.setRoot(node);
165
166 if (logger.isWarnEnabled()) {
167 for (DependencyNode child : node.getChildren()) {
168 if (!child.getRelocations().isEmpty()) {
169 org.eclipse.aether.artifact.Artifact relocated =
170 child.getDependency().getArtifact();
171 String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact
172 ? ((org.apache.maven.repository.internal.RelocatedArtifact) relocated).getMessage()
173 : null;
174 logger.warn("The artifact " + child.getRelocations().get(0) + " has been relocated to " + relocated
175 + (message != null ? ": " + message : ""));
176 }
177 }
178 }
179
180 if (logger.isDebugEnabled()) {
181 node.accept(new GraphLogger(project));
182 }
183
184 try {
185 process(result, repoSystem.resolveDependencies(session, depRequest).getArtifactResults());
186 } catch (org.eclipse.aether.resolution.DependencyResolutionException e) {
187 process(result, e.getResult().getArtifactResults());
188
189 throw new DependencyResolutionException(
190 result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
191 }
192
193 return result;
194 }
195
196 private void process(DefaultDependencyResolutionResult result, Collection<ArtifactResult> results) {
197 for (ArtifactResult ar : results) {
198 DependencyNode node = ar.getRequest().getDependencyNode();
199 if (ar.isResolved()) {
200 result.addResolvedDependency(node.getDependency());
201 } else {
202 result.setResolutionErrors(node.getDependency(), ar.getExceptions());
203 }
204 }
205 }
206
207
208 class GraphLogger implements DependencyVisitor {
209
210 private final MavenProject project;
211
212 private String indent = "";
213
214 GraphLogger(MavenProject project) {
215 this.project = project;
216 }
217
218 public boolean visitEnter(DependencyNode node) {
219 StringBuilder buffer = new StringBuilder(128);
220 buffer.append(indent);
221 org.eclipse.aether.graph.Dependency dep = node.getDependency();
222 if (dep != null) {
223 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
224
225 buffer.append(art);
226 if (StringUtils.isNotEmpty(dep.getScope())) {
227 buffer.append(':').append(dep.getScope());
228 }
229
230 if (dep.isOptional()) {
231 buffer.append(" (optional)");
232 }
233
234
235
236
237 if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
238 final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
239 buffer.append(" (scope managed from ");
240 buffer.append(Objects.toString(premanagedScope, "default"));
241 buffer.append(')');
242 }
243
244 if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
245 final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
246 buffer.append(" (version managed from ");
247 buffer.append(Objects.toString(premanagedVersion, "default"));
248 buffer.append(')');
249 }
250
251 if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
252 final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
253 buffer.append(" (optionality managed from ");
254 buffer.append(Objects.toString(premanagedOptional, "default"));
255 buffer.append(')');
256 }
257
258 if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
259 final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
260 DependencyManagerUtils.getPremanagedExclusions(node);
261
262 buffer.append(" (exclusions managed from ");
263 buffer.append(Objects.toString(premanagedExclusions, "default"));
264 buffer.append(')');
265 }
266
267 if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
268 final Map<String, String> premanagedProperties =
269 DependencyManagerUtils.getPremanagedProperties(node);
270
271 buffer.append(" (properties managed from ");
272 buffer.append(Objects.toString(premanagedProperties, "default"));
273 buffer.append(')');
274 }
275 } else {
276 buffer.append(project.getGroupId());
277 buffer.append(':').append(project.getArtifactId());
278 buffer.append(':').append(project.getPackaging());
279 buffer.append(':').append(project.getVersion());
280 }
281
282 logger.debug(buffer.toString());
283 indent += " ";
284 return true;
285 }
286
287 public boolean visitLeave(DependencyNode node) {
288 indent = indent.substring(0, indent.length() - 3);
289 return true;
290 }
291 }
292 }