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