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