View Javadoc
1   package org.apache.maven.report.projectinfo;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.List;
26  import java.util.Locale;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.versioning.VersionRange;
30  import org.apache.maven.doxia.sink.Sink;
31  import org.apache.maven.model.Plugin;
32  import org.apache.maven.model.ReportPlugin;
33  import org.apache.maven.plugin.logging.Log;
34  import org.apache.maven.plugins.annotations.Mojo;
35  import org.apache.maven.plugins.annotations.ResolutionScope;
36  import org.apache.maven.project.DefaultProjectBuildingRequest;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuilder;
39  import org.apache.maven.project.ProjectBuildingException;
40  import org.apache.maven.project.ProjectBuildingRequest;
41  import org.apache.maven.repository.RepositorySystem;
42  import org.codehaus.plexus.i18n.I18N;
43  import org.codehaus.plexus.util.StringUtils;
44  
45  /**
46   * Generates the Project Plugins report.
47   *
48   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
49   * @since 2.1
50   */
51  @Mojo( name = "plugins", requiresDependencyResolution = ResolutionScope.TEST )
52  public class PluginsReport
53      extends AbstractProjectInfoReport
54  {
55      // ----------------------------------------------------------------------
56      // Public methods
57      // ----------------------------------------------------------------------
58  
59      @Override
60      public boolean canGenerateReport()
61      {
62          boolean result = super.canGenerateReport();
63          if ( result && skipEmptyReport )
64          {
65              result = !isEmpty( getProject().getBuildPlugins() ) || !isEmpty( getProject().getReportPlugins() );
66          }
67  
68          return result;
69      }
70  
71      @Override
72      public void executeReport( Locale locale )
73      {
74          PluginsRenderer r =
75              new PluginsRenderer( getLog(), getSink(), locale, getI18N( locale ), project.getBuildPlugins(),
76                                   project.getReportPlugins(), project, projectBuilder, repositorySystem,
77                                   getSession().getProjectBuildingRequest() );
78          r.render();
79      }
80  
81      /** {@inheritDoc} */
82      public String getOutputName()
83      {
84          return "plugins";
85      }
86  
87      @Override
88      protected String getI18Nsection()
89      {
90          return "plugins";
91      }
92  
93      // ----------------------------------------------------------------------
94      // Private
95      // ----------------------------------------------------------------------
96  
97      /**
98       * Internal renderer class
99       */
100     protected static class PluginsRenderer
101         extends AbstractProjectInfoRenderer
102     {
103         private final Log log;
104 
105         private final List<Plugin> plugins;
106 
107         private final List<ReportPlugin> reports;
108 
109         private final MavenProject project;
110 
111         private final ProjectBuilder projectBuilder;
112 
113         private final RepositorySystem repositorySystem;
114 
115         private final ProjectBuildingRequest buildingRequest;
116 
117         /**
118          * @param log {@link #log}
119          * @param sink {@link Sink}
120          * @param locale {@link Locale}
121          * @param i18n {@link I18N}
122          * @param plugins {@link Artifact}
123          * @param reports {@link Artifact}
124          * @param project {@link MavenProject}
125          * @param projectBuilder {@link ProjectBuilder}
126          * @param repositorySystem {@link RepositorySystem}
127          * @param buildingRequest {@link ProjectBuildingRequest}
128          *
129          */
130         public PluginsRenderer( Log log, Sink sink, Locale locale, I18N i18n, List<Plugin> plugins,
131                                 List<ReportPlugin> reports, MavenProject project,
132                                 ProjectBuilder projectBuilder, RepositorySystem repositorySystem,
133                                 ProjectBuildingRequest buildingRequest )
134         {
135             super( sink, i18n, locale );
136 
137             this.log = log;
138 
139             this.plugins = new ArrayList<>( plugins );
140 
141             this.reports = new ArrayList<>( reports );
142 
143             this.project = project;
144 
145             this.projectBuilder = projectBuilder;
146 
147             this.repositorySystem = repositorySystem;
148 
149             this.buildingRequest = buildingRequest;
150         }
151 
152         @Override
153         protected String getI18Nsection()
154         {
155             return "plugins";
156         }
157 
158         @Override
159         public void renderBody()
160         {
161             // === Section: Project Plugins.
162             renderSectionPlugins( true );
163 
164             // === Section: Project Reports.
165             renderSectionPlugins( false );
166         }
167 
168         /**
169          * @param isPlugins <code>true</code> to use <code>plugins</code> variable, <code>false</code> to use
170          * <code>reports</code> variable.
171          */
172         private void renderSectionPlugins( boolean isPlugins )
173         {
174             List<GAV> list = isPlugins ? GAV.pluginsToGAV( plugins ) : GAV.reportPluginsToGAV( reports, project );
175 
176             String[] tableHeader = getPluginTableHeader();
177 
178             startSection( getI18nString( isPlugins ? "build.title" : "report.title" ) );
179 
180             if ( list.isEmpty() )
181             {
182 
183                 paragraph( getI18nString( isPlugins ? "nolist" : "report.nolist" ) ) ;
184                 endSection();
185                 return;
186             }
187 
188             Collections.sort( list, getPluginComparator() );
189 
190             startTable();
191             tableHeader( tableHeader );
192 
193             ProjectBuildingRequest buildRequest = new DefaultProjectBuildingRequest( buildingRequest );
194             buildRequest.setRemoteRepositories( project.getPluginArtifactRepositories() );
195 
196             for ( GAV plugin : list )
197             {
198                 VersionRange versionRange = VersionRange.createFromVersion( plugin.getVersion() );
199 
200 
201                 Artifact pluginArtifact =
202                                 repositorySystem.createProjectArtifact( plugin.getGroupId(), plugin.getArtifactId(),
203                                                           versionRange.toString() );
204                 try
205                 {
206                     MavenProject pluginProject = projectBuilder.build( pluginArtifact, buildRequest ).getProject();
207 
208                     tableRow( getPluginRow( pluginProject.getGroupId(), pluginProject.getArtifactId(), pluginProject
209                                             .getVersion(), pluginProject.getUrl() ) );
210                 }
211                 catch ( ProjectBuildingException e )
212                 {
213                     log.info( "Could not build project for " + plugin.getArtifactId(), e );
214                     tableRow( getPluginRow( plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(),
215                                             null ) );
216                 }
217             }
218             endTable();
219 
220             endSection();
221         }
222 
223         // ----------------------------------------------------------------------
224         // Private methods
225         // ----------------------------------------------------------------------
226 
227         private String[] getPluginTableHeader()
228         {
229             // reused key...
230             String groupId = getI18nString( "dependency-management", "column.groupId" );
231             String artifactId = getI18nString( "dependency-management", "column.artifactId" );
232             String version = getI18nString( "dependency-management", "column.version" );
233             return new String[] { groupId, artifactId, version };
234         }
235 
236         private String[] getPluginRow( String groupId, String artifactId, String version, String link )
237         {
238             artifactId = ProjectInfoReportUtils.getArtifactIdCell( artifactId, link );
239             return new String[] { groupId, artifactId, version };
240         }
241 
242         private static class GAV
243         {
244             private final String groupId;
245             private final String artifactId;
246             private final String version;
247 
248             private GAV( Plugin plugin )
249             {
250                 groupId = plugin.getGroupId();
251                 artifactId = plugin.getArtifactId();
252                 version = StringUtils.isEmpty( plugin.getVersion() ) ? Artifact.RELEASE_VERSION : plugin.getVersion();
253             }
254 
255             private GAV( ReportPlugin reportPlugin, MavenProject project )
256             {
257                 groupId = reportPlugin.getGroupId();
258                 artifactId = reportPlugin.getArtifactId();
259                 version = resolveReportPluginVersion( reportPlugin, project );
260             }
261 
262             public String getGroupId()
263             {
264                 return groupId;
265             }
266 
267             public String getArtifactId()
268             {
269                 return artifactId;
270             }
271 
272             public String getVersion()
273             {
274                 return version;
275             }
276 
277             public static List<GAV> pluginsToGAV( List<Plugin> plugins )
278             {
279                 List<GAV> result = new ArrayList<>( plugins.size() );
280                 for ( Plugin plugin : plugins )
281                 {
282                     result.add( new GAV( plugin ) );
283                 }
284                 return result;
285             }
286 
287             public static List<GAV> reportPluginsToGAV( List<ReportPlugin> reportPlugins, MavenProject project )
288             {
289                 List<GAV> result = new ArrayList<>( reportPlugins.size() );
290                 for ( ReportPlugin reportPlugin : reportPlugins )
291                 {
292                     result.add( new GAV( reportPlugin, project ) );
293                 }
294                 return result;
295             }
296         }
297 
298         private Comparator<GAV> getPluginComparator()
299         {
300             return new Comparator<GAV>()
301             {
302                 /** {@inheritDoc} */
303                 public int compare( GAV a1, GAV a2 )
304                 {
305                     int result = a1.groupId.compareTo( a2.groupId );
306                     if ( result == 0 )
307                     {
308                         result = a1.artifactId.compareTo( a2.artifactId );
309                     }
310                     return result;
311                 }
312             };
313         }
314 
315         /**
316          * Resolve report plugin version. Steps to find a plugin version stop after each step if a non <code>null</code>
317          * value has been found:
318          * <ol>
319          * <li>use the one defined in the reportPlugin configuration,</li>
320          * <li>search similar (same groupId and artifactId) mojo in the build/plugins section of the pom,</li>
321          * <li>search similar (same groupId and artifactId) mojo in the build/pluginManagement section of the pom,</li>
322          * <li>default value is RELEASE.</li>
323          * </ol>
324          *
325          * @param reportPlugin the report plugin to resolve the version
326          * @param project the current project
327          * @return the report plugin version
328          */
329         protected static String resolveReportPluginVersion( ReportPlugin reportPlugin, MavenProject project )
330         {
331             // look for version defined in the reportPlugin configuration
332             if ( reportPlugin.getVersion() != null )
333             {
334                 return reportPlugin.getVersion();
335             }
336 
337             // search in the build section
338             if ( project.getBuild() != null )
339             {
340                 Plugin plugin = find( reportPlugin, project.getBuild().getPlugins() );
341 
342                 if ( plugin != null && plugin.getVersion() != null )
343                 {
344                     return plugin.getVersion();
345                 }
346             }
347 
348             // search in pluginManagement section
349             if ( project.getBuild() != null && project.getBuild().getPluginManagement() != null )
350             {
351                 Plugin plugin = find( reportPlugin, project.getBuild().getPluginManagement().getPlugins() );
352 
353                 if ( plugin != null && plugin.getVersion() != null )
354                 {
355                     return plugin.getVersion();
356                 }
357             }
358 
359             // empty version
360             return Artifact.RELEASE_VERSION;
361         }
362 
363         /**
364          * Search similar (same groupId and artifactId) plugin as a given report plugin.
365          *
366          * @param reportPlugin the report plugin to search for a similar plugin
367          * @param plugins the candidate plugins
368          * @return the first similar plugin
369          */
370         private static Plugin find( ReportPlugin reportPlugin, List<Plugin> plugins )
371         {
372             if ( plugins == null )
373             {
374                 return null;
375             }
376             for ( Plugin plugin : plugins )
377             {
378                 if ( StringUtils.equals( plugin.getArtifactId(), reportPlugin.getArtifactId() )
379                     && StringUtils.equals( plugin.getGroupId(), reportPlugin.getGroupId() ) )
380                 {
381                     return plugin;
382                 }
383             }
384             return null;
385         }
386     }
387 }