1 package org.apache.maven.plugin.dependency;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.StringWriter;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.maven.artifact.Artifact;
30 import org.apache.maven.plugin.AbstractMojo;
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.MojoFailureException;
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalysis;
35 import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzer;
36 import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzerException;
37 import org.codehaus.plexus.PlexusConstants;
38 import org.codehaus.plexus.PlexusContainer;
39 import org.codehaus.plexus.context.Context;
40 import org.codehaus.plexus.context.ContextException;
41 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
42 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
43
44
45
46
47
48
49
50
51
52 public abstract class AbstractAnalyzeMojo
53 extends AbstractMojo
54 implements Contextualizable
55 {
56
57
58
59
60
61
62 private Context context;
63
64
65
66
67
68
69
70
71 private MavenProject project;
72
73
74
75
76
77
78
79 private String analyzer;
80
81
82
83
84
85
86 private boolean failOnWarning;
87
88
89
90
91
92
93 private boolean verbose;
94
95
96
97
98
99
100 private boolean ignoreNonCompile;
101
102
103
104
105
106
107
108 private boolean outputXML;
109
110
111
112
113
114
115
116 private boolean scriptableOutput;
117
118
119
120
121
122
123
124 private String scriptableFlag;
125
126
127
128
129
130
131
132
133 private File baseDir;
134
135
136
137
138
139
140
141
142 private File outputDirectory;
143
144
145
146
147
148
149 public void execute()
150 throws MojoExecutionException, MojoFailureException
151 {
152 if ( "pom".equals( project.getPackaging() ) )
153 {
154 getLog().info( "Skipping pom project" );
155 return;
156 }
157
158 if ( outputDirectory == null || !outputDirectory.exists() )
159 {
160 getLog().info( "Skipping project with no build directory" );
161 return;
162 }
163
164 boolean warning = checkDependencies();
165
166 if ( warning && failOnWarning )
167 {
168 throw new MojoExecutionException( "Dependency problems found" );
169 }
170 }
171
172 protected ProjectDependencyAnalyzer createProjectDependencyAnalyzer()
173 throws MojoExecutionException
174 {
175
176 final String role = ProjectDependencyAnalyzer.ROLE;
177 final String roleHint = analyzer;
178
179 try
180 {
181 final PlexusContainer container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
182
183 return (ProjectDependencyAnalyzer) container.lookup( role, roleHint );
184 }
185 catch ( Exception exception )
186 {
187 throw new MojoExecutionException( "Failed to instantiate ProjectDependencyAnalyser with role " + role
188 + " / role-hint " + roleHint,exception );
189 }
190 }
191
192 public void contextualize( Context context )
193 throws ContextException
194 {
195 this.context = context;
196 }
197
198
199
200 private boolean checkDependencies()
201 throws MojoExecutionException
202 {
203 ProjectDependencyAnalysis analysis;
204 try
205 {
206 analysis = createProjectDependencyAnalyzer().analyze( project );
207 }
208 catch ( ProjectDependencyAnalyzerException exception )
209 {
210 throw new MojoExecutionException( "Cannot analyze dependencies", exception );
211 }
212
213 Set<Artifact> usedDeclared = analysis.getUsedDeclaredArtifacts();
214 Set<Artifact> usedUndeclared = analysis.getUsedUndeclaredArtifacts();
215 Set<Artifact> unusedDeclared = analysis.getUnusedDeclaredArtifacts();
216
217 if ( ignoreNonCompile )
218 {
219 Set<Artifact> filteredUnusedDeclared = new HashSet<Artifact>( unusedDeclared );
220 Iterator<Artifact> iter = filteredUnusedDeclared.iterator();
221 while ( iter.hasNext() )
222 {
223 Artifact artifact = iter.next();
224 if ( !artifact.getScope().equals( Artifact.SCOPE_COMPILE ) )
225 {
226 iter.remove();
227 }
228 }
229 unusedDeclared = filteredUnusedDeclared;
230 }
231
232 if ( ( !verbose || usedDeclared.isEmpty() ) && usedUndeclared.isEmpty() && unusedDeclared.isEmpty() )
233 {
234 getLog().info( "No dependency problems found" );
235 return false;
236 }
237
238 if ( verbose && !usedDeclared.isEmpty() )
239 {
240 getLog().info( "Used declared dependencies found:" );
241
242 logArtifacts( analysis.getUsedDeclaredArtifacts(), false );
243 }
244
245 if ( !usedUndeclared.isEmpty() )
246 {
247 getLog().warn( "Used undeclared dependencies found:" );
248
249 logArtifacts( usedUndeclared, true );
250 }
251
252 if ( !unusedDeclared.isEmpty() )
253 {
254 getLog().warn( "Unused declared dependencies found:" );
255
256 logArtifacts( unusedDeclared, true );
257 }
258
259 if ( outputXML )
260 {
261 writeDependencyXML( usedUndeclared );
262 }
263
264 if ( scriptableOutput )
265 {
266 writeScriptableOutput( usedUndeclared );
267 }
268
269 return !usedUndeclared.isEmpty() || !unusedDeclared.isEmpty();
270 }
271
272 private void logArtifacts( Set<Artifact> artifacts, boolean warn )
273 {
274 if ( artifacts.isEmpty() )
275 {
276 getLog().info( " None" );
277 }
278 else
279 {
280 for ( Artifact artifact : artifacts )
281 {
282
283 artifact.isSnapshot();
284
285 if ( warn )
286 {
287 getLog().warn( " " + artifact );
288 }
289 else
290 {
291 getLog().info( " " + artifact );
292 }
293
294 }
295 }
296 }
297
298 private void writeDependencyXML( Set<Artifact> artifacts )
299 {
300 if ( !artifacts.isEmpty() )
301 {
302 getLog().info( "Add the following to your pom to correct the missing dependencies: " );
303
304 StringWriter out = new StringWriter();
305 PrettyPrintXMLWriter writer = new PrettyPrintXMLWriter( out );
306
307 for ( Artifact artifact : artifacts )
308 {
309
310 artifact.isSnapshot();
311
312 writer.startElement( "dependency" );
313 writer.startElement( "groupId" );
314 writer.writeText( artifact.getGroupId() );
315 writer.endElement();
316 writer.startElement( "artifactId" );
317 writer.writeText( artifact.getArtifactId() );
318 writer.endElement();
319 writer.startElement( "version" );
320 writer.writeText( artifact.getBaseVersion() );
321 if ( !StringUtils.isBlank( artifact.getClassifier() ) )
322 {
323 writer.startElement( "classifier" );
324 writer.writeText( artifact.getClassifier() );
325 writer.endElement();
326 }
327 writer.endElement();
328
329 if ( !Artifact.SCOPE_COMPILE.equals( artifact.getScope() ) )
330 {
331 writer.startElement( "scope" );
332 writer.writeText( artifact.getScope() );
333 writer.endElement();
334 }
335 writer.endElement();
336 }
337
338 getLog().info( "\n" + out.getBuffer() );
339 }
340 }
341
342 private void writeScriptableOutput( Set<Artifact> artifacts )
343 {
344 if ( !artifacts.isEmpty() )
345 {
346 getLog().info( "Missing dependencies: " );
347 String pomFile = baseDir.getAbsolutePath() + File.separatorChar + "pom.xml";
348 StringBuffer buf = new StringBuffer();
349
350 for ( Artifact artifact : artifacts )
351 {
352
353 artifact.isSnapshot();
354
355 buf.append( scriptableFlag + ":" + pomFile + ":" + artifact.getDependencyConflictId() + ":"
356 + artifact.getClassifier() + ":" + artifact.getBaseVersion() + ":"
357 + artifact.getScope() + "\n" );
358 }
359 getLog().info( "\n" + buf );
360 }
361 }
362 }