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