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.IOException;
24 import java.io.StringWriter;
25 import java.io.Writer;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.List;
29
30 import org.apache.maven.artifact.factory.ArtifactFactory;
31 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
32 import org.apache.maven.artifact.repository.ArtifactRepository;
33 import org.apache.maven.artifact.resolver.ArtifactCollector;
34 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
35 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
36 import org.apache.maven.artifact.versioning.ArtifactVersion;
37 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
38 import org.apache.maven.artifact.versioning.Restriction;
39 import org.apache.maven.artifact.versioning.VersionRange;
40 import org.apache.maven.execution.RuntimeInformation;
41 import org.apache.maven.plugin.AbstractMojo;
42 import org.apache.maven.plugin.MojoExecutionException;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.apache.maven.plugin.dependency.utils.DependencyUtil;
45 import org.apache.maven.plugin.dependency.treeSerializers.GraphmlDependencyNodeVisitor;
46 import org.apache.maven.plugin.dependency.treeSerializers.TGFDependencyNodeVisitor;
47 import org.apache.maven.plugin.dependency.treeSerializers.DOTDependencyNodeVisitor;
48 import org.apache.maven.project.MavenProject;
49 import org.apache.maven.shared.artifact.filter.StrictPatternExcludesArtifactFilter;
50 import org.apache.maven.shared.artifact.filter.StrictPatternIncludesArtifactFilter;
51 import org.apache.maven.shared.dependency.tree.DependencyNode;
52 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
53 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
54 import org.apache.maven.shared.dependency.tree.filter.AncestorOrSelfDependencyNodeFilter;
55 import org.apache.maven.shared.dependency.tree.filter.AndDependencyNodeFilter;
56 import org.apache.maven.shared.dependency.tree.filter.ArtifactDependencyNodeFilter;
57 import org.apache.maven.shared.dependency.tree.filter.DependencyNodeFilter;
58 import org.apache.maven.shared.dependency.tree.filter.StateDependencyNodeFilter;
59 import org.apache.maven.shared.dependency.tree.traversal.BuildingDependencyNodeVisitor;
60 import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor;
61 import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor;
62 import org.apache.maven.shared.dependency.tree.traversal.FilteringDependencyNodeVisitor;
63 import org.apache.maven.shared.dependency.tree.traversal.SerializingDependencyNodeVisitor;
64 import org.apache.maven.shared.dependency.tree.traversal.SerializingDependencyNodeVisitor.TreeTokens;
65
66
67
68
69
70
71
72
73
74
75 public class TreeMojo extends AbstractMojo
76 {
77
78
79
80
81
82
83
84
85
86 private MavenProject project;
87
88
89
90
91
92
93
94
95 private ArtifactRepository localRepository;
96
97
98
99
100
101
102
103
104 private ArtifactFactory artifactFactory;
105
106
107
108
109
110
111
112
113 private ArtifactMetadataSource artifactMetadataSource;
114
115
116
117
118
119
120
121
122 private ArtifactCollector artifactCollector;
123
124
125
126
127
128
129
130
131 private DependencyTreeBuilder dependencyTreeBuilder;
132
133
134
135
136
137
138
139 private File output;
140
141
142
143
144
145
146
147 private File outputFile;
148
149
150
151
152
153
154
155
156
157
158
159 private String outputType;
160
161
162
163
164
165
166
167
168
169
170 private String scope;
171
172
173
174
175
176
177
178
179 private boolean verbose;
180
181
182
183
184
185
186
187
188
189
190 private String tokens;
191
192
193
194
195
196
197
198
199
200
201 private String includes;
202
203
204
205
206
207
208
209
210
211
212
213 private String excludes;
214
215
216
217
218
219
220 private RuntimeInformation rti;
221
222
223
224
225 private DependencyNode rootNode;
226
227
228
229
230
231
232
233 private boolean appendOutput;
234
235
236
237
238
239
240 public void execute()
241 throws MojoExecutionException, MojoFailureException
242 {
243
244 ArtifactVersion detectedMavenVersion = rti.getApplicationVersion();
245 VersionRange vr;
246 try
247 {
248 vr = VersionRange.createFromVersionSpec( "[2.0.8,)" );
249 if ( !containsVersion( vr, detectedMavenVersion ) )
250 {
251 getLog().warn(
252 "The tree mojo requires at least Maven 2.0.8 to function properly. You may get erroneous results on earlier versions" );
253 }
254 }
255 catch ( InvalidVersionSpecificationException e )
256 {
257 throw new MojoExecutionException( e.getLocalizedMessage(), e );
258 }
259
260
261 if ( output != null )
262 {
263 getLog().warn( "The parameter output is deprecated. Use outputFile instead." );
264 this.outputFile = output;
265 }
266
267 ArtifactFilter artifactFilter = createResolvingArtifactFilter();
268
269 try
270 {
271
272
273 rootNode =
274 dependencyTreeBuilder.buildDependencyTree( project, localRepository, artifactFactory,
275 artifactMetadataSource, artifactFilter, artifactCollector );
276
277 String dependencyTreeString = serializeDependencyTree( rootNode );
278
279 if ( outputFile != null )
280 {
281 DependencyUtil.write( dependencyTreeString, outputFile, this.appendOutput ,getLog() );
282
283 getLog().info( "Wrote dependency tree to: " + outputFile );
284 }
285 else
286 {
287 DependencyUtil.log( dependencyTreeString, getLog() );
288 }
289 }
290 catch ( DependencyTreeBuilderException exception )
291 {
292 throw new MojoExecutionException( "Cannot build project dependency tree", exception );
293 }
294 catch ( IOException exception )
295 {
296 throw new MojoExecutionException( "Cannot serialise project dependency tree", exception );
297 }
298 }
299
300
301
302
303
304
305
306
307 public MavenProject getProject()
308 {
309 return project;
310 }
311
312
313
314
315
316
317 public DependencyNode getDependencyTree()
318 {
319 return rootNode;
320 }
321
322
323
324
325
326
327
328
329 private ArtifactFilter createResolvingArtifactFilter()
330 {
331 ArtifactFilter filter;
332
333
334 if ( scope != null )
335 {
336 getLog().debug( "+ Resolving dependency tree for scope '" + scope + "'" );
337
338 filter = new ScopeArtifactFilter( scope );
339 }
340 else
341 {
342 filter = null;
343 }
344
345 return filter;
346 }
347
348
349
350
351
352
353
354
355 private String serializeDependencyTree( DependencyNode rootNode )
356 {
357 StringWriter writer = new StringWriter();
358
359 DependencyNodeVisitor visitor = getSerializingDependencyNodeVisitor( writer );
360
361
362 visitor = new BuildingDependencyNodeVisitor( visitor );
363
364 DependencyNodeFilter filter = createDependencyNodeFilter();
365
366 if ( filter != null )
367 {
368 CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
369 DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor( collectingVisitor, filter );
370 rootNode.accept( firstPassVisitor );
371
372 DependencyNodeFilter secondPassFilter = new AncestorOrSelfDependencyNodeFilter( collectingVisitor.getNodes() );
373 visitor = new FilteringDependencyNodeVisitor( visitor, secondPassFilter );
374 }
375
376 rootNode.accept( visitor );
377
378 return writer.toString();
379 }
380
381 public DependencyNodeVisitor getSerializingDependencyNodeVisitor( Writer writer )
382 {
383 if ( "graphml".equals( outputType ) )
384 {
385 return new GraphmlDependencyNodeVisitor( writer );
386 }
387 else if ( "tgf".equals( outputType ) )
388 {
389 return new TGFDependencyNodeVisitor( writer );
390 }
391 else if ( "dot".equals( outputType ) )
392 {
393 return new DOTDependencyNodeVisitor( writer ) ;
394 }
395 else
396 {
397 return new SerializingDependencyNodeVisitor( writer, toTreeTokens( tokens ) );
398 }
399 }
400
401
402
403
404
405
406
407
408 private TreeTokens toTreeTokens( String tokens )
409 {
410 TreeTokens treeTokens;
411
412 if ( "whitespace".equals( tokens ) )
413 {
414 getLog().debug( "+ Using whitespace tree tokens" );
415
416 treeTokens = SerializingDependencyNodeVisitor.WHITESPACE_TOKENS;
417 }
418 else if ( "extended".equals( tokens ) )
419 {
420 getLog().debug( "+ Using extended tree tokens" );
421
422 treeTokens = SerializingDependencyNodeVisitor.EXTENDED_TOKENS;
423 }
424 else
425 {
426 treeTokens = SerializingDependencyNodeVisitor.STANDARD_TOKENS;
427 }
428
429 return treeTokens;
430 }
431
432
433
434
435
436
437 private DependencyNodeFilter createDependencyNodeFilter()
438 {
439 List<DependencyNodeFilter> filters = new ArrayList<DependencyNodeFilter>();
440
441
442 if ( !verbose )
443 {
444 getLog().debug( "+ Filtering omitted nodes from dependency tree" );
445
446 filters.add( StateDependencyNodeFilter.INCLUDED );
447 }
448
449
450 if ( includes != null )
451 {
452 List<String> patterns = Arrays.asList( includes.split( "," ) );
453
454 getLog().debug( "+ Filtering dependency tree by artifact include patterns: " + patterns );
455
456 ArtifactFilter artifactFilter = new StrictPatternIncludesArtifactFilter( patterns );
457 filters.add( new ArtifactDependencyNodeFilter( artifactFilter ) );
458 }
459
460
461 if ( excludes != null )
462 {
463 List<String> patterns = Arrays.asList( excludes.split( "," ) );
464
465 getLog().debug( "+ Filtering dependency tree by artifact exclude patterns: " + patterns );
466
467 ArtifactFilter artifactFilter = new StrictPatternExcludesArtifactFilter( patterns );
468 filters.add( new ArtifactDependencyNodeFilter( artifactFilter ) );
469 }
470
471 return filters.isEmpty() ? null : new AndDependencyNodeFilter( filters );
472 }
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 public static boolean containsVersion( VersionRange allowedRange, ArtifactVersion theVersion )
489 {
490 ArtifactVersion recommendedVersion = allowedRange.getRecommendedVersion();
491 if ( recommendedVersion == null )
492 {
493 List<Restriction> restrictions = allowedRange.getRestrictions();
494 for ( Restriction restriction : restrictions )
495 {
496 if ( restriction.containsVersion( theVersion ) )
497 {
498 return true;
499 }
500 }
501 }
502
503
504 return recommendedVersion.compareTo( theVersion ) <= 0;
505 }
506
507 }