1 package org.apache.maven.shared.dependency.graph.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.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.maven.RepositoryUtils;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
30 import org.apache.maven.model.Dependency;
31 import org.apache.maven.project.MavenProject;
32 import org.apache.maven.project.ProjectBuildingRequest;
33 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
34 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
35 import org.apache.maven.shared.dependency.graph.DependencyNode;
36 import org.apache.maven.shared.dependency.graph.internal.maven30.ConflictResolver;
37 import org.apache.maven.shared.dependency.graph.internal.maven30.JavaScopeDeriver;
38 import org.apache.maven.shared.dependency.graph.internal.maven30.Maven3DirectScopeDependencySelector;
39 import org.apache.maven.shared.dependency.graph.internal.maven30.NearestVersionSelector;
40 import org.apache.maven.shared.dependency.graph.internal.maven30.SimpleOptionalitySelector;
41 import org.apache.maven.shared.dependency.graph.internal.maven30.VerboseJavaScopeSelector;
42 import org.codehaus.plexus.component.annotations.Component;
43 import org.codehaus.plexus.component.annotations.Requirement;
44 import org.codehaus.plexus.logging.AbstractLogEnabled;
45 import org.sonatype.aether.RepositorySystem;
46 import org.sonatype.aether.RepositorySystemSession;
47 import org.sonatype.aether.artifact.ArtifactTypeRegistry;
48 import org.sonatype.aether.collection.CollectRequest;
49 import org.sonatype.aether.collection.CollectResult;
50 import org.sonatype.aether.collection.DependencyCollectionException;
51 import org.sonatype.aether.collection.DependencyGraphTransformer;
52 import org.sonatype.aether.collection.DependencySelector;
53 import org.sonatype.aether.graph.DependencyVisitor;
54 import org.sonatype.aether.graph.Exclusion;
55 import org.sonatype.aether.util.DefaultRepositorySystemSession;
56 import org.sonatype.aether.util.artifact.JavaScopes;
57 import org.sonatype.aether.util.graph.TreeDependencyVisitor;
58 import org.sonatype.aether.util.graph.selector.AndDependencySelector;
59 import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
60 import org.sonatype.aether.util.graph.selector.OptionalDependencySelector;
61 import org.sonatype.aether.version.VersionConstraint;
62
63
64
65
66
67
68
69 @Component( role = DependencyCollectorBuilder.class, hint = "maven3" )
70 public class Maven3DependencyCollectorBuilder
71 extends AbstractLogEnabled
72 implements DependencyCollectorBuilder
73 {
74 @Requirement
75 private RepositorySystem repositorySystem;
76
77 private final ExceptionHandler<DependencyCollectorBuilderException> exceptionHandler;
78
79 public Maven3DependencyCollectorBuilder()
80 {
81 this.exceptionHandler = DependencyCollectorBuilderException::new;
82 }
83
84 @Override
85 public DependencyNode collectDependencyGraph( ProjectBuildingRequest buildingRequest, ArtifactFilter filter )
86 throws DependencyCollectorBuilderException
87 {
88 try
89 {
90 MavenProject project = buildingRequest.getProject();
91
92 Artifact projectArtifact = project.getArtifact();
93 List<ArtifactRepository> remoteArtifactRepositories = project.getRemoteArtifactRepositories();
94
95
96
97
98 RepositorySystemSession repositorySystemSession = buildingRequest.getRepositorySession();
99
100 DefaultRepositorySystemSession session = new DefaultRepositorySystemSession( repositorySystemSession );
101
102 DependencyGraphTransformer transformer =
103 new ConflictResolver( new NearestVersionSelector(), new VerboseJavaScopeSelector(),
104 new SimpleOptionalitySelector(), new JavaScopeDeriver() );
105 session.setDependencyGraphTransformer( transformer );
106
107 DependencySelector depFilter =
108 new AndDependencySelector( new Maven3DirectScopeDependencySelector( JavaScopes.TEST ),
109 new OptionalDependencySelector(),
110 new ExclusionDependencySelector() );
111 session.setDependencySelector( depFilter );
112
113 session.setConfigProperty( ConflictResolver.CONFIG_PROP_VERBOSE, true );
114 session.setConfigProperty( "aether.dependencyManager.verbose", true );
115
116 org.sonatype.aether.artifact.Artifact aetherArtifact =
117 (org.sonatype.aether.artifact.Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
118 Artifact.class, projectArtifact,
119 exceptionHandler );
120
121 @SuppressWarnings( "unchecked" )
122 List<org.sonatype.aether.repository.RemoteRepository> aetherRepos =
123 (List<org.sonatype.aether.repository.RemoteRepository>) Invoker.invoke( RepositoryUtils.class,
124 "toRepos", List.class,
125 remoteArtifactRepositories,
126 exceptionHandler );
127
128 CollectRequest collectRequest = new CollectRequest();
129 collectRequest.setRoot( new org.sonatype.aether.graph.Dependency( aetherArtifact, "" ) );
130 collectRequest.setRepositories( aetherRepos );
131
132 org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
133 collectDependencyList( collectRequest, project, stereotypes );
134 collectManagedDependencyList( collectRequest, project, stereotypes );
135
136 CollectResult collectResult = repositorySystem.collectDependencies( session, collectRequest );
137
138 org.sonatype.aether.graph.DependencyNode rootNode = collectResult.getRoot();
139
140 if ( getLogger().isDebugEnabled() )
141 {
142 logTree( rootNode );
143 }
144
145 return buildDependencyNode( null, rootNode, projectArtifact, filter );
146 }
147 catch ( DependencyCollectionException e )
148 {
149 throw new DependencyCollectorBuilderException( "Could not collect dependencies: " + e.getResult(), e );
150 }
151 }
152
153 private void logTree( org.sonatype.aether.graph.DependencyNode rootNode )
154 {
155
156 rootNode.accept( new TreeDependencyVisitor( new DependencyVisitor()
157 {
158 String indent = "";
159
160 @Override
161 public boolean visitEnter( org.sonatype.aether.graph.DependencyNode dependencyNode )
162 {
163 StringBuilder sb = new StringBuilder();
164 sb.append( indent ).append( "Aether node: " ).append( dependencyNode );
165 if ( !dependencyNode.getData().isEmpty() )
166 {
167 sb.append( "data map: " ).append( dependencyNode.getData() );
168 }
169 if ( dependencyNode.getPremanagedVersion() != null && !dependencyNode.getPremanagedVersion().isEmpty() )
170 {
171 sb.append( "Premanaged.version: " ).append( dependencyNode.getPremanagedVersion() );
172 }
173 if ( dependencyNode.getPremanagedScope() != null && !dependencyNode.getPremanagedScope().isEmpty() )
174 {
175 sb.append( "Premanaged.scope: " ).append( dependencyNode.getPremanagedScope() );
176 }
177 getLogger().debug( sb.toString() );
178 indent += " ";
179 return true;
180 }
181
182 @Override
183 public boolean visitLeave( org.sonatype.aether.graph.DependencyNode dependencyNode )
184 {
185 indent = indent.substring( 0, indent.length() - 4 );
186 return true;
187 }
188 } ) );
189 }
190
191 private void collectManagedDependencyList( CollectRequest collectRequest, MavenProject project,
192 ArtifactTypeRegistry stereotypes )
193 throws DependencyCollectorBuilderException
194 {
195 if ( project.getDependencyManagement() != null )
196 {
197 for ( Dependency dependency : project.getDependencyManagement().getDependencies() )
198 {
199 org.sonatype.aether.graph.Dependency aetherDep = toAetherDependency( stereotypes, dependency );
200 collectRequest.addManagedDependency( aetherDep );
201 }
202 }
203 }
204
205 private void collectDependencyList( CollectRequest collectRequest, MavenProject project,
206 org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes )
207 throws DependencyCollectorBuilderException
208 {
209 for ( Dependency dependency : project.getDependencies() )
210 {
211 org.sonatype.aether.graph.Dependency aetherDep = toAetherDependency( stereotypes, dependency );
212 collectRequest.addDependency( aetherDep );
213 }
214 }
215
216
217 private org.sonatype.aether.graph.Dependency toAetherDependency( org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes,
218 Dependency dependency )
219 throws DependencyCollectorBuilderException
220 {
221 return (org.sonatype.aether.graph.Dependency) Invoker.invoke( RepositoryUtils.class, "toDependency",
222 Dependency.class,
223 ArtifactTypeRegistry.class,
224 dependency, stereotypes, exceptionHandler );
225 }
226
227
228 private Artifact getDependencyArtifact( org.sonatype.aether.graph.Dependency dep )
229 {
230 org.sonatype.aether.artifact.Artifact artifact = dep.getArtifact();
231
232 try
233 {
234 Artifact mavenArtifact =
235 (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
236 org.sonatype.aether.artifact.Artifact.class, artifact, exceptionHandler );
237
238 mavenArtifact.setScope( dep.getScope() );
239 mavenArtifact.setOptional( dep.isOptional() );
240
241 return mavenArtifact;
242 }
243 catch ( DependencyCollectorBuilderException e )
244 {
245
246 throw new RuntimeException( e.getMessage(), e );
247 }
248 }
249
250 private DependencyNode buildDependencyNode( DependencyNode parent, org.sonatype.aether.graph.DependencyNode node,
251 Artifact artifact, ArtifactFilter filter )
252 {
253 String premanagedVersion = node.getPremanagedVersion();
254 String premanagedScope = node.getPremanagedScope();
255
256 Boolean optional = null;
257 if ( node.getDependency() != null )
258 {
259 optional = node.getDependency().isOptional();
260 }
261
262 List<org.apache.maven.model.Exclusion> exclusions = null;
263 if ( node.getDependency() != null )
264 {
265 exclusions = new ArrayList<>( node.getDependency().getExclusions().size() );
266 for ( Exclusion exclusion : node.getDependency().getExclusions() )
267 {
268 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
269 modelExclusion.setGroupId( exclusion.getGroupId() );
270 modelExclusion.setArtifactId( exclusion.getArtifactId() );
271 exclusions.add( modelExclusion );
272 }
273 }
274
275 org.sonatype.aether.graph.DependencyNode winner =
276 (org.sonatype.aether.graph.DependencyNode) node.getData().get( ConflictResolver.NODE_DATA_WINNER );
277 String winnerVersion = null;
278 String ignoredScope = null;
279 if ( winner != null )
280 {
281 winnerVersion = winner.getVersion().toString();
282 }
283 else
284 {
285 ignoredScope = (String) node.getData().get( VerboseJavaScopeSelector.REDUCED_SCOPE );
286 }
287
288 ConflictData data = new ConflictData( winnerVersion, ignoredScope );
289
290 VerboseDependencyNode current =
291 new VerboseDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
292 getVersionSelectedFromRange( node.getVersionConstraint() ), optional, exclusions,
293 data );
294
295 List<DependencyNode> nodes = new ArrayList<>( node.getChildren().size() );
296 for ( org.sonatype.aether.graph.DependencyNode child : node.getChildren() )
297 {
298 Artifact childArtifact = getDependencyArtifact( child.getDependency() );
299
300 if ( ( filter == null ) || filter.include( childArtifact ) )
301 {
302 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
303 }
304 }
305
306 current.setChildren( Collections.unmodifiableList( nodes ) );
307
308 return current;
309 }
310
311 private String getVersionSelectedFromRange( VersionConstraint constraint )
312 {
313 if ( ( constraint == null ) || ( constraint.getVersion() != null ) || ( constraint.getRanges().isEmpty() ) )
314 {
315 return null;
316 }
317
318 return constraint.getRanges().iterator().next().toString();
319 }
320
321 }