1 package org.apache.maven.plugin.surefire;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.artifact.repository.ArtifactRepository;
32 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
33 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
34 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
35 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
36 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
37 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
38 import org.apache.maven.artifact.versioning.VersionRange;
39 import org.apache.maven.model.Dependency;
40 import org.apache.maven.model.Plugin;
41 import org.apache.maven.plugin.MojoExecutionException;
42 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
43 import org.apache.maven.project.ProjectBuildingRequest;
44 import org.apache.maven.repository.RepositorySystem;
45 import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
46 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
47 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
48
49 import javax.annotation.Nonnull;
50 import javax.annotation.Nullable;
51
52 import static java.util.Arrays.asList;
53 import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
54 import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE_PLUS_RUNTIME;
55 import static org.apache.maven.artifact.Artifact.SCOPE_RUNTIME;
56 import static org.apache.maven.artifact.ArtifactUtils.artifactMapByVersionlessId;
57 import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
58 import static org.apache.maven.shared.artifact.filter.resolve.ScopeFilter.including;
59
60
61
62
63
64
65
66 final class SurefireDependencyResolver
67 {
68 static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
69
70 private static final String[] PROVIDER_CLASSPATH_ORDER = {
71 "surefire-junit3",
72 "surefire-junit4",
73 "surefire-junit47",
74 "surefire-testng",
75 "surefire-junit-platform",
76 "surefire-api",
77 "surefire-logger-api",
78 "surefire-shared-utils",
79 "common-java5",
80 "common-junit3",
81 "common-junit4",
82 "common-junit48",
83 "common-testng-utils"
84 };
85
86 private final RepositorySystem repositorySystem;
87
88 private final ConsoleLogger log;
89
90 private final ArtifactRepository localRepository;
91
92 private final List<ArtifactRepository> pluginRemoteRepositories;
93
94 private final List<ArtifactRepository> projectRemoteRepositories;
95
96 private final String pluginName;
97
98 private final DependencyResolver dependencyResolver;
99
100 private final boolean offline;
101
102 SurefireDependencyResolver( RepositorySystem repositorySystem, ConsoleLogger log,
103 ArtifactRepository localRepository,
104 List<ArtifactRepository> pluginRemoteRepositories,
105 List<ArtifactRepository> projectRemoteRepositories, String pluginName,
106 DependencyResolver dependencyResolver, boolean offline )
107 {
108 this.repositorySystem = repositorySystem;
109 this.log = log;
110 this.localRepository = localRepository;
111 this.pluginRemoteRepositories = pluginRemoteRepositories;
112 this.projectRemoteRepositories = projectRemoteRepositories;
113 this.pluginName = pluginName;
114 this.dependencyResolver = dependencyResolver;
115 this.offline = offline;
116 }
117
118 static boolean isWithinVersionSpec( @Nullable Artifact artifact, @Nonnull String versionSpec )
119 {
120 if ( artifact == null )
121 {
122 return false;
123 }
124 try
125 {
126 VersionRange range = createFromVersionSpec( versionSpec );
127 try
128 {
129 return range.containsVersion( artifact.getSelectedVersion() );
130 }
131 catch ( NullPointerException e )
132 {
133 return range.containsVersion( new DefaultArtifactVersion( artifact.getBaseVersion() ) );
134 }
135 }
136 catch ( InvalidVersionSpecificationException | OverConstrainedVersionException e )
137 {
138 throw new RuntimeException( "Bug in plugin. Please report with stacktrace" );
139 }
140 }
141
142 Map<String, Artifact> resolvePluginDependencies( ProjectBuildingRequest request,
143 Plugin plugin, Map<String, Artifact> pluginResolvedDependencies )
144 throws MojoExecutionException
145 {
146 Collection<Dependency> pluginDependencies = plugin.getDependencies();
147 try
148 {
149 Iterable<ArtifactResult> resolvedArtifacts = dependencyResolver.resolveDependencies( request,
150 pluginDependencies, null, including( RuntimeArtifactFilter.SCOPES ) );
151
152 Map<String, Artifact> resolved = new LinkedHashMap<>();
153 for ( ArtifactResult resolvedArtifact : resolvedArtifacts )
154 {
155 Artifact artifact = resolvedArtifact.getArtifact();
156 String key = artifact.getGroupId() + ":" + artifact.getArtifactId();
157 Artifact resolvedPluginDependency = pluginResolvedDependencies.get( key );
158 if ( resolvedPluginDependency != null )
159 {
160 resolved.put( key, artifact );
161 }
162 }
163 return resolved;
164 }
165 catch ( DependencyResolverException e )
166 {
167 throw new MojoExecutionException( e.getLocalizedMessage(), e );
168 }
169 }
170
171 ArtifactResolutionResult resolvePluginArtifact( Artifact artifact )
172 {
173 return resolvePluginArtifact( artifact, new RuntimeArtifactFilter() );
174 }
175
176 ArtifactResolutionResult resolveProjectArtifact( Artifact artifact )
177 {
178 return resolveProjectArtifact( artifact, new RuntimeArtifactFilter() );
179 }
180
181 private ArtifactResolutionResult resolvePluginArtifact( Artifact artifact, ArtifactFilter filter )
182 {
183 return resolveArtifact( artifact, pluginRemoteRepositories, filter );
184 }
185
186 private ArtifactResolutionResult resolveProjectArtifact( Artifact artifact, ArtifactFilter filter )
187 {
188 return resolveArtifact( artifact, projectRemoteRepositories, filter );
189 }
190
191 private ArtifactResolutionResult resolveArtifact( Artifact artifact, List<ArtifactRepository> repositories,
192 ArtifactFilter filter )
193 {
194 ArtifactResolutionRequest request = new ArtifactResolutionRequest()
195 .setOffline( offline )
196 .setArtifact( artifact )
197 .setLocalRepository( localRepository )
198 .setResolveTransitively( true )
199 .setCollectionFilter( filter )
200 .setRemoteRepositories( repositories );
201
202 return repositorySystem.resolve( request );
203 }
204
205 @Nonnull
206 Set<Artifact> getProviderClasspath( String providerArtifactId, String providerVersion )
207 {
208 Dependency provider = toProviderDependency( providerArtifactId, providerVersion );
209
210 Artifact providerArtifact = repositorySystem.createDependencyArtifact( provider );
211
212 ArtifactResolutionResult result = resolvePluginArtifact( providerArtifact );
213
214 if ( log.isDebugEnabled() )
215 {
216 for ( Artifact artifact : result.getArtifacts() )
217 {
218 String artifactPath = artifact.getFile().getAbsolutePath();
219 String scope = artifact.getScope();
220 log.debug( "Adding to " + pluginName + " test classpath: " + artifactPath + " Scope: " + scope );
221 }
222 }
223
224 return orderProviderArtifacts( result.getArtifacts() );
225 }
226
227 @Nonnull
228 Map<String, Artifact> getProviderClasspathAsMap( String providerArtifactId, String providerVersion )
229 {
230 return artifactMapByVersionlessId( getProviderClasspath( providerArtifactId, providerVersion ) );
231 }
232
233 private static Set<Artifact> orderProviderArtifacts( Set<Artifact> providerArtifacts )
234 {
235 Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<>();
236 for ( String order : PROVIDER_CLASSPATH_ORDER )
237 {
238 Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
239 while ( providerArtifactsIt.hasNext() )
240 {
241 Artifact providerArtifact = providerArtifactsIt.next();
242 if ( providerArtifact.getArtifactId().equals( order ) )
243 {
244 orderedProviderArtifacts.add( providerArtifact );
245 providerArtifactsIt.remove();
246 }
247 }
248 }
249 orderedProviderArtifacts.addAll( providerArtifacts );
250 return orderedProviderArtifacts;
251 }
252
253 private static Dependency toProviderDependency( String providerArtifactId, String providerVersion )
254 {
255 Dependency dependency = new Dependency();
256 dependency.setGroupId( PROVIDER_GROUP_ID );
257 dependency.setArtifactId( providerArtifactId );
258 dependency.setVersion( providerVersion );
259 dependency.setType( "jar" );
260 return dependency;
261 }
262
263 static class RuntimeArtifactFilter implements ArtifactFilter
264 {
265 private static final Collection<String> SCOPES =
266 asList( SCOPE_COMPILE, SCOPE_COMPILE_PLUS_RUNTIME, SCOPE_RUNTIME );
267
268 private final Artifact filter;
269
270 RuntimeArtifactFilter()
271 {
272 this( null );
273 }
274
275 RuntimeArtifactFilter( Artifact filter )
276 {
277 this.filter = filter;
278 }
279
280 @Override
281 public boolean include( Artifact artifact )
282 {
283 String scope = artifact.getScope();
284 return ( filter == null || artifact.equals( filter ) )
285 && !artifact.isOptional() && ( scope == null || SCOPES.contains( scope ) );
286 }
287 }
288 }