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