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 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.List;
24
25 import org.apache.maven.artifact.Artifact;
26 import org.apache.maven.artifact.factory.ArtifactFactory;
27 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.artifact.resolver.ArtifactCollector;
30 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
31 import org.apache.maven.enforcer.rule.api.EnforcerRule;
32 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
33 import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
34 import org.apache.maven.plugin.logging.Log;
35 import org.apache.maven.plugins.enforcer.utils.DependencyVersionMap;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.maven.shared.dependency.tree.DependencyNode;
38 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
39 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
40 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
41 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
42 import org.codehaus.plexus.i18n.I18N;
43
44
45
46
47 public class DependencyConvergence
48 implements EnforcerRule
49 {
50
51 private static Log log;
52
53 private static I18N i18n;
54
55 private boolean uniqueVersions;
56
57 public void setUniqueVersions( boolean uniqueVersions )
58 {
59 this.uniqueVersions = uniqueVersions;
60 }
61
62
63
64
65
66
67
68
69
70
71
72 private DependencyNode getNode( EnforcerRuleHelper helper )
73 throws EnforcerRuleException
74 {
75 try
76 {
77 MavenProject project = (MavenProject) helper.evaluate( "${project}" );
78 DependencyTreeBuilder dependencyTreeBuilder =
79 (DependencyTreeBuilder) helper.getComponent( DependencyTreeBuilder.class );
80 ArtifactRepository repository = (ArtifactRepository) helper.evaluate( "${localRepository}" );
81 ArtifactFactory factory = (ArtifactFactory) helper.getComponent( ArtifactFactory.class );
82 ArtifactMetadataSource metadataSource =
83 (ArtifactMetadataSource) helper.getComponent( ArtifactMetadataSource.class );
84 ArtifactCollector collector = (ArtifactCollector) helper.getComponent( ArtifactCollector.class );
85 ArtifactFilter filter = null;
86 DependencyNode node =
87 dependencyTreeBuilder.buildDependencyTree( project, repository, factory, metadataSource, filter,
88 collector );
89 return node;
90 }
91 catch ( ExpressionEvaluationException e )
92 {
93 throw new EnforcerRuleException( "Unable to lookup an expression " + e.getLocalizedMessage(), e );
94 }
95 catch ( ComponentLookupException e )
96 {
97 throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
98 }
99 catch ( DependencyTreeBuilderException e )
100 {
101 throw new EnforcerRuleException( "Could not build dependency tree " + e.getLocalizedMessage(), e );
102 }
103 }
104
105 public void execute( EnforcerRuleHelper helper )
106 throws EnforcerRuleException
107 {
108 if ( log == null )
109 {
110 log = helper.getLog();
111 }
112 try
113 {
114 if ( i18n == null )
115 {
116 i18n = (I18N) helper.getComponent( I18N.class );
117 }
118 DependencyNode node = getNode( helper );
119 DependencyVersionMap visitor = new DependencyVersionMap( log );
120 visitor.setUniqueVersions( uniqueVersions );
121 node.accept( visitor );
122 List<CharSequence> errorMsgs = new ArrayList<CharSequence>();
123 errorMsgs.addAll( getConvergenceErrorMsgs( visitor.getConflictedVersionNumbers() ) );
124 for ( CharSequence errorMsg : errorMsgs )
125 {
126 log.warn( errorMsg );
127 }
128 if ( errorMsgs.size() > 0 )
129 {
130 throw new EnforcerRuleException( "Failed while enforcing releasability the error(s) are " + errorMsgs );
131 }
132 }
133 catch ( ComponentLookupException e )
134 {
135 throw new EnforcerRuleException( "Unable to lookup a component " + e.getLocalizedMessage(), e );
136 }
137 catch ( Exception e )
138 {
139 throw new EnforcerRuleException( e.getLocalizedMessage(), e );
140 }
141 }
142
143 private String getFullArtifactName( Artifact artifact )
144 {
145 return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
146 }
147
148 private StringBuilder buildTreeString( DependencyNode node )
149 {
150 List<String> loc = new ArrayList<String>();
151 DependencyNode currentNode = node;
152 while ( currentNode != null )
153 {
154 loc.add( getFullArtifactName( currentNode.getArtifact() ) );
155 currentNode = currentNode.getParent();
156 }
157 Collections.reverse( loc );
158 StringBuilder builder = new StringBuilder();
159 for ( int i = 0; i < loc.size(); i++ )
160 {
161 for ( int j = 0; j < i; j++ )
162 {
163 builder.append( " " );
164 }
165 builder.append( "+-" + loc.get( i ) );
166 builder.append( "\n" );
167 }
168 return builder;
169 }
170
171 private List<String> getConvergenceErrorMsgs( List<List<DependencyNode>> errors )
172 {
173 List<String> errorMsgs = new ArrayList<String>();
174 for ( List<DependencyNode> nodeList : errors )
175 {
176 errorMsgs.add( buildConvergenceErrorMsg( nodeList ) );
177 }
178 return errorMsgs;
179 }
180
181 private String buildConvergenceErrorMsg( List<DependencyNode> nodeList )
182 {
183 StringBuilder builder = new StringBuilder();
184 builder.append( "\nDependency convergence error for " + getFullArtifactName( nodeList.get( 0 ).getArtifact() )
185 + " paths to dependency are:\n" );
186 if ( nodeList.size() > 0 )
187 {
188 builder.append( buildTreeString( nodeList.get( 0 ) ) );
189 }
190 for ( DependencyNode node : nodeList.subList( 1, nodeList.size() ) )
191 {
192 builder.append( "and\n" );
193 builder.append( buildTreeString( node ) );
194 }
195 return builder.toString();
196 }
197
198
199
200
201
202
203
204 public String getCacheId()
205 {
206 return "";
207 }
208
209
210
211
212
213
214 public boolean isCacheable()
215 {
216 return false;
217 }
218
219
220
221
222
223
224
225 public boolean isResultValid( EnforcerRule arg0 )
226 {
227 return false;
228 }
229 }