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 @Named
68 @Singleton
69 class SurefireDependencyResolver {
70
71 static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
72
73 private static final String[] PROVIDER_CLASSPATH_ORDER = {
74 "surefire-junit3",
75 "surefire-junit4",
76 "surefire-junit47",
77 "surefire-testng",
78 "surefire-junit-platform",
79 "surefire-api",
80 "surefire-logger-api",
81 "surefire-shared-utils",
82 "common-java5",
83 "common-junit3",
84 "common-junit4",
85 "common-junit48",
86 "common-testng-utils"
87 };
88
89 private final RepositorySystem repositorySystem;
90
91 @Inject
92 SurefireDependencyResolver(RepositorySystem repositorySystem) {
93 this.repositorySystem = repositorySystem;
94 }
95
96 static boolean isWithinVersionSpec(@Nullable Artifact artifact, @Nonnull String versionSpec) {
97 if (artifact == null) {
98 return false;
99 }
100 try {
101 VersionRange range = createFromVersionSpec(versionSpec);
102 try {
103 return range.containsVersion(artifact.getSelectedVersion());
104 } catch (NullPointerException e) {
105 return range.containsVersion(new DefaultArtifactVersion(artifact.getBaseVersion()));
106 }
107 } catch (InvalidVersionSpecificationException | OverConstrainedVersionException e) {
108 throw new RuntimeException("Bug in plugin. Please report with stacktrace");
109 }
110 }
111
112 Map<String, Artifact> resolvePluginDependencies(
113 RepositorySystemSession session,
114 List<RemoteRepository> repositories,
115 Plugin plugin,
116 Map<String, Artifact> pluginResolvedDependencies)
117 throws MojoExecutionException {
118 Map<String, Artifact> resolved = new LinkedHashMap<>();
119 Collection<Dependency> pluginDependencies = plugin.getDependencies();
120
121 for (Dependency dependency : pluginDependencies) {
122 Set<Artifact> artifacts = resolveDependencies(
123 session, repositories, RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry()));
124 for (Artifact artifact : artifacts) {
125 String key = artifact.getGroupId() + ":" + artifact.getArtifactId();
126 Artifact resolvedPluginDependency = pluginResolvedDependencies.get(key);
127 if (resolvedPluginDependency != null) {
128 resolved.put(key, artifact);
129 }
130 }
131 }
132 return resolved;
133 }
134
135 public Set<Artifact> resolveArtifacts(
136 RepositorySystemSession session, List<RemoteRepository> repositories, Artifact artifact)
137 throws MojoExecutionException {
138 return resolveDependencies(session, repositories, RepositoryUtils.toDependency(artifact, null));
139 }
140
141 public Set<Artifact> resolveDependencies(
142 RepositorySystemSession session, List<RemoteRepository> repositories, Dependency dependency)
143 throws MojoExecutionException {
144 return resolveDependencies(
145 session, repositories, RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry()));
146 }
147
148 private Set<Artifact> resolveDependencies(
149 RepositorySystemSession session,
150 List<RemoteRepository> repositories,
151 org.eclipse.aether.graph.Dependency dependency)
152 throws MojoExecutionException {
153
154 try {
155 List<ArtifactResult> results = resolveDependencies(
156 session, repositories, dependency, DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME));
157 return results.stream()
158 .map(ArtifactResult::getArtifact)
159 .map(RepositoryUtils::toArtifact)
160 .collect(Collectors.toCollection(LinkedHashSet::new));
161
162 } catch (DependencyResolutionException e) {
163 throw new MojoExecutionException(e.getMessage(), e);
164 }
165 }
166
167 private List<ArtifactResult> resolveDependencies(
168 RepositorySystemSession session,
169 List<RemoteRepository> repositories,
170 org.eclipse.aether.graph.Dependency dependency,
171 DependencyFilter dependencyFilter)
172 throws DependencyResolutionException {
173
174
175 CollectRequest collectRequest = new CollectRequest(Collections.singletonList(dependency), null, repositories);
176
177 DependencyRequest request = new DependencyRequest();
178 request.setCollectRequest(collectRequest);
179 request.setFilter(dependencyFilter);
180
181 DependencyResult dependencyResult = repositorySystem.resolveDependencies(session, request);
182 return dependencyResult.getArtifactResults();
183 }
184
185 @Nonnull
186 Set<Artifact> getProviderClasspath(
187 RepositorySystemSession session,
188 List<RemoteRepository> repositories,
189 String providerArtifactId,
190 String providerVersion)
191 throws MojoExecutionException {
192 Dependency provider = toProviderDependency(providerArtifactId, providerVersion);
193
194 org.eclipse.aether.graph.Dependency dependency =
195 RepositoryUtils.toDependency(provider, session.getArtifactTypeRegistry());
196
197 Set<Artifact> result = resolveDependencies(session, repositories, dependency);
198
199 return orderProviderArtifacts(result);
200 }
201
202 @Nonnull
203 Map<String, Artifact> getProviderClasspathAsMap(
204 RepositorySystemSession session,
205 List<RemoteRepository> repositories,
206 String providerArtifactId,
207 String providerVersion)
208 throws MojoExecutionException {
209 return artifactMapByVersionlessId(
210 getProviderClasspath(session, repositories, providerArtifactId, providerVersion));
211 }
212
213
214
215
216 private static Set<Artifact> orderProviderArtifacts(Set<Artifact> providerArtifacts) {
217 Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<>();
218 for (String order : PROVIDER_CLASSPATH_ORDER) {
219 Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
220 while (providerArtifactsIt.hasNext()) {
221 Artifact providerArtifact = providerArtifactsIt.next();
222 if (providerArtifact.getArtifactId().equals(order)) {
223 orderedProviderArtifacts.add(providerArtifact);
224 providerArtifactsIt.remove();
225 }
226 }
227 }
228 orderedProviderArtifacts.addAll(providerArtifacts);
229 return orderedProviderArtifacts;
230 }
231
232 private static Dependency toProviderDependency(String providerArtifactId, String providerVersion) {
233 Dependency dependency = new Dependency();
234 dependency.setGroupId(PROVIDER_GROUP_ID);
235 dependency.setArtifactId(providerArtifactId);
236 dependency.setVersion(providerVersion);
237 dependency.setType("jar");
238 return dependency;
239 }
240 }