1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.internal;
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.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32
33 import org.apache.maven.RepositoryUtils;
34 import org.apache.maven.model.Dependency;
35 import org.apache.maven.model.Plugin;
36 import org.apache.maven.plugin.PluginResolutionException;
37 import org.codehaus.plexus.util.StringUtils;
38 import org.eclipse.aether.DefaultRepositorySystemSession;
39 import org.eclipse.aether.RepositorySystem;
40 import org.eclipse.aether.RepositorySystemSession;
41 import org.eclipse.aether.RequestTrace;
42 import org.eclipse.aether.artifact.Artifact;
43 import org.eclipse.aether.artifact.DefaultArtifact;
44 import org.eclipse.aether.collection.CollectRequest;
45 import org.eclipse.aether.collection.DependencyCollectionChecker;
46 import org.eclipse.aether.collection.DependencyCollectionException;
47 import org.eclipse.aether.collection.DependencySelector;
48 import org.eclipse.aether.collection.VersionFilterBuilder;
49 import org.eclipse.aether.graph.DependencyFilter;
50 import org.eclipse.aether.graph.DependencyNode;
51 import org.eclipse.aether.graph.DependencyVisitor;
52 import org.eclipse.aether.repository.RemoteRepository;
53 import org.eclipse.aether.resolution.ArtifactDescriptorException;
54 import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
55 import org.eclipse.aether.resolution.ArtifactDescriptorResult;
56 import org.eclipse.aether.resolution.ArtifactRequest;
57 import org.eclipse.aether.resolution.ArtifactResolutionException;
58 import org.eclipse.aether.resolution.DependencyRequest;
59 import org.eclipse.aether.resolution.DependencyResolutionException;
60 import org.eclipse.aether.resolution.DependencyResult;
61 import org.eclipse.aether.util.artifact.JavaScopes;
62 import org.eclipse.aether.util.filter.AndDependencyFilter;
63 import org.eclipse.aether.util.filter.ScopeDependencyFilter;
64 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
65 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
66 import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73
74
75
76
77
78 @Singleton
79 @Named
80 public class DefaultPluginDependenciesResolver implements PluginDependenciesResolver {
81
82 private static final String REPOSITORY_CONTEXT = "plugin";
83
84 private final Logger logger = LoggerFactory.getLogger(getClass());
85
86 @Inject
87 private RepositorySystem repoSystem;
88
89 @Inject
90 private List<MavenPluginDependenciesValidator> dependenciesValidators;
91
92 private Artifact toArtifact(Plugin plugin, RepositorySystemSession session) {
93 return new DefaultArtifact(
94 plugin.getGroupId(),
95 plugin.getArtifactId(),
96 null,
97 "jar",
98 plugin.getVersion(),
99 session.getArtifactTypeRegistry().get("maven-plugin"));
100 }
101
102 @Override
103 public Artifact resolve(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
104 throws PluginResolutionException {
105 RequestTrace trace = RequestTrace.newChild(null, plugin);
106
107 Artifact pluginArtifact = toArtifact(plugin, session);
108
109 try {
110 DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session);
111 pluginSession.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, false));
112
113 ArtifactDescriptorRequest request =
114 new ArtifactDescriptorRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT);
115 request.setTrace(trace);
116 ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor(pluginSession, request);
117
118 for (MavenPluginDependenciesValidator dependenciesValidator : dependenciesValidators) {
119 dependenciesValidator.validate(session, pluginArtifact, result);
120 }
121
122 pluginArtifact = result.getArtifact();
123
124 if (logger.isWarnEnabled()) {
125 if (!result.getRelocations().isEmpty()) {
126 String message = pluginArtifact instanceof org.apache.maven.repository.internal.RelocatedArtifact
127 ? ((org.apache.maven.repository.internal.RelocatedArtifact) pluginArtifact).getMessage()
128 : null;
129 logger.warn("The artifact " + result.getRelocations().get(0) + " has been relocated to "
130 + pluginArtifact + (message != null ? ": " + message : ""));
131 }
132 }
133
134 String requiredMavenVersion = (String) result.getProperties().get("prerequisites.maven");
135 if (requiredMavenVersion != null) {
136 Map<String, String> props = new LinkedHashMap<>(pluginArtifact.getProperties());
137 props.put("requiredMavenVersion", requiredMavenVersion);
138 pluginArtifact = pluginArtifact.setProperties(props);
139 }
140 } catch (ArtifactDescriptorException e) {
141 throw new PluginResolutionException(
142 plugin, e.getResult().getExceptions(), logger.isDebugEnabled() ? e : null);
143 }
144
145 try {
146 ArtifactRequest request = new ArtifactRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT);
147 request.setTrace(trace);
148 pluginArtifact = repoSystem.resolveArtifact(session, request).getArtifact();
149 } catch (ArtifactResolutionException e) {
150 throw new PluginResolutionException(
151 plugin, e.getResult().getExceptions(), logger.isDebugEnabled() ? e : null);
152 }
153
154 return pluginArtifact;
155 }
156
157
158
159
160
161 @Deprecated
162 public DependencyNode resolveCoreExtension(
163 Plugin plugin,
164 DependencyFilter dependencyFilter,
165 List<RemoteRepository> repositories,
166 RepositorySystemSession session)
167 throws PluginResolutionException {
168 return resolveInternal(plugin, null , dependencyFilter, repositories, session)
169 .getRoot();
170 }
171
172
173
174
175 @Override
176 public DependencyResult resolveCoreExtensionAndFlatten(
177 Plugin plugin,
178 DependencyFilter dependencyFilter,
179 List<RemoteRepository> repositories,
180 RepositorySystemSession session)
181 throws PluginResolutionException {
182 return resolveInternal(plugin, null , dependencyFilter, repositories, session);
183 }
184
185 @Override
186 public DependencyNode resolve(
187 Plugin plugin,
188 Artifact pluginArtifact,
189 DependencyFilter dependencyFilter,
190 List<RemoteRepository> repositories,
191 RepositorySystemSession session)
192 throws PluginResolutionException {
193 return resolveInternal(plugin, pluginArtifact, dependencyFilter, repositories, session)
194 .getRoot();
195 }
196
197 @Override
198 public DependencyResult resolvePluginAndFlatten(
199 Plugin plugin,
200 Artifact pluginArtifact,
201 DependencyFilter dependencyFilter,
202 List<RemoteRepository> repositories,
203 RepositorySystemSession session)
204 throws PluginResolutionException {
205 return resolveInternal(plugin, pluginArtifact, dependencyFilter, repositories, session);
206 }
207
208 private DependencyResult resolveInternal(
209 Plugin plugin,
210 Artifact pluginArtifact,
211 DependencyFilter dependencyFilter,
212 List<RemoteRepository> repositories,
213 RepositorySystemSession session)
214 throws PluginResolutionException {
215 RequestTrace trace = RequestTrace.newChild(null, plugin);
216
217 if (pluginArtifact == null) {
218 pluginArtifact = toArtifact(plugin, session);
219 }
220
221 DependencyFilter collectionFilter = new ScopeDependencyFilter("provided", "test");
222 DependencyFilter resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, dependencyFilter);
223
224 try {
225 DependencySelector selector =
226 AndDependencySelector.newInstance(session.getDependencySelector(), new WagonExcluder());
227
228 DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session);
229 pluginSession.setConfigProperty(VersionFilterBuilder.VERSION_FILTER_SUPPRESSED, Boolean.TRUE.toString());
230 pluginSession.setConfigProperty(
231 DependencyCollectionChecker.COLLECTOR_CHECKER_SUPPRESSED, Boolean.TRUE.toString());
232 pluginSession.setDependencySelector(selector);
233 pluginSession.setDependencyGraphTransformer(session.getDependencyGraphTransformer());
234
235 CollectRequest request = new CollectRequest();
236 request.setRequestContext(REPOSITORY_CONTEXT);
237 request.setRepositories(repositories);
238 request.setRoot(new org.eclipse.aether.graph.Dependency(pluginArtifact, null));
239 for (Dependency dependency : plugin.getDependencies()) {
240 org.eclipse.aether.graph.Dependency pluginDep =
241 RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry());
242 if (!JavaScopes.SYSTEM.equals(pluginDep.getScope())) {
243 pluginDep = pluginDep.setScope(JavaScopes.RUNTIME);
244 }
245 request.addDependency(pluginDep);
246 }
247
248 DependencyRequest depRequest = new DependencyRequest(request, resolutionFilter);
249 depRequest.setTrace(trace);
250
251 request.setTrace(RequestTrace.newChild(trace, depRequest));
252
253 DependencyNode node =
254 repoSystem.collectDependencies(pluginSession, request).getRoot();
255
256 if (logger.isDebugEnabled()) {
257 node.accept(new GraphLogger());
258 }
259
260 depRequest.setRoot(node);
261 return repoSystem.resolveDependencies(session, depRequest);
262
263 } catch (DependencyCollectionException e) {
264 throw new PluginResolutionException(
265 plugin, e.getResult().getExceptions(), logger.isDebugEnabled() ? e : null);
266 } catch (DependencyResolutionException e) {
267 List<Exception> exceptions = Stream.concat(
268 e.getResult().getCollectExceptions().stream(),
269 e.getResult().getArtifactResults().stream()
270 .filter(r -> !r.isResolved())
271 .flatMap(r -> r.getExceptions().stream()))
272 .collect(Collectors.toList());
273 throw new PluginResolutionException(plugin, exceptions, logger.isDebugEnabled() ? e : null);
274 }
275 }
276
277
278 class GraphLogger implements DependencyVisitor {
279
280 private String indent = "";
281
282 public boolean visitEnter(DependencyNode node) {
283 StringBuilder buffer = new StringBuilder(128);
284 buffer.append(indent);
285 org.eclipse.aether.graph.Dependency dep = node.getDependency();
286 if (dep != null) {
287 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
288
289 buffer.append(art);
290 if (StringUtils.isNotEmpty(dep.getScope())) {
291 buffer.append(':').append(dep.getScope());
292 }
293
294 if (dep.isOptional()) {
295 buffer.append(" (optional)");
296 }
297
298
299
300
301 if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
302 final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
303 buffer.append(" (scope managed from ");
304 buffer.append(Objects.toString(premanagedScope, "default"));
305 buffer.append(')');
306 }
307
308 if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
309 final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
310 buffer.append(" (version managed from ");
311 buffer.append(Objects.toString(premanagedVersion, "default"));
312 buffer.append(')');
313 }
314
315 if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
316 final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
317 buffer.append(" (optionality managed from ");
318 buffer.append(Objects.toString(premanagedOptional, "default"));
319 buffer.append(')');
320 }
321
322 if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
323 final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
324 DependencyManagerUtils.getPremanagedExclusions(node);
325
326 buffer.append(" (exclusions managed from ");
327 buffer.append(Objects.toString(premanagedExclusions, "default"));
328 buffer.append(')');
329 }
330
331 if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
332 final Map<String, String> premanagedProperties =
333 DependencyManagerUtils.getPremanagedProperties(node);
334
335 buffer.append(" (properties managed from ");
336 buffer.append(Objects.toString(premanagedProperties, "default"));
337 buffer.append(')');
338 }
339 }
340
341 logger.debug(buffer.toString());
342 indent += " ";
343 return true;
344 }
345
346 public boolean visitLeave(DependencyNode node) {
347 indent = indent.substring(0, indent.length() - 3);
348 return true;
349 }
350 }
351 }