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 = deps.stream().collect(Collectors.toMap(d -> d, artifacts::get));
116 List<Path> paths = new ArrayList<>(dependencies.values());
117
118 return new DefaultDependencyResolverResult(
119 collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies);
120 }
121
122 private Stream<DependencyNode> stream(DependencyNode node) {
123 return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream));
124 }
125
126 private DependencyResolutionResult resolveDependencies(Session session, Project project, ResolutionScope scope) {
127 Collection<String> toResolve = toScopes(scope);
128 try {
129 LifecycleDependencyResolver lifecycleDependencyResolver =
130 session.getService(Lookup.class).lookup(LifecycleDependencyResolver.class);
131 return lifecycleDependencyResolver.getProjectDependencyResolutionResult(
132 getMavenProject(project),
133 toResolve,
134 toResolve,
135 InternalSession.from(session).getMavenSession(),
136 false,
137 Collections.emptySet());
138 } catch (LifecycleExecutionException e) {
139 throw new DependencyResolverException("Unable to resolve project dependencies", e);
140 }
141 }
142
143 private MavenProject getMavenProject(Project project) {
144 return ((DefaultProject) project).getProject();
145 }
146
147 private Collection<String> toScopes(ResolutionScope scope) {
148 return map(scope.scopes(), Scope::id);
149 }
150
151 static class DefaultDependencyResolverResult implements DependencyResolverResult {
152 private final List<Exception> exceptions;
153 private final Node root;
154 private final List<Node> nodes;
155 private final List<Path> paths;
156 private final Map<Dependency, Path> dependencies;
157
158 DefaultDependencyResolverResult(
159 List<Exception> exceptions,
160 Node root,
161 List<Node> nodes,
162 List<Path> paths,
163 Map<Dependency, Path> dependencies) {
164 this.exceptions = exceptions;
165 this.root = root;
166 this.nodes = nodes;
167 this.paths = paths;
168 this.dependencies = dependencies;
169 }
170
171 @Override
172 public List<Exception> getExceptions() {
173 return exceptions;
174 }
175
176 @Override
177 public Node getRoot() {
178 return root;
179 }
180
181 @Override
182 public List<Node> getNodes() {
183 return nodes;
184 }
185
186 @Override
187 public List<Path> getPaths() {
188 return paths;
189 }
190
191 @Override
192 public Map<Dependency, Path> getDependencies() {
193 return dependencies;
194 }
195 }
196 }