1 package org.apache.maven.lifecycle.internal;
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.Collections;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import javax.inject.Inject;
32 import javax.inject.Named;
33
34 import org.apache.maven.RepositoryUtils;
35 import org.apache.maven.artifact.Artifact;
36 import org.apache.maven.artifact.ArtifactUtils;
37 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
38 import org.apache.maven.execution.MavenSession;
39 import org.apache.maven.lifecycle.LifecycleExecutionException;
40 import org.apache.maven.project.DefaultDependencyResolutionRequest;
41 import org.apache.maven.project.DependencyResolutionException;
42 import org.apache.maven.project.DependencyResolutionResult;
43 import org.apache.maven.project.MavenProject;
44 import org.apache.maven.project.ProjectDependenciesResolver;
45 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
46 import org.codehaus.plexus.logging.Logger;
47 import org.eclipse.aether.graph.Dependency;
48 import org.eclipse.aether.graph.DependencyFilter;
49 import org.eclipse.aether.graph.DependencyNode;
50 import org.eclipse.aether.util.filter.AndDependencyFilter;
51 import org.eclipse.aether.util.filter.ScopeDependencyFilter;
52
53
54
55
56
57
58
59
60
61
62
63 @Named
64 public class LifecycleDependencyResolver
65 {
66
67 @Inject
68 private ProjectDependenciesResolver dependenciesResolver;
69
70 @Inject
71 private Logger logger;
72
73 @Inject
74 private ProjectArtifactFactory artifactFactory;
75
76 @Inject
77 private EventSpyDispatcher eventSpyDispatcher;
78
79 public LifecycleDependencyResolver()
80 {
81 }
82
83 public LifecycleDependencyResolver( ProjectDependenciesResolver projectDependenciesResolver, Logger logger )
84 {
85 this.dependenciesResolver = projectDependenciesResolver;
86 this.logger = logger;
87 }
88
89 public static List<MavenProject> getProjects( MavenProject project, MavenSession session, boolean aggregator )
90 {
91 if ( aggregator )
92 {
93 return session.getProjects();
94 }
95 else
96 {
97 return Collections.singletonList( project );
98 }
99 }
100
101 public void resolveProjectDependencies( MavenProject project, Collection<String> scopesToCollect,
102 Collection<String> scopesToResolve, MavenSession session,
103 boolean aggregating, Set<Artifact> projectArtifacts )
104 throws LifecycleExecutionException
105 {
106 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
107 try
108 {
109 ClassLoader projectRealm = project.getClassRealm();
110 if ( projectRealm != null && projectRealm != tccl )
111 {
112 Thread.currentThread().setContextClassLoader( projectRealm );
113 }
114
115 if ( project.getDependencyArtifacts() == null )
116 {
117 try
118 {
119 project.setDependencyArtifacts( artifactFactory.createArtifacts( project ) );
120 }
121 catch ( InvalidDependencyVersionException e )
122 {
123 throw new LifecycleExecutionException( e );
124 }
125 }
126
127 Set<Artifact> artifacts =
128 getDependencies( project, scopesToCollect, scopesToResolve, session, aggregating, projectArtifacts );
129
130 project.setResolvedArtifacts( artifacts );
131
132 Map<String, Artifact> map = new HashMap<>();
133 for ( Artifact artifact : artifacts )
134 {
135 map.put( artifact.getDependencyConflictId(), artifact );
136 }
137 for ( Artifact artifact : project.getDependencyArtifacts() )
138 {
139 if ( artifact.getFile() == null )
140 {
141 Artifact resolved = map.get( artifact.getDependencyConflictId() );
142 if ( resolved != null )
143 {
144 artifact.setFile( resolved.getFile() );
145 artifact.setDependencyTrail( resolved.getDependencyTrail() );
146 artifact.setResolvedVersion( resolved.getVersion() );
147 artifact.setResolved( true );
148 }
149 }
150 }
151 }
152 finally
153 {
154 Thread.currentThread().setContextClassLoader( tccl );
155 }
156 }
157
158 private Set<Artifact> getDependencies( MavenProject project, Collection<String> scopesToCollect,
159 Collection<String> scopesToResolve, MavenSession session,
160 boolean aggregating, Set<Artifact> projectArtifacts )
161 throws LifecycleExecutionException
162 {
163 if ( scopesToCollect == null )
164 {
165 scopesToCollect = Collections.emptySet();
166 }
167 if ( scopesToResolve == null )
168 {
169 scopesToResolve = Collections.emptySet();
170 }
171
172 if ( scopesToCollect.isEmpty() && scopesToResolve.isEmpty() )
173 {
174 return new LinkedHashSet<>();
175 }
176
177 scopesToCollect = new HashSet<>( scopesToCollect );
178 scopesToCollect.addAll( scopesToResolve );
179
180 DependencyFilter collectionFilter = new ScopeDependencyFilter( null, negate( scopesToCollect ) );
181 DependencyFilter resolutionFilter = new ScopeDependencyFilter( null, negate( scopesToResolve ) );
182 resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, resolutionFilter );
183 resolutionFilter =
184 AndDependencyFilter.newInstance( resolutionFilter, new ReactorDependencyFilter( projectArtifacts ) );
185
186 DependencyResolutionResult result;
187 try
188 {
189 DefaultDependencyResolutionRequest request =
190 new DefaultDependencyResolutionRequest( project, session.getRepositorySession() );
191 request.setResolutionFilter( resolutionFilter );
192
193 eventSpyDispatcher.onEvent( request );
194
195 result = dependenciesResolver.resolve( request );
196 }
197 catch ( DependencyResolutionException e )
198 {
199 result = e.getResult();
200
201
202
203
204
205
206 if ( aggregating && areAllDependenciesInReactor( session.getProjects(),
207 result.getUnresolvedDependencies() ) )
208 {
209 logger.warn( "The following dependencies could not be resolved at this point of the build"
210 + " but seem to be part of the reactor:" );
211
212 for ( Dependency dependency : result.getUnresolvedDependencies() )
213 {
214 logger.warn( "o " + dependency );
215 }
216
217 logger.warn( "Try running the build up to the lifecycle phase \"package\"" );
218 }
219 else
220 {
221 throw new LifecycleExecutionException( null, project, e );
222 }
223 }
224
225 eventSpyDispatcher.onEvent( result );
226
227 Set<Artifact> artifacts = new LinkedHashSet<>();
228 if ( result.getDependencyGraph() != null && !result.getDependencyGraph().getChildren().isEmpty() )
229 {
230 RepositoryUtils.toArtifacts( artifacts, result.getDependencyGraph().getChildren(),
231 Collections.singletonList( project.getArtifact().getId() ), collectionFilter );
232 }
233 return artifacts;
234 }
235
236 private boolean areAllDependenciesInReactor( Collection<MavenProject> projects,
237 Collection<Dependency> dependencies )
238 {
239 Set<String> projectKeys = getReactorProjectKeys( projects );
240
241 for ( Dependency dependency : dependencies )
242 {
243 org.eclipse.aether.artifact.Artifact a = dependency.getArtifact();
244 String key = ArtifactUtils.key( a.getGroupId(), a.getArtifactId(), a.getVersion() );
245 if ( !projectKeys.contains( key ) )
246 {
247 return false;
248 }
249 }
250
251 return true;
252 }
253
254 private Set<String> getReactorProjectKeys( Collection<MavenProject> projects )
255 {
256 Set<String> projectKeys = new HashSet<>( projects.size() * 2 );
257 for ( MavenProject project : projects )
258 {
259 String key = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
260 projectKeys.add( key );
261 }
262 return projectKeys;
263 }
264
265 private Collection<String> negate( Collection<String> scopes )
266 {
267 Collection<String> result = new HashSet<>();
268 Collections.addAll( result, "system", "compile", "provided", "runtime", "test" );
269
270 for ( String scope : scopes )
271 {
272 if ( "compile".equals( scope ) )
273 {
274 result.remove( "compile" );
275 result.remove( "system" );
276 result.remove( "provided" );
277 }
278 else if ( "runtime".equals( scope ) )
279 {
280 result.remove( "compile" );
281 result.remove( "runtime" );
282 }
283 else if ( "compile+runtime".equals( scope ) )
284 {
285 result.remove( "compile" );
286 result.remove( "system" );
287 result.remove( "provided" );
288 result.remove( "runtime" );
289 }
290 else if ( "runtime+system".equals( scope ) )
291 {
292 result.remove( "compile" );
293 result.remove( "system" );
294 result.remove( "runtime" );
295 }
296 else if ( "test".equals( scope ) )
297 {
298 result.clear();
299 }
300 }
301
302 return result;
303 }
304
305 private static class ReactorDependencyFilter
306 implements DependencyFilter
307 {
308
309 private Set<String> keys = new HashSet<>();
310
311 public ReactorDependencyFilter( Collection<Artifact> artifacts )
312 {
313 for ( Artifact artifact : artifacts )
314 {
315 String key = ArtifactUtils.key( artifact );
316 keys.add( key );
317 }
318 }
319
320 public boolean accept( DependencyNode node, List<DependencyNode> parents )
321 {
322 Dependency dependency = node.getDependency();
323 if ( dependency != null )
324 {
325 org.eclipse.aether.artifact.Artifact a = dependency.getArtifact();
326 String key = ArtifactUtils.key( a.getGroupId(), a.getArtifactId(), a.getVersion() );
327 return !keys.contains( key );
328 }
329 return false;
330 }
331
332 }
333
334 }