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 org.apache.maven.artifact.resolver.filter.ArtifactFilter;
23 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
24 import org.apache.maven.artifact.versioning.ArtifactVersion;
25 import org.apache.maven.artifact.versioning.Restriction;
26 import org.apache.maven.artifact.versioning.VersionRange;
27 import org.apache.maven.plugin.AbstractMojo;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.plugin.MojoFailureException;
30 import org.apache.maven.plugin.dependency.treeSerializers.DOTDependencyNodeVisitor;
31 import org.apache.maven.plugin.dependency.treeSerializers.GraphmlDependencyNodeVisitor;
32 import org.apache.maven.plugin.dependency.treeSerializers.TGFDependencyNodeVisitor;
33 import org.apache.maven.plugin.dependency.utils.DependencyUtil;
34 import org.apache.maven.plugins.annotations.Component;
35 import org.apache.maven.plugins.annotations.Mojo;
36 import org.apache.maven.plugins.annotations.Parameter;
37 import org.apache.maven.plugins.annotations.ResolutionScope;
38 import org.apache.maven.project.MavenProject;
39 import org.apache.maven.shared.artifact.filter.StrictPatternExcludesArtifactFilter;
40 import org.apache.maven.shared.artifact.filter.StrictPatternIncludesArtifactFilter;
41 import org.apache.maven.shared.dependency.graph.DependencyNode;
42 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
43 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
44 import org.apache.maven.shared.dependency.graph.filter.AncestorOrSelfDependencyNodeFilter;
45 import org.apache.maven.shared.dependency.graph.filter.AndDependencyNodeFilter;
46 import org.apache.maven.shared.dependency.graph.filter.ArtifactDependencyNodeFilter;
47 import org.apache.maven.shared.dependency.graph.filter.DependencyNodeFilter;
48 import org.apache.maven.shared.dependency.graph.traversal.BuildingDependencyNodeVisitor;
49 import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
50 import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
51 import org.apache.maven.shared.dependency.graph.traversal.FilteringDependencyNodeVisitor;
52 import org.apache.maven.shared.dependency.graph.traversal.SerializingDependencyNodeVisitor;
53 import org.apache.maven.shared.dependency.graph.traversal.SerializingDependencyNodeVisitor.TreeTokens;
54
55 import java.io.File;
56 import java.io.IOException;
57 import java.io.StringWriter;
58 import java.io.Writer;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.List;
62
63
64
65
66
67
68
69
70 @Mojo( name = "tree", requiresDependencyResolution = ResolutionScope.TEST )
71 public class TreeMojo
72 extends AbstractMojo
73 {
74
75
76
77
78
79 @Component
80 private MavenProject project;
81
82
83
84
85 @Component( hint = "default" )
86 private DependencyGraphBuilder dependencyGraphBuilder;
87
88
89
90
91
92
93
94 @Parameter( property = "output" )
95 private File output;
96
97
98
99
100
101
102
103 @Parameter( property = "outputFile" )
104 private File outputFile;
105
106
107
108
109
110
111
112
113
114
115 @Parameter( property = "outputType", defaultValue = "text" )
116 private String outputType;
117
118
119
120
121
122
123
124
125 @Parameter( property = "scope" )
126 private String scope;
127
128
129
130
131
132
133
134 @Parameter( property = "verbose", defaultValue = "false" )
135 private boolean verbose;
136
137
138
139
140
141
142
143
144 @Parameter( property = "tokens", defaultValue = "standard" )
145 private String tokens;
146
147
148
149
150
151
152
153
154
155 private String includes;
156
157
158
159
160
161
162
163
164
165 @Parameter( property = "excludes" )
166 private String excludes;
167
168
169
170
171 private DependencyNode rootNode;
172
173
174
175
176
177
178 @Parameter( property = "appendOutput", defaultValue = "false" )
179 private boolean appendOutput;
180
181
182
183
184
185
186 public void execute()
187 throws MojoExecutionException, MojoFailureException
188 {
189
190 if ( output != null )
191 {
192 getLog().warn( "The parameter output is deprecated. Use outputFile instead." );
193 this.outputFile = output;
194 }
195
196 ArtifactFilter artifactFilter = createResolvingArtifactFilter();
197
198 try
199 {
200
201
202 rootNode = dependencyGraphBuilder.buildDependencyGraph( project, artifactFilter );
203
204 String dependencyTreeString = serializeDependencyTree( rootNode );
205
206 if ( outputFile != null )
207 {
208 DependencyUtil.write( dependencyTreeString, outputFile, this.appendOutput, getLog() );
209
210 getLog().info( "Wrote dependency tree to: " + outputFile );
211 }
212 else
213 {
214 DependencyUtil.log( dependencyTreeString, getLog() );
215 }
216 }
217 catch ( DependencyGraphBuilderException exception )
218 {
219 throw new MojoExecutionException( "Cannot build project dependency graph", exception );
220 }
221 catch ( IOException exception )
222 {
223 throw new MojoExecutionException( "Cannot serialise project dependency graph", exception );
224 }
225 }
226
227
228
229
230
231
232
233
234 public MavenProject getProject()
235 {
236 return project;
237 }
238
239
240
241
242
243
244 public DependencyNode getDependencyGraph()
245 {
246 return rootNode;
247 }
248
249
250
251
252
253
254
255
256 private ArtifactFilter createResolvingArtifactFilter()
257 {
258 ArtifactFilter filter;
259
260
261 if ( scope != null )
262 {
263 getLog().debug( "+ Resolving dependency tree for scope '" + scope + "'" );
264
265 filter = new ScopeArtifactFilter( scope );
266 }
267 else
268 {
269 filter = null;
270 }
271
272 return filter;
273 }
274
275
276
277
278
279
280
281 private String serializeDependencyTree( DependencyNode rootNode )
282 {
283 StringWriter writer = new StringWriter();
284
285 DependencyNodeVisitor visitor = getSerializingDependencyNodeVisitor( writer );
286
287
288 visitor = new BuildingDependencyNodeVisitor( visitor );
289
290 DependencyNodeFilter filter = createDependencyNodeFilter();
291
292 if ( filter != null )
293 {
294 CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
295 DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor( collectingVisitor, filter );
296 rootNode.accept( firstPassVisitor );
297
298 DependencyNodeFilter secondPassFilter =
299 new AncestorOrSelfDependencyNodeFilter( collectingVisitor.getNodes() );
300 visitor = new FilteringDependencyNodeVisitor( visitor, secondPassFilter );
301 }
302
303 rootNode.accept( visitor );
304
305 return writer.toString();
306 }
307
308 public DependencyNodeVisitor getSerializingDependencyNodeVisitor( Writer writer )
309 {
310 if ( "graphml".equals( outputType ) )
311 {
312 return new GraphmlDependencyNodeVisitor( writer );
313 }
314 else if ( "tgf".equals( outputType ) )
315 {
316 return new TGFDependencyNodeVisitor( writer );
317 }
318 else if ( "dot".equals( outputType ) )
319 {
320 return new DOTDependencyNodeVisitor( writer );
321 }
322 else
323 {
324 return new SerializingDependencyNodeVisitor( writer, toTreeTokens( tokens ) );
325 }
326 }
327
328
329
330
331
332
333
334 private TreeTokens toTreeTokens( String tokens )
335 {
336 TreeTokens treeTokens;
337
338 if ( "whitespace".equals( tokens ) )
339 {
340 getLog().debug( "+ Using whitespace tree tokens" );
341
342 treeTokens = SerializingDependencyNodeVisitor.WHITESPACE_TOKENS;
343 }
344 else if ( "extended".equals( tokens ) )
345 {
346 getLog().debug( "+ Using extended tree tokens" );
347
348 treeTokens = SerializingDependencyNodeVisitor.EXTENDED_TOKENS;
349 }
350 else
351 {
352 treeTokens = SerializingDependencyNodeVisitor.STANDARD_TOKENS;
353 }
354
355 return treeTokens;
356 }
357
358
359
360
361
362
363 private DependencyNodeFilter createDependencyNodeFilter()
364 {
365 List<DependencyNodeFilter> filters = new ArrayList<DependencyNodeFilter>();
366
367
368
369
370
371
372
373
374
375
376 if ( includes != null )
377 {
378 List<String> patterns = Arrays.asList( includes.split( "," ) );
379
380 getLog().debug( "+ Filtering dependency tree by artifact include patterns: " + patterns );
381
382 ArtifactFilter artifactFilter = new StrictPatternIncludesArtifactFilter( patterns );
383 filters.add( new ArtifactDependencyNodeFilter( artifactFilter ) );
384 }
385
386
387 if ( excludes != null )
388 {
389 List<String> patterns = Arrays.asList( excludes.split( "," ) );
390
391 getLog().debug( "+ Filtering dependency tree by artifact exclude patterns: " + patterns );
392
393 ArtifactFilter artifactFilter = new StrictPatternExcludesArtifactFilter( patterns );
394 filters.add( new ArtifactDependencyNodeFilter( artifactFilter ) );
395 }
396
397 return filters.isEmpty() ? null : new AndDependencyNodeFilter( filters );
398 }
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 public static boolean containsVersion( VersionRange allowedRange, ArtifactVersion theVersion )
414 {
415 ArtifactVersion recommendedVersion = allowedRange.getRecommendedVersion();
416 if ( recommendedVersion == null )
417 {
418 @SuppressWarnings( "unchecked" ) List<Restriction> restrictions = allowedRange.getRestrictions();
419 for ( Restriction restriction : restrictions )
420 {
421 if ( restriction.containsVersion( theVersion ) )
422 {
423 return true;
424 }
425 }
426 }
427
428
429 return recommendedVersion.compareTo( theVersion ) <= 0;
430 }
431
432 }