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