1 package org.apache.maven.plugins.enforcer;
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.artifact.repository.ArtifactRepository;
27 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
28 import org.apache.maven.enforcer.rule.api.EnforcerRule;
29 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
30 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.plugin.logging.Log;
33 import org.apache.maven.plugins.enforcer.utils.DependencyVersionMap;
34 import org.apache.maven.project.DefaultProjectBuildingRequest;
35 import org.apache.maven.project.MavenProject;
36 import org.apache.maven.project.ProjectBuildingRequest;
37 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
38 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
39 import org.apache.maven.shared.dependency.graph.DependencyNode;
40 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
41 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
42
43
44
45
46 public class DependencyConvergence
47 implements EnforcerRule
48 {
49 private static Log log;
50
51 private boolean uniqueVersions;
52
53 public void setUniqueVersions( boolean uniqueVersions )
54 {
55 this.uniqueVersions = uniqueVersions;
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69
70 private DependencyNode getNode( EnforcerRuleHelper helper )
71 throws EnforcerRuleException
72 {
73 try
74 {
75 MavenProject project = (MavenProject) helper.evaluate( "${project}" );
76 MavenSession session = (MavenSession) helper.evaluate( "${session}" );
77 DependencyCollectorBuilder dependencyCollectorBuilder =
78 helper.getComponent( DependencyCollectorBuilder.class );
79 ArtifactRepository repository = (ArtifactRepository) helper.evaluate( "${localRepository}" );
80
81 ProjectBuildingRequest buildingRequest =
82 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
83 buildingRequest.setProject( project );
84 buildingRequest.setLocalRepository( repository );
85 ArtifactFilter filter = null;
86
87 return dependencyCollectorBuilder.collectDependencyGraph( buildingRequest, filter );
88 }
89 catch ( ExpressionEvaluationException | ComponentLookupException e )
90 {
91 throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
92 }
93 catch ( DependencyCollectorBuilderException e )
94 {
95 throw new EnforcerRuleException( "Could not build dependency tree " + e.getLocalizedMessage(), e );
96 }
97 }
98
99 @Override
100 public void execute( EnforcerRuleHelper helper )
101 throws EnforcerRuleException
102 {
103 if ( log == null )
104 {
105 log = helper.getLog();
106 }
107 try
108 {
109 DependencyNode node = getNode( helper );
110 DependencyVersionMap visitor = new DependencyVersionMap( log );
111 visitor.setUniqueVersions( uniqueVersions );
112 node.accept( visitor );
113 List<CharSequence> errorMsgs = new ArrayList<>();
114 errorMsgs.addAll( getConvergenceErrorMsgs( visitor.getConflictedVersionNumbers() ) );
115 for ( CharSequence errorMsg : errorMsgs )
116 {
117 log.warn( errorMsg );
118 }
119 if ( errorMsgs.size() > 0 )
120 {
121 throw new EnforcerRuleException( "Failed while enforcing releasability. "
122 + "See above detailed error message." );
123 }
124 }
125 catch ( Exception e )
126 {
127 throw new EnforcerRuleException( e.getLocalizedMessage(), e );
128 }
129 }
130
131 private StringBuilder buildTreeString( DependencyNode node )
132 {
133 List<String> loc = new ArrayList<>();
134 DependencyNode currentNode = node;
135 while ( currentNode != null )
136 {
137 loc.add( currentNode.getArtifact().toString() );
138 currentNode = currentNode.getParent();
139 }
140 Collections.reverse( loc );
141 StringBuilder builder = new StringBuilder();
142 for ( int i = 0; i < loc.size(); i++ )
143 {
144 for ( int j = 0; j < i; j++ )
145 {
146 builder.append( " " );
147 }
148 builder.append( "+-" + loc.get( i ) );
149 builder.append( System.lineSeparator() );
150 }
151 return builder;
152 }
153
154 private List<String> getConvergenceErrorMsgs( List<List<DependencyNode>> errors )
155 {
156 List<String> errorMsgs = new ArrayList<>();
157 for ( List<DependencyNode> nodeList : errors )
158 {
159 errorMsgs.add( buildConvergenceErrorMsg( nodeList ) );
160 }
161 return errorMsgs;
162 }
163
164 private String buildConvergenceErrorMsg( List<DependencyNode> nodeList )
165 {
166 StringBuilder builder = new StringBuilder();
167 builder.append( System.lineSeparator() + "Dependency convergence error for "
168 + nodeList.get( 0 ).getArtifact().toString()
169 + " paths to dependency are:" + System.lineSeparator() );
170 if ( nodeList.size() > 0 )
171 {
172 builder.append( buildTreeString( nodeList.get( 0 ) ) );
173 }
174 for ( DependencyNode node : nodeList.subList( 1, nodeList.size() ) )
175 {
176 builder.append( "and" + System.lineSeparator() );
177 builder.append( buildTreeString( node ) );
178 }
179 return builder.toString();
180 }
181
182 @Override
183 public String getCacheId()
184 {
185 return "";
186 }
187
188 @Override
189 public boolean isCacheable()
190 {
191 return false;
192 }
193
194 @Override
195 public boolean isResultValid( EnforcerRule rule )
196 {
197 return false;
198 }
199 }