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.eclipse.aether.artifact.Artifact;
23 import org.eclipse.aether.graph.DependencyNode;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Queue;
33 import java.util.Set;
34
35
36
37
38 abstract class AbstractVerboseGraphSerializer
39 {
40 protected static final String LINE_START_LAST_CHILD = "\\- ", LINE_START_CHILD = "+- ";
41 protected static final String PRE_MANAGED_SCOPE = "preManagedScope", PRE_MANAGED_VERSION = "preManagedVersion",
42 MANAGED_SCOPE = "managedScope";
43
44 public abstract String serialize( DependencyNode root );
45
46 protected static String getDependencyCoordinate( DependencyNode node )
47 {
48 Artifact artifact = node.getArtifact();
49
50 if ( node.getDependency() == null )
51 {
52
53 return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getExtension() + ":"
54 + artifact.getVersion();
55 }
56
57 String scope;
58 if ( artifact.getProperties().containsKey( MANAGED_SCOPE ) )
59 {
60 scope = artifact.getProperties().get( MANAGED_SCOPE );
61 }
62 else
63 {
64 scope = node.getDependency().getScope();
65 }
66
67 String coords = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getExtension() + ":"
68 + artifact.getVersion();
69
70 if ( scope != null && !scope.isEmpty() )
71 {
72 coords = coords.concat( ":" + scope );
73 }
74 return coords;
75 }
76
77 private static String getVersionlessScopelessCoordinate( DependencyNode node )
78 {
79 Artifact artifact = node.getArtifact();
80
81 return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getExtension();
82 }
83
84 private static boolean isDuplicateDependencyCoordinate( DependencyNode node, Set<String> coordinateStrings )
85 {
86 return coordinateStrings.contains( getDependencyCoordinate( node ) );
87 }
88
89 private static String versionConflict( DependencyNode node, Map<String, String> coordinateVersionMap )
90 {
91 if ( coordinateVersionMap.containsKey( getVersionlessScopelessCoordinate( node ) ) )
92 {
93 return coordinateVersionMap.get( getVersionlessScopelessCoordinate( node ) );
94 }
95 return null;
96 }
97
98 private static String scopeConflict( DependencyNode node, Set<String> coordinateStrings )
99 {
100 Artifact artifact = node.getArtifact();
101 List<String> scopes = Arrays.asList( "compile", "provided", "runtime", "test", "system" );
102
103 for ( String scope : scopes )
104 {
105 String coordinate = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getExtension()
106 + ":" + artifact.getVersion() + ":" + scope;
107 if ( coordinateStrings.contains( coordinate ) )
108 {
109 return scope;
110 }
111 }
112 return null;
113 }
114
115 protected Map<DependencyNode, String> getNodeConflictMessagesBfs( DependencyNode root, Set<String> coordinateStrings
116 , Map<String, String> coordinateVersionMap )
117 {
118 Map<DependencyNode, String> nodeErrors = new HashMap<>();
119 Set<DependencyNode> visitedNodes = new HashSet<>( 512 );
120 Queue<DependencyNode> queue = new LinkedList<>();
121 visitedNodes.add( root );
122 queue.add( root );
123
124 while ( !queue.isEmpty() )
125 {
126 DependencyNode node = queue.poll();
127
128 if ( node == null || node.getArtifact() == null )
129 {
130
131 nodeErrors.put( node, "Null Artifact Node" );
132 break;
133 }
134
135 if ( isDuplicateDependencyCoordinate( node, coordinateStrings ) )
136 {
137 nodeErrors.put( node, "omitted for duplicate" );
138 }
139 else if ( scopeConflict( node, coordinateStrings ) != null )
140 {
141 nodeErrors.put( node, "omitted for conflict with " + scopeConflict( node, coordinateStrings ) );
142 }
143 else if ( versionConflict( node, coordinateVersionMap ) != null )
144 {
145 nodeErrors.put( node, "omitted for conflict with " + versionConflict( node, coordinateVersionMap ) );
146 }
147 else if ( versionConflict( node, coordinateVersionMap ) != null )
148 {
149 nodeErrors.put( node, "omitted for conflict with "
150 + versionConflict( node, coordinateVersionMap ) );
151 }
152 else if ( node.getDependency() != null && node.getDependency().isOptional() )
153 {
154 nodeErrors.put( node, "omitted due to optional dependency" );
155 }
156 else
157 {
158 boolean ignoreNode = false;
159 nodeErrors.put( node, null );
160
161 if ( node.getArtifact() != null )
162 {
163 coordinateVersionMap.put( getVersionlessScopelessCoordinate( node ),
164 node.getArtifact().getVersion() );
165 }
166
167 for ( DependencyNode child : node.getChildren() )
168 {
169 if ( visitedNodes.contains( child ) )
170 {
171 ignoreNode = true;
172 nodeErrors.put( node, "omitted for introducing a cycle with "
173 + getDependencyCoordinate( child ) );
174 node.setChildren( new ArrayList<DependencyNode>() );
175 break;
176 }
177 }
178
179 if ( !ignoreNode )
180 {
181 for ( int i = 0; i < node.getChildren().size(); ++i )
182 {
183 DependencyNode child = node.getChildren().get( i );
184
185 if ( !visitedNodes.contains( child ) )
186 {
187 visitedNodes.add( child );
188 queue.add( child );
189 }
190 }
191 }
192 }
193 coordinateStrings.add( getDependencyCoordinate( node ) );
194 }
195 return nodeErrors;
196 }
197 }