View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.report.projectinfo;
20  
21  import javax.inject.Inject;
22  
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.PluginManagement;
33  import org.apache.maven.plugin.logging.Log;
34  import org.apache.maven.plugins.annotations.Mojo;
35  import org.apache.maven.plugins.annotations.Parameter;
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.reporting.MavenReportException;
43  import org.apache.maven.repository.RepositorySystem;
44  import org.apache.maven.shared.artifact.filter.PatternExcludesArtifactFilter;
45  import org.codehaus.plexus.i18n.I18N;
46  import org.codehaus.plexus.util.StringUtils;
47  
48  /**
49   * Generates the Project Plugin Management report.
50   *
51   * @author Nick Stolwijk
52   * @since 2.1
53   */
54  @Mojo(name = "plugin-management", requiresDependencyResolution = ResolutionScope.TEST)
55  public class PluginManagementReport extends AbstractProjectInfoReport {
56  
57      /**
58       * Specify the excluded plugins. This can be a list of artifacts in the format
59       * groupId[:artifactId[:type[:version]]]. <br>
60       * Plugins matching any exclude will not be present in the report.
61       *
62       * @since 3.0.1
63       */
64      @Parameter
65      private List<String> pluginManagementExcludes = null;
66  
67      @Inject
68      public PluginManagementReport(RepositorySystem repositorySystem, I18N i18n, ProjectBuilder projectBuilder) {
69          super(repositorySystem, i18n, projectBuilder);
70      }
71  
72      // ----------------------------------------------------------------------
73      // Public methods
74      // ----------------------------------------------------------------------
75  
76      @Override
77      public void executeReport(Locale locale) {
78          PluginManagementRenderer r = new PluginManagementRenderer(
79                  getLog(),
80                  getSink(),
81                  locale,
82                  getI18N(locale),
83                  project.getPluginManagement().getPlugins(),
84                  project,
85                  projectBuilder,
86                  repositorySystem,
87                  getSession().getProjectBuildingRequest(),
88                  pluginManagementExcludes);
89          r.render();
90      }
91  
92      /** {@inheritDoc} */
93      public String getOutputName() {
94          return "plugin-management";
95      }
96  
97      @Override
98      protected String getI18Nsection() {
99          return "plugin-management";
100     }
101 
102     @Override
103     public boolean canGenerateReport() throws MavenReportException {
104         boolean result = super.canGenerateReport();
105         if (result && skipEmptyReport) {
106             result = getProject().getPluginManagement() != null
107                     && !isEmpty(project.getPluginManagement().getPlugins());
108         }
109 
110         return result;
111     }
112 
113     // ----------------------------------------------------------------------
114     // Private
115     // ----------------------------------------------------------------------
116 
117     /**
118      * Internal renderer class
119      *
120      * @author Nick Stolwijk
121      */
122     protected static class PluginManagementRenderer extends AbstractProjectInfoRenderer {
123 
124         private final Log log;
125 
126         private final List<Plugin> pluginManagement;
127 
128         private final MavenProject project;
129 
130         private final ProjectBuilder projectBuilder;
131 
132         private final RepositorySystem repositorySystem;
133 
134         private final ProjectBuildingRequest buildingRequest;
135 
136         private final PatternExcludesArtifactFilter patternExcludesArtifactFilter;
137 
138         /**
139          * @param log {@link #log}
140          * @param sink {@link Sink}
141          * @param locale {@link Locale}
142          * @param i18n {@link I18N}
143          * @param plugins {@link Plugin}
144          * @param project {@link MavenProject}
145          * @param projectBuilder {@link ProjectBuilder}
146          * @param repositorySystem {@link RepositorySystem}
147          * @param buildingRequest {@link ProjectBuildingRequest}
148          * @param excludes the list of plugins to be excluded from the report
149          */
150         public PluginManagementRenderer(
151                 Log log,
152                 Sink sink,
153                 Locale locale,
154                 I18N i18n,
155                 List<Plugin> plugins,
156                 MavenProject project,
157                 ProjectBuilder projectBuilder,
158                 RepositorySystem repositorySystem,
159                 ProjectBuildingRequest buildingRequest,
160                 List<String> excludes) {
161             super(sink, i18n, locale);
162 
163             this.log = log;
164 
165             this.pluginManagement = plugins;
166 
167             this.project = project;
168 
169             this.projectBuilder = projectBuilder;
170 
171             this.repositorySystem = repositorySystem;
172 
173             this.buildingRequest = buildingRequest;
174 
175             this.patternExcludesArtifactFilter = new PatternExcludesArtifactFilter(excludes);
176         }
177 
178         @Override
179         protected String getI18Nsection() {
180             return "plugin-management";
181         }
182 
183         @Override
184         protected void renderBody() {
185             PluginManagement projectPluginManagement = project.getPluginManagement();
186 
187             if (projectPluginManagement == null
188                     || projectPluginManagement.getPlugins() == null
189                     || projectPluginManagement.getPlugins().isEmpty()) {
190                 startSection(getTitle());
191 
192                 paragraph(getI18nString("nolist"));
193 
194                 endSection();
195 
196                 return;
197             }
198 
199             // === Section: Project PluginManagement.
200             renderSectionPluginManagement();
201         }
202 
203         private void renderSectionPluginManagement() {
204             String[] tableHeader = getPluginTableHeader();
205 
206             startSection(getTitle());
207 
208             // can't use straight artifact comparison because we want optional last
209             Collections.sort(pluginManagement, getPluginComparator());
210 
211             startTable();
212             tableHeader(tableHeader);
213 
214             ProjectBuildingRequest buildRequest = new DefaultProjectBuildingRequest(buildingRequest);
215             buildRequest.setRemoteRepositories(project.getPluginArtifactRepositories());
216             buildRequest.setProcessPlugins(false);
217 
218             for (Plugin plugin : pluginManagement) {
219                 VersionRange versionRange;
220                 if (StringUtils.isEmpty(plugin.getVersion())) {
221                     versionRange = VersionRange.createFromVersion(Artifact.RELEASE_VERSION);
222                 } else {
223                     versionRange = VersionRange.createFromVersion(plugin.getVersion());
224                 }
225 
226                 Artifact pluginArtifact = repositorySystem.createProjectArtifact(
227                         plugin.getGroupId(), plugin.getArtifactId(), versionRange.toString());
228 
229                 if (patternExcludesArtifactFilter.include(pluginArtifact)) {
230                     try {
231                         MavenProject pluginProject = projectBuilder
232                                 .build(pluginArtifact, buildRequest)
233                                 .getProject();
234 
235                         tableRow(getPluginRow(
236                                 pluginProject.getGroupId(), pluginProject.getArtifactId(),
237                                 pluginProject.getVersion(), pluginProject.getUrl()));
238                     } catch (ProjectBuildingException e) {
239                         log.info("Could not build project for " + plugin.getArtifactId(), e);
240                         tableRow(getPluginRow(plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(), null));
241                     }
242                 } else {
243                     log.debug("Excluding plugin " + pluginArtifact.getId() + " from report");
244                 }
245             }
246             endTable();
247 
248             endSection();
249         }
250 
251         // ----------------------------------------------------------------------
252         // Private methods
253         // ----------------------------------------------------------------------
254 
255         private String[] getPluginTableHeader() {
256             // reused key...
257             String groupId = getI18nString("dependency-management", "column.groupId");
258             String artifactId = getI18nString("dependency-management", "column.artifactId");
259             String version = getI18nString("dependency-management", "column.version");
260             return new String[] {groupId, artifactId, version};
261         }
262 
263         private String[] getPluginRow(String groupId, String artifactId, String version, String link) {
264             artifactId = ProjectInfoReportUtils.getArtifactIdCell(artifactId, link);
265             return new String[] {groupId, artifactId, version};
266         }
267 
268         private Comparator<Plugin> getPluginComparator() {
269             return new Comparator<Plugin>() {
270                 /** {@inheritDoc} */
271                 public int compare(Plugin a1, Plugin a2) {
272                     int result = a1.getGroupId().compareTo(a2.getGroupId());
273                     if (result == 0) {
274                         result = a1.getArtifactId().compareTo(a2.getArtifactId());
275                     }
276                     return result;
277                 }
278             };
279         }
280     }
281 }