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 javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30
31 import org.apache.maven.RepositoryUtils;
32 import org.apache.maven.artifact.Artifact;
33 import org.apache.maven.model.Dependency;
34 import org.apache.maven.model.DependencyManagement;
35 import org.apache.maven.model.Exclusion;
36 import org.codehaus.plexus.util.StringUtils;
37 import org.eclipse.aether.DefaultRepositorySystemSession;
38 import org.eclipse.aether.RepositorySystem;
39 import org.eclipse.aether.RepositorySystemSession;
40 import org.eclipse.aether.RequestTrace;
41 import org.eclipse.aether.artifact.ArtifactType;
42 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
43 import org.eclipse.aether.collection.CollectRequest;
44 import org.eclipse.aether.collection.DependencyCollectionException;
45 import org.eclipse.aether.graph.DependencyFilter;
46 import org.eclipse.aether.graph.DependencyNode;
47 import org.eclipse.aether.graph.DependencyVisitor;
48 import org.eclipse.aether.resolution.ArtifactResult;
49 import org.eclipse.aether.resolution.DependencyRequest;
50 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
51 import org.eclipse.aether.util.artifact.JavaScopes;
52 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59 @Singleton
60 @Named
61 public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver {
62
63 private final Logger logger = LoggerFactory.getLogger(getClass());
64
65 @Inject
66 private RepositorySystem repoSystem;
67
68 @Inject
69 private List<RepositorySessionDecorator> decorators;
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,
162 "Could not collect dependencies for project " + project.getId(),
163 logger.isDebugEnabled() ? e : null);
164 }
165
166 depRequest.setRoot(node);
167
168 if (logger.isWarnEnabled()) {
169 for (DependencyNode child : node.getChildren()) {
170 if (!child.getRelocations().isEmpty()) {
171 org.eclipse.aether.artifact.Artifact relocated =
172 child.getDependency().getArtifact();
173 String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact
174 ? ((org.apache.maven.repository.internal.RelocatedArtifact) relocated).getMessage()
175 : null;
176 logger.warn("The artifact " + child.getRelocations().get(0) + " has been relocated to " + relocated
177 + (message != null ? ": " + message : ""));
178 }
179 }
180 }
181
182 if (logger.isDebugEnabled()) {
183 node.accept(new GraphLogger(project));
184 }
185
186 try {
187 process(result, repoSystem.resolveDependencies(session, depRequest).getArtifactResults());
188 } catch (org.eclipse.aether.resolution.DependencyResolutionException e) {
189 process(result, e.getResult().getArtifactResults());
190
191 throw new DependencyResolutionException(
192 result,
193 "Could not resolve dependencies for project " + project.getId(),
194 logger.isDebugEnabled() ? e : null);
195 }
196
197 return result;
198 }
199
200 private void process(DefaultDependencyResolutionResult result, Collection<ArtifactResult> results) {
201 for (ArtifactResult ar : results) {
202 DependencyNode node = ar.getRequest().getDependencyNode();
203 if (ar.isResolved()) {
204 result.addResolvedDependency(node.getDependency());
205 } else {
206 result.setResolutionErrors(node.getDependency(), ar.getExceptions());
207 }
208 }
209 }
210
211
212 class GraphLogger implements DependencyVisitor {
213
214 private final MavenProject project;
215
216 private String indent = "";
217
218 GraphLogger(MavenProject project) {
219 this.project = project;
220 }
221
222 public boolean visitEnter(DependencyNode node) {
223 StringBuilder buffer = new StringBuilder(128);
224 buffer.append(indent);
225 org.eclipse.aether.graph.Dependency dep = node.getDependency();
226 if (dep != null) {
227 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
228
229 buffer.append(art);
230 if (StringUtils.isNotEmpty(dep.getScope())) {
231 buffer.append(':').append(dep.getScope());
232 }
233
234 if (dep.isOptional()) {
235 buffer.append(" (optional)");
236 }
237
238
239
240
241 if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
242 final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
243 buffer.append(" (scope managed from ");
244 buffer.append(Objects.toString(premanagedScope, "default"));
245 buffer.append(')');
246 }
247
248 if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
249 final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
250 buffer.append(" (version managed from ");
251 buffer.append(Objects.toString(premanagedVersion, "default"));
252 buffer.append(')');
253 }
254
255 if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
256 final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
257 buffer.append(" (optionality managed from ");
258 buffer.append(Objects.toString(premanagedOptional, "default"));
259 buffer.append(')');
260 }
261
262 if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
263 final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
264 DependencyManagerUtils.getPremanagedExclusions(node);
265
266 buffer.append(" (exclusions managed from ");
267 buffer.append(Objects.toString(premanagedExclusions, "default"));
268 buffer.append(')');
269 }
270
271 if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
272 final Map<String, String> premanagedProperties =
273 DependencyManagerUtils.getPremanagedProperties(node);
274
275 buffer.append(" (properties managed from ");
276 buffer.append(Objects.toString(premanagedProperties, "default"));
277 buffer.append(')');
278 }
279 } else {
280 buffer.append(project.getGroupId());
281 buffer.append(':').append(project.getArtifactId());
282 buffer.append(':').append(project.getPackaging());
283 buffer.append(':').append(project.getVersion());
284 }
285
286 logger.debug(buffer.toString());
287 indent += " ";
288 return true;
289 }
290
291 public boolean visitLeave(DependencyNode node) {
292 indent = indent.substring(0, indent.length() - 3);
293 return true;
294 }
295 }
296 }