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.Set;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.plugin.AbstractMojo;
29 import org.apache.maven.plugin.MojoExecutionException;
30 import org.apache.maven.plugin.MojoFailureException;
31 import org.apache.maven.plugins.annotations.Component;
32 import org.apache.maven.plugins.annotations.Parameter;
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 @Component
68 private MavenProject project;
69
70
71
72
73
74
75
76
77
78
79
80 @Parameter( property = "analyzer", defaultValue = "default" )
81 private String analyzer;
82
83
84
85
86 @Parameter( property = "failOnWarning", defaultValue = "false" )
87 private boolean failOnWarning;
88
89
90
91
92 @Parameter( property = "verbose", defaultValue = "false" )
93 private boolean verbose;
94
95
96
97
98 @Parameter( property = "ignoreNonCompile", defaultValue = "false" )
99 private boolean ignoreNonCompile;
100
101
102
103
104
105
106 @Parameter( property = "outputXML", defaultValue = "false" )
107 private boolean outputXML;
108
109
110
111
112
113
114 @Parameter( property = "scriptableOutput", defaultValue = "false" )
115 private boolean scriptableOutput;
116
117
118
119
120
121
122 @Parameter( property = "scriptableFlag", defaultValue = "$$$%%%" )
123 private String scriptableFlag;
124
125
126
127
128
129
130 @Parameter( defaultValue = "${basedir}", readonly = true )
131 private File baseDir;
132
133
134
135
136
137
138 @Parameter( defaultValue = "${project.build.directory}", readonly = true )
139 private File outputDirectory;
140
141
142
143
144
145
146
147 @Parameter
148 private String[] usedDependencies;
149
150
151
152
153
154
155 @Parameter( property = "mdep.analyze.skip", defaultValue = "false" )
156 private boolean skip;
157
158
159
160
161
162
163 public void execute()
164 throws MojoExecutionException, MojoFailureException
165 {
166 if ( isSkip() )
167 {
168 getLog().info( "Skipping plugin execution" );
169 return;
170 }
171
172 if ( "pom".equals( project.getPackaging() ) )
173 {
174 getLog().info( "Skipping pom project" );
175 return;
176 }
177
178 if ( outputDirectory == null || !outputDirectory.exists() )
179 {
180 getLog().info( "Skipping project with no build directory" );
181 return;
182 }
183
184 boolean warning = checkDependencies();
185
186 if ( warning && failOnWarning )
187 {
188 throw new MojoExecutionException( "Dependency problems found" );
189 }
190 }
191
192 protected ProjectDependencyAnalyzer createProjectDependencyAnalyzer()
193 throws MojoExecutionException
194 {
195
196 final String role = ProjectDependencyAnalyzer.ROLE;
197 final String roleHint = analyzer;
198
199 try
200 {
201 final PlexusContainer container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
202
203 return (ProjectDependencyAnalyzer) container.lookup( role, roleHint );
204 }
205 catch ( Exception exception )
206 {
207 throw new MojoExecutionException(
208 "Failed to instantiate ProjectDependencyAnalyser with role " + role + " / role-hint " + roleHint,
209 exception );
210 }
211 }
212
213 public void contextualize( Context context )
214 throws ContextException
215 {
216 this.context = context;
217 }
218
219 public boolean isSkip()
220 {
221 return skip;
222 }
223
224 public void setSkip( boolean skip )
225 {
226 this.skip = skip;
227 }
228
229
230
231 private boolean checkDependencies()
232 throws MojoExecutionException
233 {
234 ProjectDependencyAnalysis analysis;
235 try
236 {
237 analysis = createProjectDependencyAnalyzer().analyze( project );
238
239 if ( usedDependencies != null )
240 {
241 analysis = analysis.forceDeclaredDependenciesUsage( usedDependencies );
242 }
243 }
244 catch ( ProjectDependencyAnalyzerException exception )
245 {
246 throw new MojoExecutionException( "Cannot analyze dependencies", exception );
247 }
248
249 if ( ignoreNonCompile )
250 {
251 analysis = analysis.ignoreNonCompile();
252 }
253
254 Set<Artifact> usedDeclared = analysis.getUsedDeclaredArtifacts();
255 Set<Artifact> usedUndeclared = analysis.getUsedUndeclaredArtifacts();
256 Set<Artifact> unusedDeclared = analysis.getUnusedDeclaredArtifacts();
257
258 if ( ( !verbose || usedDeclared.isEmpty() ) && usedUndeclared.isEmpty() && unusedDeclared.isEmpty() )
259 {
260 getLog().info( "No dependency problems found" );
261 return false;
262 }
263
264 if ( verbose && !usedDeclared.isEmpty() )
265 {
266 getLog().info( "Used declared dependencies found:" );
267
268 logArtifacts( analysis.getUsedDeclaredArtifacts(), false );
269 }
270
271 if ( !usedUndeclared.isEmpty() )
272 {
273 getLog().warn( "Used undeclared dependencies found:" );
274
275 logArtifacts( usedUndeclared, true );
276 }
277
278 if ( !unusedDeclared.isEmpty() )
279 {
280 getLog().warn( "Unused declared dependencies found:" );
281
282 logArtifacts( unusedDeclared, true );
283 }
284
285 if ( outputXML )
286 {
287 writeDependencyXML( usedUndeclared );
288 }
289
290 if ( scriptableOutput )
291 {
292 writeScriptableOutput( usedUndeclared );
293 }
294
295 return !usedUndeclared.isEmpty() || !unusedDeclared.isEmpty();
296 }
297
298 private void logArtifacts( Set<Artifact> artifacts, boolean warn )
299 {
300 if ( artifacts.isEmpty() )
301 {
302 getLog().info( " None" );
303 }
304 else
305 {
306 for ( Artifact artifact : artifacts )
307 {
308
309 artifact.isSnapshot();
310
311 if ( warn )
312 {
313 getLog().warn( " " + artifact );
314 }
315 else
316 {
317 getLog().info( " " + artifact );
318 }
319
320 }
321 }
322 }
323
324 private void writeDependencyXML( Set<Artifact> artifacts )
325 {
326 if ( !artifacts.isEmpty() )
327 {
328 getLog().info( "Add the following to your pom to correct the missing dependencies: " );
329
330 StringWriter out = new StringWriter();
331 PrettyPrintXMLWriter writer = new PrettyPrintXMLWriter( out );
332
333 for ( Artifact artifact : artifacts )
334 {
335
336 artifact.isSnapshot();
337
338 writer.startElement( "dependency" );
339 writer.startElement( "groupId" );
340 writer.writeText( artifact.getGroupId() );
341 writer.endElement();
342 writer.startElement( "artifactId" );
343 writer.writeText( artifact.getArtifactId() );
344 writer.endElement();
345 writer.startElement( "version" );
346 writer.writeText( artifact.getBaseVersion() );
347 if ( !StringUtils.isBlank( artifact.getClassifier() ) )
348 {
349 writer.startElement( "classifier" );
350 writer.writeText( artifact.getClassifier() );
351 writer.endElement();
352 }
353 writer.endElement();
354
355 if ( !Artifact.SCOPE_COMPILE.equals( artifact.getScope() ) )
356 {
357 writer.startElement( "scope" );
358 writer.writeText( artifact.getScope() );
359 writer.endElement();
360 }
361 writer.endElement();
362 }
363
364 getLog().info( "\n" + out.getBuffer() );
365 }
366 }
367
368 private void writeScriptableOutput( Set<Artifact> artifacts )
369 {
370 if ( !artifacts.isEmpty() )
371 {
372 getLog().info( "Missing dependencies: " );
373 String pomFile = baseDir.getAbsolutePath() + File.separatorChar + "pom.xml";
374 StringBuilder buf = new StringBuilder();
375
376 for ( Artifact artifact : artifacts )
377 {
378
379 artifact.isSnapshot();
380
381 buf.append( scriptableFlag + ":" + pomFile + ":" + artifact.getDependencyConflictId() + ":"
382 + artifact.getClassifier() + ":" + artifact.getBaseVersion() + ":" + artifact.getScope()
383 + "\n" );
384 }
385 getLog().info( "\n" + buf );
386 }
387 }
388 }