1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.surefire;
20
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import javax.inject.Inject;
24 import javax.inject.Named;
25 import javax.inject.Singleton;
26
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.LinkedHashMap;
31 import java.util.LinkedHashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.stream.Collectors;
36
37 import org.apache.maven.RepositoryUtils;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
40 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
41 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
42 import org.apache.maven.artifact.versioning.VersionRange;
43 import org.apache.maven.model.Dependency;
44 import org.apache.maven.model.Plugin;
45 import org.apache.maven.plugin.MojoExecutionException;
46 import org.eclipse.aether.RepositorySystem;
47 import org.eclipse.aether.RepositorySystemSession;
48 import org.eclipse.aether.collection.CollectRequest;
49 import org.eclipse.aether.graph.DependencyFilter;
50 import org.eclipse.aether.repository.RemoteRepository;
51 import org.eclipse.aether.resolution.ArtifactResult;
52 import org.eclipse.aether.resolution.DependencyRequest;
53 import org.eclipse.aether.resolution.DependencyResolutionException;
54 import org.eclipse.aether.resolution.DependencyResult;
55 import org.eclipse.aether.util.artifact.JavaScopes;
56 import org.eclipse.aether.util.filter.DependencyFilterUtils;
57
58 import static org.apache.maven.artifact.ArtifactUtils.artifactMapByVersionlessId;
59 import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
60
61
62
63
64
65
66
67
68
69 @Named
70 @Singleton
71 public class SurefireDependencyResolver {
72
73 static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
74
75 private static final String[] PROVIDER_CLASSPATH_ORDER = {
76 "surefire-junit-platform", "surefire-api", "surefire-logger-api", "surefire-shared-utils", "common-java5"
77 };
78
79 private final RepositorySystem repositorySystem;
80
81 @Inject
82 SurefireDependencyResolver(RepositorySystem repositorySystem) {
83 this.repositorySystem = repositorySystem;
84 }
85
86 public static boolean isWithinVersionSpec(@Nullable Artifact artifact, @Nonnull String versionSpec) {
87 if (artifact == null) {
88 return false;
89 }
90 try {
91 VersionRange range = createFromVersionSpec(versionSpec);
92 try {
93 return range.containsVersion(artifact.getSelectedVersion());
94 } catch (NullPointerException e) {
95 return range.containsVersion(new DefaultArtifactVersion(artifact.getBaseVersion()));
96 }
97 } catch (InvalidVersionSpecificationException | OverConstrainedVersionException e) {
98 throw new RuntimeException("Bug in plugin. Please report with stacktrace");
99 }
100 }
101
102 Map<String, Artifact> resolvePluginDependencies(
103 RepositorySystemSession session,
104 List<RemoteRepository> repositories,
105 Plugin plugin,
106 Map<String, Artifact> pluginResolvedDependencies)
107 throws MojoExecutionException {
108 Map<String, Artifact> resolved = new LinkedHashMap<>();
109 Collection<Dependency> pluginDependencies = plugin.getDependencies();
110
111 for (Dependency dependency : pluginDependencies) {
112 Set<Artifact> artifacts = resolveDependencies(
113 session, repositories, RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry()));
114 for (Artifact artifact : artifacts) {
115 String key = artifact.getGroupId() + ":" + artifact.getArtifactId();
116 Artifact resolvedPluginDependency = pluginResolvedDependencies.get(key);
117 if (resolvedPluginDependency != null) {
118 resolved.put(key, artifact);
119 }
120 }
121 }
122 return resolved;
123 }
124
125 public Set<Artifact> resolveArtifacts(
126 RepositorySystemSession session, List<RemoteRepository> repositories, Artifact artifact)
127 throws MojoExecutionException {
128 return resolveDependencies(session, repositories, RepositoryUtils.toDependency(artifact, null));
129 }
130
131 public Set<Artifact> resolveDependencies(
132 RepositorySystemSession session, List<RemoteRepository> repositories, Dependency dependency)
133 throws MojoExecutionException {
134 return resolveDependencies(
135 session, repositories, RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry()));
136 }
137
138 private Set<Artifact> resolveDependencies(
139 RepositorySystemSession session,
140 List<RemoteRepository> repositories,
141 org.eclipse.aether.graph.Dependency dependency)
142 throws MojoExecutionException {
143
144 List<ArtifactResult> results = resolveDependencies(
145 session, repositories, dependency, DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME));
146 return results.stream()
147 .map(ArtifactResult::getArtifact)
148 .map(RepositoryUtils::toArtifact)
149 .collect(Collectors.toCollection(LinkedHashSet::new));
150 }
151
152 private List<ArtifactResult> resolveDependencies(
153 RepositorySystemSession session,
154 List<RemoteRepository> repositories,
155 org.eclipse.aether.graph.Dependency dependency,
156 DependencyFilter dependencyFilter)
157 throws MojoExecutionException {
158
159 try {
160
161 CollectRequest collectRequest =
162 new CollectRequest(Collections.singletonList(dependency), null, repositories);
163
164 DependencyRequest request = new DependencyRequest();
165 request.setCollectRequest(collectRequest);
166 request.setFilter(dependencyFilter);
167
168 DependencyResult dependencyResult = repositorySystem.resolveDependencies(session, request);
169 return dependencyResult.getArtifactResults();
170 } catch (DependencyResolutionException e) {
171 throw new MojoExecutionException(e.getMessage(), e);
172 }
173 }
174
175 @Nonnull
176 Set<Artifact> getProviderClasspath(
177 RepositorySystemSession session,
178 List<RemoteRepository> repositories,
179 String providerArtifactId,
180 String providerVersion)
181 throws MojoExecutionException {
182
183 Dependency provider = toProviderDependency(providerArtifactId, providerVersion);
184
185 org.eclipse.aether.graph.Dependency dependency =
186 RepositoryUtils.toDependency(provider, session.getArtifactTypeRegistry());
187
188 Set<Artifact> result = resolveDependencies(session, repositories, dependency);
189
190 return orderProviderArtifacts(result);
191 }
192
193 @Nonnull
194 Map<String, Artifact> getProviderClasspathAsMap(
195 RepositorySystemSession session,
196 List<RemoteRepository> repositories,
197 String providerArtifactId,
198 String providerVersion)
199 throws MojoExecutionException {
200 return artifactMapByVersionlessId(
201 getProviderClasspath(session, repositories, providerArtifactId, providerVersion));
202 }
203
204
205
206
207 private static Set<Artifact> orderProviderArtifacts(Set<Artifact> providerArtifacts) {
208 Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<>();
209 for (String order : PROVIDER_CLASSPATH_ORDER) {
210 Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
211 while (providerArtifactsIt.hasNext()) {
212 Artifact providerArtifact = providerArtifactsIt.next();
213 if (providerArtifact.getArtifactId().equals(order)) {
214 orderedProviderArtifacts.add(providerArtifact);
215 providerArtifactsIt.remove();
216 }
217 }
218 }
219 orderedProviderArtifacts.addAll(providerArtifacts);
220 return orderedProviderArtifacts;
221 }
222
223 private static Dependency toProviderDependency(String providerArtifactId, String providerVersion) {
224 Dependency dependency = new Dependency();
225 dependency.setGroupId(PROVIDER_GROUP_ID);
226 dependency.setArtifactId(providerArtifactId);
227 dependency.setVersion(providerVersion);
228 dependency.setType("jar");
229 return dependency;
230 }
231 }