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