1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.impl;
20
21 import java.io.IOException;
22 import java.nio.file.Path;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Set;
29 import java.util.function.Predicate;
30 import java.util.stream.Collectors;
31
32 import org.apache.maven.api.Artifact;
33 import org.apache.maven.api.ArtifactCoordinates;
34 import org.apache.maven.api.DependencyCoordinates;
35 import org.apache.maven.api.DependencyScope;
36 import org.apache.maven.api.Node;
37 import org.apache.maven.api.PathScope;
38 import org.apache.maven.api.PathType;
39 import org.apache.maven.api.Project;
40 import org.apache.maven.api.RemoteRepository;
41 import org.apache.maven.api.Session;
42 import org.apache.maven.api.Version;
43 import org.apache.maven.api.annotations.Nonnull;
44 import org.apache.maven.api.annotations.Nullable;
45 import org.apache.maven.api.di.Named;
46 import org.apache.maven.api.di.Singleton;
47 import org.apache.maven.api.services.ArtifactResolver;
48 import org.apache.maven.api.services.ArtifactResolverException;
49 import org.apache.maven.api.services.ArtifactResolverResult;
50 import org.apache.maven.api.services.DependencyResolver;
51 import org.apache.maven.api.services.DependencyResolverException;
52 import org.apache.maven.api.services.DependencyResolverRequest;
53 import org.apache.maven.api.services.DependencyResolverResult;
54 import org.apache.maven.api.services.ProjectManager;
55 import org.eclipse.aether.DefaultRepositorySystemSession;
56 import org.eclipse.aether.RepositorySystemSession;
57 import org.eclipse.aether.collection.CollectRequest;
58 import org.eclipse.aether.collection.CollectResult;
59 import org.eclipse.aether.collection.DependencyCollectionException;
60 import org.eclipse.aether.graph.DependencyFilter;
61 import org.eclipse.aether.graph.DependencyNode;
62 import org.eclipse.aether.scope.ResolutionScope;
63 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
64 import org.eclipse.aether.util.graph.transformer.ConflictResolver;
65
66 import static java.util.Objects.requireNonNull;
67 import static org.apache.maven.impl.ImplUtils.cast;
68 import static org.apache.maven.impl.ImplUtils.map;
69
70 @Named
71 @Singleton
72 public class DefaultDependencyResolver implements DependencyResolver {
73
74
75
76
77
78
79
80
81 private final Map<Runtime.Version, PathModularizationCache> moduleCaches;
82
83
84
85
86 public DefaultDependencyResolver() {
87
88 moduleCaches = new HashMap<>();
89 }
90
91
92
93
94
95
96
97 private PathModularizationCache moduleCache(DependencyResolverRequest request) {
98 return moduleCaches.computeIfAbsent(getTargetVersion(request), PathModularizationCache::new);
99 }
100
101
102
103
104
105
106
107
108 static Runtime.Version getTargetVersion(DependencyResolverRequest request) {
109 Version target = request.getTargetVersion();
110 return (target != null) ? Runtime.Version.parse(target.toString()) : Runtime.version();
111 }
112
113 @Nonnull
114 @Override
115 public DependencyResolverResult collect(@Nonnull DependencyResolverRequest request)
116 throws DependencyResolverException, IllegalArgumentException {
117 requireNonNull(request, "request");
118 InternalSession session = InternalSession.from(request.getSession());
119 RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
120 try {
121 Artifact rootArtifact;
122 DependencyCoordinates root;
123 Collection<DependencyCoordinates> dependencies;
124 Collection<DependencyCoordinates> managedDependencies;
125 List<RemoteRepository> remoteRepositories;
126 if (request.getProject().isPresent()) {
127 Project project = request.getProject().get();
128 rootArtifact = project.getPomArtifact();
129 root = null;
130 dependencies = project.getDependencies();
131 managedDependencies = project.getManagedDependencies();
132 remoteRepositories = request.getRepositories() != null
133 ? request.getRepositories()
134 : session.getService(ProjectManager.class).getRemoteProjectRepositories(project);
135 } else {
136 rootArtifact = request.getRootArtifact().orElse(null);
137 root = request.getRoot().orElse(null);
138 dependencies = request.getDependencies();
139 managedDependencies = request.getManagedDependencies();
140 remoteRepositories =
141 request.getRepositories() != null ? request.getRepositories() : session.getRemoteRepositories();
142 }
143 ResolutionScope resolutionScope = null;
144 if (request.getPathScope() != null) {
145 resolutionScope = session.getSession()
146 .getScopeManager()
147 .getResolutionScope(request.getPathScope().id())
148 .orElseThrow();
149 }
150 CollectRequest collectRequest = new CollectRequest()
151 .setRootArtifact(rootArtifact != null ? session.toArtifact(rootArtifact) : null)
152 .setRoot(root != null ? session.toDependency(root, false) : null)
153 .setDependencies(session.toDependencies(dependencies, false))
154 .setManagedDependencies(session.toDependencies(managedDependencies, true))
155 .setRepositories(session.toResolvingRepositories(remoteRepositories))
156 .setRequestContext(trace.context())
157 .setTrace(trace.trace());
158 collectRequest.setResolutionScope(resolutionScope);
159
160 RepositorySystemSession systemSession = session.getSession();
161 if (request.getVerbose()) {
162 systemSession = new DefaultRepositorySystemSession(systemSession)
163 .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true)
164 .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
165 }
166
167 try {
168 final CollectResult result =
169 session.getRepositorySystem().collectDependencies(systemSession, collectRequest);
170 return new DefaultDependencyResolverResult(
171 null,
172 moduleCache(request),
173 result.getExceptions(),
174 session.getNode(result.getRoot(), request.getVerbose()),
175 0);
176 } catch (DependencyCollectionException e) {
177 throw new DependencyResolverException("Unable to collect dependencies", e);
178 }
179 } finally {
180 RequestTraceHelper.exit(trace);
181 }
182 }
183
184 @Nonnull
185 @Override
186 public List<Node> flatten(@Nonnull Session s, @Nonnull Node node, @Nullable PathScope scope)
187 throws DependencyResolverException {
188 InternalSession session = InternalSession.from(s);
189 DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode();
190 List<DependencyNode> dependencies = session.getRepositorySystem()
191 .flattenDependencyNodes(session.getSession(), root, getScopeDependencyFilter(scope));
192 dependencies.remove(root);
193 return map(dependencies, session::getNode);
194 }
195
196 private static DependencyFilter getScopeDependencyFilter(PathScope scope) {
197 if (scope == null) {
198 return null;
199 }
200 Set<String> scopes =
201 scope.dependencyScopes().stream().map(DependencyScope::id).collect(Collectors.toSet());
202 return (n, p) -> {
203 org.eclipse.aether.graph.Dependency d = n.getDependency();
204 return d == null || scopes.contains(d.getScope());
205 };
206 }
207
208
209
210
211
212
213
214 @Override
215 public DependencyResolverResult resolve(DependencyResolverRequest request)
216 throws DependencyResolverException, ArtifactResolverException {
217 InternalSession session =
218 InternalSession.from(requireNonNull(request, "request").getSession());
219 RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
220 DependencyResolverResult result;
221 try {
222 DependencyResolverResult collectorResult = collect(request);
223 List<RemoteRepository> repositories = request.getRepositories() != null
224 ? request.getRepositories()
225 : request.getProject().isPresent()
226 ? session.getService(ProjectManager.class)
227 .getRemoteProjectRepositories(
228 request.getProject().get())
229 : session.getRemoteRepositories();
230 if (request.getRequestType() == DependencyResolverRequest.RequestType.COLLECT) {
231 result = collectorResult;
232 } else {
233 List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getPathScope());
234 List<ArtifactCoordinates> coordinates = nodes.stream()
235 .map(Node::getDependency)
236 .filter(Objects::nonNull)
237 .map(Artifact::toCoordinates)
238 .collect(Collectors.toList());
239 Predicate<PathType> filter = request.getPathTypeFilter();
240 DefaultDependencyResolverResult resolverResult = new DefaultDependencyResolverResult(
241 null,
242 moduleCache(request),
243 collectorResult.getExceptions(),
244 collectorResult.getRoot(),
245 nodes.size());
246 if (request.getRequestType() == DependencyResolverRequest.RequestType.FLATTEN) {
247 for (Node node : nodes) {
248 resolverResult.addNode(node);
249 }
250 } else {
251 ArtifactResolverResult artifactResolverResult =
252 session.getService(ArtifactResolver.class).resolve(session, coordinates, repositories);
253 for (Node node : nodes) {
254 Path path = (node.getArtifact() != null)
255 ? artifactResolverResult
256 .getResult(node.getArtifact().toCoordinates())
257 .getPath()
258 : null;
259 try {
260 resolverResult.addDependency(node, node.getDependency(), filter, path);
261 } catch (IOException e) {
262 throw cannotReadModuleInfo(path, e);
263 }
264 }
265 }
266 result = resolverResult;
267 }
268 } finally {
269 RequestTraceHelper.exit(trace);
270 }
271 return result;
272 }
273
274 private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) {
275 return new DependencyResolverException("Cannot read module information of " + path, cause);
276 }
277 }