View Javadoc
1   package org.apache.maven.plugin.surefire;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Iterator;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.factory.ArtifactFactory;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
32  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
33  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
34  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
35  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
36  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
37  import org.apache.maven.artifact.versioning.VersionRange;
38  import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
39  import org.apache.maven.repository.RepositorySystem;
40  
41  import javax.annotation.Nonnull;
42  import javax.annotation.Nullable;
43  
44  import static java.util.Collections.singletonList;
45  import static org.apache.maven.artifact.Artifact.SCOPE_TEST;
46  import static org.apache.maven.artifact.versioning.VersionRange.createFromVersion;
47  import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
48  
49  /**
50   * Does dependency resolution and artifact handling for the surefire plugin.
51   *
52   * @author Stephen Connolly
53   * @author Kristian Rosenvold
54   */
55  final class SurefireDependencyResolver
56  {
57      static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
58  
59      private static final String[] PROVIDER_CLASSPATH_ORDER = {
60              "surefire-junit3",
61              "surefire-junit4",
62              "surefire-junit47",
63              "surefire-testng",
64              "surefire-junit-platform",
65              "surefire-api",
66              "surefire-logger-api",
67              "common-java5",
68              "common-junit3",
69              "common-junit4",
70              "common-junit48",
71              "common-testng-utils"
72      };
73  
74      private final RepositorySystem repositorySystem;
75  
76      private final ArtifactFactory artifactFactory;
77  
78      private final ConsoleLogger log;
79  
80      private final ArtifactRepository localRepository;
81  
82      private final List<ArtifactRepository> remoteRepositories;
83  
84      private final String pluginName;
85  
86      SurefireDependencyResolver( RepositorySystem repositorySystem, ArtifactFactory artifactFactory, ConsoleLogger log,
87                                            ArtifactRepository localRepository,
88                                            List<ArtifactRepository> remoteRepositories, String pluginName )
89      {
90          this.repositorySystem = repositorySystem;
91          this.artifactFactory = artifactFactory;
92          this.log = log;
93          this.localRepository = localRepository;
94          this.remoteRepositories = remoteRepositories;
95          this.pluginName = pluginName;
96      }
97  
98      static boolean isWithinVersionSpec( @Nullable Artifact artifact, @Nonnull String versionSpec )
99      {
100         if ( artifact == null )
101         {
102             return false;
103         }
104         try
105         {
106             VersionRange range = createFromVersionSpec( versionSpec );
107             try
108             {
109                 return range.containsVersion( artifact.getSelectedVersion() );
110             }
111             catch ( NullPointerException e )
112             {
113                 return range.containsVersion( new DefaultArtifactVersion( artifact.getBaseVersion() ) );
114             }
115         }
116         catch ( InvalidVersionSpecificationException | OverConstrainedVersionException e )
117         {
118             throw new RuntimeException( "Bug in plugin. Please report with stacktrace" );
119         }
120     }
121 
122     ArtifactResolutionResult resolveArtifact( Artifact providerArtifact )
123     {
124         return resolveArtifact( providerArtifact, null );
125     }
126 
127     private ArtifactResolutionResult resolveArtifact( Artifact providerArtifact, @Nullable Artifact excludeArtifact )
128     {
129         ArtifactResolutionRequest request = new ArtifactResolutionRequest()
130                                                     .setArtifact( providerArtifact )
131                                                     .setRemoteRepositories( remoteRepositories )
132                                                     .setLocalRepository( localRepository )
133                                                     .setResolveTransitively( true );
134         if ( excludeArtifact != null )
135         {
136             String pattern = excludeArtifact.getGroupId() + ":" + excludeArtifact.getArtifactId();
137             request.setCollectionFilter( new ExcludesArtifactFilter( singletonList( pattern ) ) );
138         }
139         return repositorySystem.resolve( request );
140     }
141 
142     @Nonnull
143     Set<Artifact> getProviderClasspath( String providerArtifactId, String providerVersion )
144     {
145         Artifact providerArtifact = artifactFactory.createDependencyArtifact( PROVIDER_GROUP_ID,
146                 providerArtifactId, createFromVersion( providerVersion ), "jar", null, SCOPE_TEST );
147 
148         ArtifactResolutionResult result = resolveArtifact( providerArtifact );
149 
150         if ( log.isDebugEnabled() )
151         {
152             for ( Artifact artifact : result.getArtifacts() )
153             {
154                 String artifactPath = artifact.getFile().getAbsolutePath();
155                 String scope = artifact.getScope();
156                 log.debug( "Adding to " + pluginName + " test classpath: " + artifactPath + " Scope: " + scope );
157             }
158         }
159 
160         return orderProviderArtifacts( result.getArtifacts() );
161     }
162 
163     Set<Artifact> addProviderToClasspath( Map<String, Artifact> pluginArtifactMap, Artifact mojoPluginArtifact,
164                                           Artifact surefireCommon, Artifact surefireApi, Artifact surefireLoggerApi )
165     {
166         Set<Artifact> providerArtifacts = new LinkedHashSet<>();
167         ArtifactResolutionResult artifactResolutionResult = resolveArtifact( mojoPluginArtifact );
168         for ( Artifact artifact : pluginArtifactMap.values() )
169         {
170             if ( !artifactResolutionResult.getArtifacts().contains( artifact ) )
171             {
172                 providerArtifacts.add( artifact );
173                 for ( Artifact dependency : resolveArtifact( artifact ).getArtifacts() )
174                 {
175                     String groupId = dependency.getGroupId();
176                     String artifactId = dependency.getArtifactId();
177                     if ( groupId.equals( surefireCommon.getGroupId() )
178                             && artifactId.equals( surefireCommon.getArtifactId() ) )
179                     {
180                         providerArtifacts.add( surefireCommon );
181                     }
182                     else if ( groupId.equals( surefireApi.getGroupId() )
183                             && artifactId.equals( surefireApi.getArtifactId() ) )
184                     {
185                         providerArtifacts.add( surefireApi );
186                     }
187                     else if ( groupId.equals( surefireLoggerApi.getGroupId() )
188                             && artifactId.equals( surefireLoggerApi.getArtifactId() ) )
189                     {
190                         providerArtifacts.add( surefireLoggerApi );
191                     }
192                 }
193             }
194         }
195         return orderProviderArtifacts( providerArtifacts );
196     }
197 
198     private static Set<Artifact> orderProviderArtifacts( Set<Artifact> providerArtifacts )
199     {
200         Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<>();
201         for ( String order : PROVIDER_CLASSPATH_ORDER )
202         {
203             Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
204             while ( providerArtifactsIt.hasNext() )
205             {
206                 Artifact providerArtifact = providerArtifactsIt.next();
207                 if ( providerArtifact.getArtifactId().equals( order ) )
208                 {
209                     orderedProviderArtifacts.add( providerArtifact );
210                     providerArtifactsIt.remove();
211                 }
212             }
213         }
214         orderedProviderArtifacts.addAll( providerArtifacts );
215         return orderedProviderArtifacts;
216     }
217 }