1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.stream.Collectors;
34 import java.util.stream.Stream;
35
36 import org.apache.maven.api.Artifact;
37 import org.apache.maven.api.ArtifactCoordinate;
38 import org.apache.maven.api.Dependency;
39 import org.apache.maven.api.Node;
40 import org.apache.maven.api.Project;
41 import org.apache.maven.api.ResolutionScope;
42 import org.apache.maven.api.Scope;
43 import org.apache.maven.api.Session;
44 import org.apache.maven.api.services.*;
45 import org.apache.maven.lifecycle.LifecycleExecutionException;
46 import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
47 import org.apache.maven.project.DependencyResolutionResult;
48 import org.apache.maven.project.MavenProject;
49 import org.eclipse.aether.graph.DependencyFilter;
50 import org.eclipse.aether.graph.DependencyNode;
51
52 import static org.apache.maven.internal.impl.Utils.cast;
53 import static org.apache.maven.internal.impl.Utils.map;
54 import static org.apache.maven.internal.impl.Utils.nonNull;
55
56 @Named
57 @Singleton
58 public class DefaultDependencyResolver implements DependencyResolver {
59
60 @Override
61 public List<Node> flatten(Session s, Node node, ResolutionScope scope) throws DependencyResolverException {
62 InternalSession session = InternalSession.from(s);
63 DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode();
64 List<DependencyNode> dependencies = session.getRepositorySystem()
65 .flattenDependencyNodes(session.getSession(), root, getScopeDependencyFilter(scope));
66 dependencies.remove(root);
67 return map(dependencies, session::getNode);
68 }
69
70 private static DependencyFilter getScopeDependencyFilter(ResolutionScope scope) {
71 Set<String> scopes = scope.scopes().stream().map(Scope::id).collect(Collectors.toSet());
72 return (n, p) -> {
73 org.eclipse.aether.graph.Dependency d = n.getDependency();
74 return d == null || scopes.contains(d.getScope());
75 };
76 }
77
78 @Override
79 public DependencyResolverResult resolve(DependencyResolverRequest request)
80 throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException {
81 nonNull(request, "request can not be null");
82 InternalSession session = InternalSession.from(request.getSession());
83
84 if (request.getProject().isPresent()) {
85 DependencyResolutionResult result = resolveDependencies(
86 request.getSession(), request.getProject().get(), request.getResolutionScope());
87
88 Map<org.eclipse.aether.graph.Dependency, org.eclipse.aether.graph.DependencyNode> nodes = stream(
89 result.getDependencyGraph())
90 .filter(n -> n.getDependency() != null)
91 .collect(Collectors.toMap(DependencyNode::getDependency, n -> n));
92
93 Node root = session.getNode(result.getDependencyGraph());
94 List<Node> dependencies = new ArrayList<>();
95 Map<Dependency, Path> artifacts = new LinkedHashMap<>();
96 List<Path> paths = new ArrayList<>();
97 for (org.eclipse.aether.graph.Dependency dep : result.getResolvedDependencies()) {
98 dependencies.add(session.getNode(nodes.get(dep)));
99 Path path = dep.getArtifact().getFile().toPath();
100 artifacts.put(session.getDependency(dep), path);
101 paths.add(path);
102 }
103 return new DefaultDependencyResolverResult(
104 result.getCollectionErrors(), root, dependencies, paths, artifacts);
105 }
106
107 DependencyCollectorResult collectorResult =
108 session.getService(DependencyCollector.class).collect(request);
109 List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope());
110 List<Dependency> deps =
111 nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList());
112 List<ArtifactCoordinate> coordinates =
113 deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList());
114 Map<Artifact, Path> artifacts = session.resolveArtifacts(coordinates);
115 Map<Dependency, Path> dependencies = new LinkedHashMap<>();
116 List<Path> paths = new ArrayList<>();
117 for (Dependency d : deps) {
118 Path path = artifacts.get(d);
119 if (dependencies.put(d, path) != null) {
120 throw new IllegalStateException("Duplicate key");
121 }
122 paths.add(path);
123 }
124
125 return new DefaultDependencyResolverResult(
126 collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies);
127 }
128
129 private Stream<DependencyNode> stream(DependencyNode node) {
130 return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream));
131 }
132
133 private DependencyResolutionResult resolveDependencies(Session session, Project project, ResolutionScope scope) {
134 Collection<String> toResolve = toScopes(scope);
135 try {
136 LifecycleDependencyResolver lifecycleDependencyResolver =
137 session.getService(Lookup.class).lookup(LifecycleDependencyResolver.class);
138 return lifecycleDependencyResolver.getProjectDependencyResolutionResult(
139 getMavenProject(project),
140 toResolve,
141 toResolve,
142 InternalSession.from(session).getMavenSession(),
143 false,
144 Collections.emptySet());
145 } catch (LifecycleExecutionException e) {
146 throw new DependencyResolverException("Unable to resolve project dependencies", e);
147 }
148 }
149
150 private MavenProject getMavenProject(Project project) {
151 return ((DefaultProject) project).getProject();
152 }
153
154 private Collection<String> toScopes(ResolutionScope scope) {
155 return map(scope.scopes(), Scope::id);
156 }
157
158 static class DefaultDependencyResolverResult implements DependencyResolverResult {
159 private final List<Exception> exceptions;
160 private final Node root;
161 private final List<Node> nodes;
162 private final List<Path> paths;
163 private final Map<Dependency, Path> dependencies;
164
165 DefaultDependencyResolverResult(
166 List<Exception> exceptions,
167 Node root,
168 List<Node> nodes,
169 List<Path> paths,
170 Map<Dependency, Path> dependencies) {
171 this.exceptions = exceptions;
172 this.root = root;
173 this.nodes = nodes;
174 this.paths = paths;
175 this.dependencies = dependencies;
176 }
177
178 @Override
179 public List<Exception> getExceptions() {
180 return exceptions;
181 }
182
183 @Override
184 public Node getRoot() {
185 return root;
186 }
187
188 @Override
189 public List<Node> getNodes() {
190 return nodes;
191 }
192
193 @Override
194 public List<Path> getPaths() {
195 return paths;
196 }
197
198 @Override
199 public Map<Dependency, Path> getDependencies() {
200 return dependencies;
201 }
202 }
203 }