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