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.plugins.dependency.resolvers;
20  
21  import javax.inject.Inject;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.List;
26  import java.util.Objects;
27  import java.util.Optional;
28  import java.util.Set;
29  import java.util.function.Predicate;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.model.Dependency;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugins.annotations.LifecyclePhase;
37  import org.apache.maven.plugins.annotations.Mojo;
38  import org.apache.maven.plugins.annotations.Parameter;
39  import org.apache.maven.plugins.dependency.AbstractDependencyMojo;
40  import org.apache.maven.plugins.dependency.utils.DependencyUtil;
41  import org.apache.maven.plugins.dependency.utils.ResolverUtil;
42  import org.apache.maven.project.MavenProject;
43  import org.eclipse.aether.artifact.Artifact;
44  import org.eclipse.aether.resolution.ArtifactResolutionException;
45  import org.eclipse.aether.resolution.DependencyResolutionException;
46  import org.sonatype.plexus.build.incremental.BuildContext;
47  
48  /**
49   * Goal that resolves all project plugins and reports and their dependencies.
50   *
51   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
52   * @since 2.0
53   */
54  @Mojo(name = "resolve-plugins", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true)
55  public class ResolvePluginsMojo extends AbstractDependencyMojo {
56  
57      /**
58       * If specified, this parameter causes the dependencies to be written to the path specified instead of
59       * the console.
60       *
61       * @since 2.0
62       */
63      @Parameter(property = "outputFile")
64      protected File outputFile;
65  
66      /**
67       * If we should exclude transitive dependencies.
68       * This means only the plugin artifacts itself will be resolved not plugin dependencies.
69       *
70       * @since 2.0
71       */
72      @Parameter(property = "excludeTransitive", defaultValue = "false")
73      protected boolean excludeTransitive;
74  
75      /**
76       * List of artifact IDs to exclude.
77       *
78       * @since 2.0
79       */
80      @Parameter(property = "excludeArtifactIds", defaultValue = "")
81      protected List<String> excludeArtifactIds;
82  
83      /**
84       * List of artifact IDs to include. Empty list indicates include everything (default).
85       *
86       * @since 2.0
87       */
88      @Parameter(property = "includeArtifactIds", defaultValue = "")
89      protected List<String> includeArtifactIds;
90  
91      /**
92       * List of group IDs to exclude.
93       *
94       * @since 2.0
95       */
96      @Parameter(property = "excludeGroupIds", defaultValue = "")
97      protected List<String> excludeGroupIds;
98  
99      /**
100      * List of group IDs to include. Empty list indicates include everything (default).
101      *
102      * @since 2.0
103      */
104     @Parameter(property = "includeGroupIds", defaultValue = "")
105     protected List<String> includeGroupIds;
106 
107     /**
108      * Whether to append outputs into the output file or overwrite it.
109      *
110      * @since 2.2
111      */
112     @Parameter(property = "appendOutput", defaultValue = "false")
113     protected boolean appendOutput;
114 
115     /**
116      * Don't resolve plugins that are in the current reactor.
117      *
118      * @since 2.7
119      */
120     @Parameter(property = "excludeReactor", defaultValue = "true")
121     protected boolean excludeReactor;
122 
123     /**
124      * The encoding of the output file.
125      *
126      * @since 3.2.0
127      */
128     @Parameter(property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}")
129     private String outputEncoding;
130 
131     /**
132      * Output absolute filename for resolved artifacts.
133      *
134      * @since 2.0
135      */
136     @Parameter(property = "outputAbsoluteArtifactFilename", defaultValue = "false")
137     private boolean outputAbsoluteArtifactFilename;
138 
139     private final ResolverUtil resolverUtil;
140 
141     @Inject
142     public ResolvePluginsMojo(
143             MavenSession session, BuildContext buildContext, MavenProject project, ResolverUtil resolverUtil) {
144         super(session, buildContext, project);
145         this.resolverUtil = resolverUtil;
146     }
147 
148     /**
149      * Main entry into mojo. Gets the list of dependencies and iterates through displaying the resolved version.
150      *
151      * @throws MojoExecutionException with a message if an error occurs
152      */
153     @Override
154     protected void doExecute() throws MojoExecutionException {
155         try {
156             // ideally this should either be DependencyCoordinates or DependencyNode
157             final Set<Plugin> plugins = getProjectPlugins();
158 
159             StringBuilder sb = new StringBuilder();
160             sb.append(System.lineSeparator());
161             sb.append("The following plugins have been resolved:");
162             sb.append(System.lineSeparator());
163             if (plugins.isEmpty()) {
164                 sb.append("   none");
165                 sb.append(System.lineSeparator());
166             } else {
167                 for (Plugin plugin : plugins) {
168                     Artifact pluginArtifact = resolverUtil.resolvePlugin(plugin);
169                     String artifactFilename = null;
170                     if (outputAbsoluteArtifactFilename) {
171                         // we want to print the absolute file name here
172                         artifactFilename = Optional.ofNullable(pluginArtifact.getFile())
173                                 .map(File::getAbsoluteFile)
174                                 .map(File::getPath)
175                                 .orElse(null);
176                     }
177 
178                     String id = pluginArtifact.toString();
179                     sb.append("   ")
180                             .append(id)
181                             .append(outputAbsoluteArtifactFilename ? ":" + artifactFilename : "")
182                             .append(System.lineSeparator());
183 
184                     if (!excludeTransitive) {
185                         for (Artifact artifact : resolverUtil.resolveDependencies(plugin, getDependencyFilter())) {
186                             artifactFilename = null;
187                             if (outputAbsoluteArtifactFilename) {
188                                 // we want to print the absolute file name here
189                                 artifactFilename = Optional.ofNullable(artifact.getFile())
190                                         .map(File::getAbsoluteFile)
191                                         .map(File::getPath)
192                                         .orElse(null);
193                             }
194 
195                             id = artifact.toString();
196                             sb.append("      ")
197                                     .append(id)
198                                     .append(outputAbsoluteArtifactFilename ? ":" + artifactFilename : "")
199                                     .append(System.lineSeparator());
200                         }
201                     }
202                 }
203                 sb.append(System.lineSeparator());
204 
205                 String output = sb.toString();
206                 if (outputFile == null) {
207                     DependencyUtil.log(output, getLog());
208                 } else {
209                     String encoding = Objects.toString(outputEncoding, "UTF-8");
210                     DependencyUtil.write(output, outputFile, appendOutput, encoding);
211                 }
212             }
213         } catch (IOException | ArtifactResolutionException | DependencyResolutionException e) {
214             throw new MojoExecutionException(e.getMessage(), e);
215         }
216     }
217 
218     private Predicate<Dependency> getDependencyFilter() {
219         if (excludeReactor) {
220             return new ExcludeReactorProjectsDependencyFilter(session.getProjects());
221         } else {
222             return __ -> true;
223         }
224     }
225 
226     /**
227      * This return plugin list of the project after applying the include/exclude filters.
228      *
229      * @return set of project plugin
230      */
231     private Set<Plugin> getProjectPlugins() {
232 
233         Predicate<Plugin> pluginsFilter = new PluginsIncludeExcludeFilter(
234                 includeGroupIds, excludeGroupIds, includeArtifactIds, excludeArtifactIds);
235 
236         Predicate<Plugin> reactorExclusionFilter = plugin -> true;
237         if (excludeReactor) {
238             reactorExclusionFilter = new PluginsReactorExcludeFilter(session.getProjects());
239         }
240 
241         return resolverUtil.getProjectPlugins(getProject()).stream()
242                 .filter(reactorExclusionFilter)
243                 .filter(pluginsFilter)
244                 .collect(Collectors.toSet());
245     }
246 }