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