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 javax.inject.Inject;
27 import javax.inject.Named;
28
29 import org.apache.maven.RepositoryUtils;
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.artifact.repository.ArtifactRepository;
32 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
33 import org.apache.maven.model.Dependency;
34 import org.apache.maven.project.MavenProject;
35 import org.apache.maven.project.ProjectBuildingRequest;
36 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
37 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
38 import org.apache.maven.shared.dependency.graph.DependencyNode;
39 import org.eclipse.aether.DefaultRepositorySystemSession;
40 import org.eclipse.aether.RepositorySystem;
41 import org.eclipse.aether.RepositorySystemSession;
42 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
43 import org.eclipse.aether.collection.CollectRequest;
44 import org.eclipse.aether.collection.CollectResult;
45 import org.eclipse.aether.collection.DependencyCollectionException;
46 import org.eclipse.aether.collection.DependencyGraphTransformer;
47 import org.eclipse.aether.collection.DependencySelector;
48 import org.eclipse.aether.graph.DependencyVisitor;
49 import org.eclipse.aether.graph.Exclusion;
50 import org.eclipse.aether.util.artifact.JavaScopes;
51 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
52 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
53 import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
54 import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
55 import org.eclipse.aether.util.graph.transformer.ConflictResolver;
56 import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver;
57 import org.eclipse.aether.util.graph.transformer.NearestVersionSelector;
58 import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector;
59 import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor;
60 import org.eclipse.aether.version.VersionConstraint;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64
65
66
67
68
69
70 @Named
71 public class DefaultDependencyCollectorBuilder
72 implements DependencyCollectorBuilder
73 {
74 private static final Logger LOGGER = LoggerFactory.getLogger( DefaultDependencyCollectorBuilder.class );
75
76 private final RepositorySystem repositorySystem;
77
78 @Inject
79 public DefaultDependencyCollectorBuilder( RepositorySystem repositorySystem )
80 {
81 this.repositorySystem = repositorySystem;
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 RepositorySystemSession repositorySession = buildingRequest.getRepositorySession();
97
98 session = new DefaultRepositorySystemSession( repositorySession );
99
100 DependencyGraphTransformer transformer =
101 new ConflictResolver( new NearestVersionSelector(), new VerboseJavaScopeSelector(),
102 new SimpleOptionalitySelector(), new JavaScopeDeriver() );
103 session.setDependencyGraphTransformer( transformer );
104
105 DependencySelector depFilter =
106 new AndDependencySelector( new DirectScopeDependencySelector( JavaScopes.TEST ),
107 new DirectScopeDependencySelector( JavaScopes.PROVIDED ),
108 new OptionalDependencySelector(),
109 new ExclusionDependencySelector() );
110 session.setDependencySelector( depFilter );
111
112 session.setConfigProperty( ConflictResolver.CONFIG_PROP_VERBOSE, true );
113 session.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, true );
114
115 org.eclipse.aether.artifact.Artifact aetherArtifact = RepositoryUtils.toArtifact( projectArtifact );
116
117 List<org.eclipse.aether.repository.RemoteRepository> aetherRepos =
118 RepositoryUtils.toRepos( remoteArtifactRepositories );
119
120 CollectRequest collectRequest = new CollectRequest();
121 collectRequest.setRootArtifact( aetherArtifact );
122 collectRequest.setRepositories( aetherRepos );
123
124 org.eclipse.aether.artifact.ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
125 collectDependencyList( collectRequest, project, stereotypes );
126 collectManagedDependencyList( collectRequest, project, stereotypes );
127
128 CollectResult collectResult = repositorySystem.collectDependencies( session, collectRequest );
129
130 org.eclipse.aether.graph.DependencyNode rootNode = collectResult.getRoot();
131
132 if ( LOGGER.isDebugEnabled() )
133 {
134 logTree( rootNode );
135 }
136
137 return buildDependencyNode( null, rootNode, projectArtifact, filter );
138 }
139 catch ( DependencyCollectionException e )
140 {
141 throw new DependencyCollectorBuilderException( "Could not collect dependencies: " + e.getResult(), e );
142 }
143 finally
144 {
145 if ( session != null )
146 {
147 session.setReadOnly();
148 }
149 }
150 }
151
152 private void logTree( org.eclipse.aether.graph.DependencyNode rootNode )
153 {
154
155 rootNode.accept( new TreeDependencyVisitor( new DependencyVisitor()
156 {
157 String indent = "";
158
159 @Override
160 public boolean visitEnter( org.eclipse.aether.graph.DependencyNode dependencyNode )
161 {
162 LOGGER.debug( "{}Aether node: {} data map: {}", indent, dependencyNode, dependencyNode.getData() );
163 indent += " ";
164 return true;
165 }
166
167 @Override
168 public boolean visitLeave( org.eclipse.aether.graph.DependencyNode dependencyNode )
169 {
170 indent = indent.substring( 0, indent.length() - 4 );
171 return true;
172 }
173 } ) );
174 }
175
176 private void collectManagedDependencyList( CollectRequest collectRequest, MavenProject project,
177 ArtifactTypeRegistry stereotypes )
178 {
179 if ( project.getDependencyManagement() != null )
180 {
181 for ( Dependency dependency : project.getDependencyManagement().getDependencies() )
182 {
183 org.eclipse.aether.graph.Dependency aetherDep = RepositoryUtils.toDependency( dependency, stereotypes );
184 collectRequest.addManagedDependency( aetherDep );
185 }
186 }
187 }
188
189 private void collectDependencyList( CollectRequest collectRequest, MavenProject project,
190 org.eclipse.aether.artifact.ArtifactTypeRegistry stereotypes )
191 {
192 for ( Dependency dependency : project.getDependencies() )
193 {
194 org.eclipse.aether.graph.Dependency aetherDep = RepositoryUtils.toDependency( dependency, stereotypes );
195 collectRequest.addDependency( aetherDep );
196 }
197 }
198
199 private Artifact getDependencyArtifact( org.eclipse.aether.graph.Dependency dep )
200 {
201 org.eclipse.aether.artifact.Artifact artifact = dep.getArtifact();
202
203 Artifact mavenArtifact = RepositoryUtils.toArtifact( artifact );
204 mavenArtifact.setScope( dep.getScope() );
205 mavenArtifact.setOptional( dep.isOptional() );
206
207 return mavenArtifact;
208 }
209
210 private DependencyNode buildDependencyNode( DependencyNode parent, org.eclipse.aether.graph.DependencyNode node,
211 Artifact artifact, ArtifactFilter filter )
212 {
213 String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
214 String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
215
216 Boolean optional = null;
217 if ( node.getDependency() != null )
218 {
219 optional = node.getDependency().isOptional();
220 }
221
222 List<org.apache.maven.model.Exclusion> exclusions = null;
223 if ( node.getDependency() != null )
224 {
225 exclusions = new ArrayList<>( node.getDependency().getExclusions().size() );
226 for ( Exclusion exclusion : node.getDependency().getExclusions() )
227 {
228 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
229 modelExclusion.setGroupId( exclusion.getGroupId() );
230 modelExclusion.setArtifactId( exclusion.getArtifactId() );
231 exclusions.add( modelExclusion );
232 }
233 }
234
235 org.eclipse.aether.graph.DependencyNode winner =
236 (org.eclipse.aether.graph.DependencyNode) node.getData().get( ConflictResolver.NODE_DATA_WINNER );
237 String winnerVersion = null;
238 String ignoredScope = null;
239 if ( winner != null )
240 {
241 winnerVersion = winner.getArtifact().getBaseVersion();
242 }
243 else
244 {
245 ignoredScope = (String) node.getData().get( VerboseJavaScopeSelector.REDUCED_SCOPE );
246 }
247
248 ConflictData data = new ConflictData( winnerVersion, ignoredScope );
249
250 VerboseDependencyNode current =
251 new VerboseDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
252 getVersionSelectedFromRange( node.getVersionConstraint() ), optional,
253 exclusions, data );
254
255 List<DependencyNode> nodes = new ArrayList<>( node.getChildren().size() );
256 for ( org.eclipse.aether.graph.DependencyNode child : node.getChildren() )
257 {
258 Artifact childArtifact = getDependencyArtifact( child.getDependency() );
259
260 if ( ( filter == null ) || filter.include( childArtifact ) )
261 {
262 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
263 }
264 }
265
266 current.setChildren( Collections.unmodifiableList( nodes ) );
267
268 return current;
269 }
270
271 private String getVersionSelectedFromRange( VersionConstraint constraint )
272 {
273 if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
274 {
275 return null;
276 }
277
278 return constraint.getRange().toString();
279 }
280 }