1 package org.apache.maven.plugins.dependency.analyze;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.Reader;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.maven.model.Dependency;
32 import org.apache.maven.model.Model;
33 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.project.MavenProject;
40 import org.codehaus.plexus.util.IOUtil;
41 import org.codehaus.plexus.util.ReaderFactory;
42
43
44
45
46
47
48
49 @Mojo( name = "analyze-duplicate", aggregator = false, threadSafe = true )
50 public class AnalyzeDuplicateMojo
51 extends AbstractMojo
52 {
53 public static final String MESSAGE_DUPLICATE_DEP_IN_DEPENDENCIES =
54 "List of duplicate dependencies defined in <dependencies/> in your pom.xml:\n";
55
56 public static final String MESSAGE_DUPLICATE_DEP_IN_DEPMGMT =
57 "List of duplicate dependencies defined in <dependencyManagement/> in your pom.xml:\n";
58
59
60
61
62
63
64 @Parameter( property = "mdep.analyze.skip", defaultValue = "false" )
65 private boolean skip;
66
67
68
69
70 @Parameter( defaultValue = "${project}", readonly = true, required = true )
71 private MavenProject project;
72
73
74
75
76 @Override
77 public void execute()
78 throws MojoExecutionException, MojoFailureException
79 {
80 if ( skip )
81 {
82 getLog().info( "Skipping plugin execution" );
83 return;
84 }
85
86 MavenXpp3Reader pomReader = new MavenXpp3Reader();
87 Model model = null;
88 Reader reader = null;
89 try
90 {
91 reader = ReaderFactory.newXmlReader( project.getFile() );
92 model = pomReader.read( reader );
93 reader.close();
94 reader = null;
95 }
96 catch ( Exception e )
97 {
98 throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
99 }
100 finally
101 {
102 IOUtil.close( reader );
103 }
104
105 Set<String> duplicateDependencies = Collections.emptySet();
106 if ( model.getDependencies() != null )
107 {
108 duplicateDependencies = findDuplicateDependencies( model.getDependencies() );
109 }
110
111 Set<String> duplicateDependenciesManagement = Collections.emptySet();
112 if ( model.getDependencyManagement() != null && model.getDependencyManagement().getDependencies() != null )
113 {
114 duplicateDependenciesManagement =
115 findDuplicateDependencies( model.getDependencyManagement().getDependencies() );
116 }
117
118 if ( getLog().isInfoEnabled() )
119 {
120 StringBuilder sb = new StringBuilder();
121
122 createMessage( duplicateDependencies, sb, MESSAGE_DUPLICATE_DEP_IN_DEPENDENCIES );
123 createMessage( duplicateDependenciesManagement, sb, MESSAGE_DUPLICATE_DEP_IN_DEPMGMT );
124
125 if ( sb.length() > 0 )
126 {
127 getLog().info( sb.toString() );
128 }
129 else
130 {
131 getLog().info( "No duplicate dependencies found in <dependencies/> or in <dependencyManagement/>" );
132 }
133 }
134 }
135
136 private void createMessage( Set<String> duplicateDependencies, StringBuilder sb,
137 String messageDuplicateDepInDependencies )
138 {
139 if ( !duplicateDependencies.isEmpty() )
140 {
141 if ( sb.length() > 0 )
142 {
143 sb.append( "\n" );
144 }
145 sb.append( messageDuplicateDepInDependencies );
146 for ( Iterator<String> it = duplicateDependencies.iterator(); it.hasNext(); )
147 {
148 String dup = it.next();
149
150 sb.append( "\to " ).append( dup );
151 if ( it.hasNext() )
152 {
153 sb.append( "\n" );
154 }
155 }
156 }
157 }
158
159 private Set<String> findDuplicateDependencies( List<Dependency> modelDependencies )
160 {
161 List<String> modelDependencies2 = new ArrayList<>();
162 for ( Dependency dep : modelDependencies )
163 {
164 modelDependencies2.add( dep.getManagementKey() );
165 }
166
167
168 return new LinkedHashSet<String>(
169 CollectionUtils.disjunction( modelDependencies2, new LinkedHashSet<>( modelDependencies2 ) ) );
170
171 }
172 }