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