1 package org.apache.maven.plugins.dependency.tree;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.model.DependencyManagement;
23 import org.apache.maven.model.Model;
24 import org.apache.maven.project.DefaultDependencyResolutionRequest;
25 import org.apache.maven.project.DependencyResolutionException;
26 import org.apache.maven.project.DependencyResolutionRequest;
27 import org.apache.maven.project.DependencyResolutionResult;
28 import org.apache.maven.project.MavenProject;
29 import org.apache.maven.project.ProjectBuildingRequest;
30 import org.apache.maven.project.ProjectDependenciesResolver;
31 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
32 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
33 import org.eclipse.aether.DefaultRepositorySystemSession;
34 import org.eclipse.aether.RepositorySystemSession;
35 import org.eclipse.aether.artifact.Artifact;
36 import org.eclipse.aether.artifact.DefaultArtifact;
37 import org.eclipse.aether.collection.DependencySelector;
38 import org.eclipse.aether.graph.DefaultDependencyNode;
39 import org.eclipse.aether.graph.Dependency;
40 import org.eclipse.aether.graph.DependencyNode;
41 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
42 import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
43 import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
44 import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
45 import org.eclipse.aether.util.graph.transformer.JavaDependencyContextRefiner;
46
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Objects;
55 import java.util.Set;
56
57
58
59
60 class VerboseDependencyGraphBuilder
61 {
62 private static final String PRE_MANAGED_SCOPE = "preManagedScope", PRE_MANAGED_VERSION = "preManagedVersion",
63 MANAGED_SCOPE = "managedScope";
64
65 public DependencyNode buildVerboseGraph( MavenProject project, ProjectDependenciesResolver resolver,
66 RepositorySystemSession repositorySystemSession,
67 Collection<MavenProject> reactorProjects,
68 ProjectBuildingRequest buildingRequest )
69 throws DependencyGraphBuilderException
70 {
71 DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
72 session.setLocalRepositoryManager( repositorySystemSession.getLocalRepositoryManager() );
73
74 DependencySelector dependencySelector = new AndDependencySelector(
75
76
77 new ScopeDependencySelector(), new ExclusionDependencySelector() );
78
79 session.setDependencySelector( dependencySelector );
80 session.setDependencyGraphTransformer(
81 new ChainedDependencyGraphTransformer( new CycleBreakerGraphTransformer(),
82 new JavaDependencyContextRefiner() ) );
83 session.setDependencyManager( null );
84
85 DependencyResolutionRequest request = new DefaultDependencyResolutionRequest();
86 request.setMavenProject( buildingRequest.getProject() );
87 request.setRepositorySession( session ) ;
88 DependencyNode rootNode;
89 boolean reactor = false;
90
91 try
92 {
93 rootNode = resolver.resolve( request ).getDependencyGraph();
94 }
95 catch ( DependencyResolutionException e )
96 {
97
98
99 DependencyResolutionRequest reactorRequest = new DefaultDependencyResolutionRequest();
100 reactorRequest.setMavenProject( buildingRequest.getProject() );
101 reactorRequest.setRepositorySession( buildingRequest.getRepositorySession() ) ;
102 try
103 {
104 rootNode = resolver.resolve( reactorRequest ).getDependencyGraph();
105 }
106 catch ( DependencyResolutionException exception )
107 {
108 if ( reactorProjects == null )
109 {
110 throw new DependencyGraphBuilderException( "Could not resolve following dependencies: "
111 + exception.getResult().getUnresolvedDependencies(), exception );
112 }
113 reactor = true;
114
115 rootNode = collectDependenciesFromReactor( exception, reactorProjects ).getDependencyGraph();
116 rootNode.setData( "ContainsModule", "True" );
117
118 }
119 }
120
121
122 DependencyNode prunedRoot = pruneTransitiveTestDependencies( rootNode, project );
123 applyDependencyManagement( project, prunedRoot );
124 if ( reactor )
125 {
126 prunedRoot.setData( "ContainsModule", "True" );
127 }
128 return prunedRoot;
129 }
130
131 private void applyDependencyManagement( MavenProject project, DependencyNode root )
132 {
133 Map<String, org.apache.maven.model.Dependency> dependencyManagementMap = createDependencyManagementMap(
134 project.getDependencyManagement() );
135
136 for ( DependencyNode child : root.getChildren() )
137 {
138 for ( DependencyNode nonTransitiveDependencyNode : child.getChildren() )
139 {
140 applyDependencyManagementDfs( dependencyManagementMap, nonTransitiveDependencyNode );
141 }
142 }
143 }
144
145 private void applyDependencyManagementDfs( Map<String, org.apache.maven.model.Dependency> dependencyManagementMap,
146 DependencyNode node )
147 {
148 if ( dependencyManagementMap.containsKey( getDependencyManagementCoordinate( node.getArtifact() ) ) )
149 {
150 org.apache.maven.model.Dependency manager = dependencyManagementMap.get(
151 getDependencyManagementCoordinate( node.getArtifact() ) );
152 Map<String, String> artifactProperties = new HashMap<>();
153 for ( Map.Entry<String, String> entry : node.getArtifact().getProperties().entrySet() )
154 {
155 artifactProperties.put( entry.getKey(), entry.getValue() );
156 }
157
158 if ( !manager.getVersion().equals( node.getArtifact().getVersion() ) )
159 {
160 artifactProperties.put( PRE_MANAGED_VERSION, node.getArtifact().getVersion() );
161 node.setArtifact( node.getArtifact().setVersion( manager.getVersion() ) );
162 }
163
164 String managerScope = Objects.toString( manager.getScope(), "compile" );
165 Dependency dependency = node.getDependency();
166 String dependencyScope = dependency.getScope();
167 if ( !managerScope.equals( dependencyScope ) )
168 {
169 artifactProperties.put( PRE_MANAGED_SCOPE, dependencyScope );
170
171 artifactProperties.put( MANAGED_SCOPE, managerScope );
172 }
173 node.setArtifact( node.getArtifact().setProperties( artifactProperties ) );
174 dependency.setArtifact( dependency.getArtifact().setProperties( artifactProperties ) );
175 }
176 for ( DependencyNode child : node.getChildren() )
177 {
178 applyDependencyManagementDfs( dependencyManagementMap, child );
179 }
180 }
181
182 private static Map<String, org.apache.maven.model.Dependency> createDependencyManagementMap(
183 DependencyManagement dependencyManagement )
184 {
185 Map<String, org.apache.maven.model.Dependency> dependencyManagementMap = new HashMap<>();
186 if ( dependencyManagement == null )
187 {
188 return dependencyManagementMap;
189 }
190 for ( org.apache.maven.model.Dependency dependency : dependencyManagement.getDependencies() )
191 {
192 dependencyManagementMap.put( getDependencyManagementCoordinate( dependency ), dependency );
193 }
194 return dependencyManagementMap;
195 }
196
197 private static String getDependencyManagementCoordinate( org.apache.maven.model.Dependency dependency )
198 {
199 StringBuilder builder = new StringBuilder();
200 builder.append( dependency.getGroupId() ).append( ":" ).append( dependency.getArtifactId() ).append( ":" )
201 .append( dependency.getType() );
202 if ( dependency.getClassifier() != null && !dependency.getClassifier().equals( "" ) )
203 {
204 builder.append( ":" ).append( dependency.getClassifier() );
205 }
206 return builder.toString();
207 }
208
209 private static String getDependencyManagementCoordinate( Artifact artifact )
210 {
211 StringBuilder builder = new StringBuilder();
212 builder.append( artifact.getGroupId() ).append( ":" ).append( artifact.getArtifactId() ).append( ":" ).append(
213 artifact.getExtension() );
214 if ( artifact.getClassifier() != null && !artifact.getClassifier().equals( "" ) )
215 {
216 builder.append( ":" ).append( artifact.getClassifier() );
217 }
218 return builder.toString();
219 }
220
221 private Dependency getProjectDependency( MavenProject project )
222 {
223 Model model = project.getModel();
224
225 return new Dependency( new DefaultArtifact( model.getGroupId(), model.getArtifactId(), model.getPackaging(),
226 model.getVersion() ), "" );
227 }
228
229 private DependencyNode pruneTransitiveTestDependencies( DependencyNode rootNode, MavenProject project )
230 {
231 Set<DependencyNode> visitedNodes = new HashSet<>();
232 DependencyNode newRoot = new DefaultDependencyNode( getProjectDependency( project ) );
233 newRoot.setChildren( new ArrayList<DependencyNode>() );
234
235 for ( int i = 0; i < rootNode.getChildren().size(); i++ )
236 {
237 DependencyNode childNode = rootNode.getChildren().get( i );
238 newRoot.getChildren().add( childNode );
239
240 pruneTransitiveTestDependenciesDfs( childNode, visitedNodes );
241 }
242
243 return newRoot;
244 }
245
246 private void pruneTransitiveTestDependenciesDfs( DependencyNode node, Set<DependencyNode> visitedNodes )
247 {
248 if ( !visitedNodes.contains( node ) )
249 {
250 visitedNodes.add( node );
251
252 Iterator<DependencyNode> iterator = node.getChildren().iterator();
253 while ( iterator.hasNext() )
254 {
255 DependencyNode child = iterator.next();
256 if ( child.getDependency().getScope().equals( "test" ) )
257 {
258 iterator.remove();
259 }
260 else
261 {
262 pruneTransitiveTestDependenciesDfs( child, visitedNodes );
263 }
264 }
265 }
266 }
267
268 private DependencyResolutionResult collectDependenciesFromReactor( DependencyResolutionException e,
269 Collection<MavenProject> reactorProjects )
270 throws DependencyGraphBuilderException
271 {
272 DependencyResolutionResult result = e.getResult();
273
274 List<Dependency> reactorDeps = getReactorDependencies( reactorProjects, result.getUnresolvedDependencies() );
275 result.getUnresolvedDependencies().removeAll( reactorDeps );
276 result.getResolvedDependencies().addAll( reactorDeps );
277
278 if ( !result.getUnresolvedDependencies().isEmpty() )
279 {
280 throw new DependencyGraphBuilderException( "Could not resolve nor collect following dependencies: "
281 + result.getUnresolvedDependencies(), e );
282 }
283
284 return result;
285 }
286
287 private List<Dependency> getReactorDependencies( Collection<MavenProject> reactorProjects, List<?> dependencies )
288 {
289 Set<ArtifactKey> reactorProjectsIds = new HashSet<ArtifactKey>();
290 for ( MavenProject project : reactorProjects )
291 {
292 reactorProjectsIds.add( new ArtifactKey( project ) );
293 }
294
295 List<Dependency> reactorDeps = new ArrayList<Dependency>();
296 for ( Object untypedDependency : dependencies )
297 {
298 Dependency dependency = (Dependency) untypedDependency;
299 org.eclipse.aether.artifact.Artifact depArtifact = dependency.getArtifact();
300
301 ArtifactKey key =
302 new ArtifactKey( depArtifact.getGroupId(), depArtifact.getArtifactId(), depArtifact.getVersion() );
303
304 if ( reactorProjectsIds.contains( key ) )
305 {
306 reactorDeps.add( dependency );
307 }
308 }
309
310 return reactorDeps;
311 }
312 }