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