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.lifecycle.internal;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.List;
29  import java.util.stream.Collectors;
30  
31  import org.apache.maven.api.xml.XmlNode;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.internal.xml.XmlNodeImpl;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.plugin.BuildPluginManager;
36  import org.apache.maven.plugin.InvalidPluginDescriptorException;
37  import org.apache.maven.plugin.MojoNotFoundException;
38  import org.apache.maven.plugin.PluginDescriptorParsingException;
39  import org.apache.maven.plugin.PluginNotFoundException;
40  import org.apache.maven.plugin.PluginResolutionException;
41  import org.apache.maven.plugin.descriptor.MojoDescriptor;
42  import org.apache.maven.plugin.prefix.DefaultPluginPrefixRequest;
43  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
44  import org.apache.maven.plugin.prefix.PluginPrefixRequest;
45  import org.apache.maven.plugin.prefix.PluginPrefixResolver;
46  import org.apache.maven.plugin.prefix.PluginPrefixResult;
47  import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
48  import org.apache.maven.plugin.version.PluginVersionRequest;
49  import org.apache.maven.plugin.version.PluginVersionResolutionException;
50  import org.apache.maven.plugin.version.PluginVersionResolver;
51  import org.apache.maven.project.MavenProject;
52  import org.codehaus.plexus.configuration.PlexusConfiguration;
53  import org.slf4j.Logger;
54  import org.slf4j.LoggerFactory;
55  
56  /**
57   * <p>
58   * Resolves dependencies for the artifacts in context of the lifecycle build
59   * </p>
60   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
61   *
62   * @since 3.0
63   */
64  @Named
65  @Singleton
66  public class MojoDescriptorCreator {
67      private final Logger logger = LoggerFactory.getLogger(getClass());
68      private final PluginVersionResolver pluginVersionResolver;
69      private final BuildPluginManager pluginManager;
70      private final PluginPrefixResolver pluginPrefixResolver;
71      private final LifecyclePluginResolver lifecyclePluginResolver;
72  
73      @Inject
74      public MojoDescriptorCreator(
75              PluginVersionResolver pluginVersionResolver,
76              BuildPluginManager pluginManager,
77              PluginPrefixResolver pluginPrefixResolver,
78              LifecyclePluginResolver lifecyclePluginResolver) {
79          this.pluginVersionResolver = pluginVersionResolver;
80          this.pluginManager = pluginManager;
81          this.pluginPrefixResolver = pluginPrefixResolver;
82          this.lifecyclePluginResolver = lifecyclePluginResolver;
83      }
84  
85      private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
86          for (Plugin plugin : plugins) {
87              if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
88                  return plugin;
89              }
90          }
91  
92          return null;
93      }
94  
95      public static XmlNode convert(org.apache.maven.api.plugin.descriptor.MojoDescriptor mojoDescriptor) {
96          List<XmlNode> children = mojoDescriptor.getParameters().stream()
97                  .filter(p -> p.getDefaultValue() != null || p.getExpression() != null)
98                  .map(p -> new XmlNodeImpl(
99                          p.getName(),
100                         p.getExpression(),
101                         p.getDefaultValue() != null
102                                 ? Collections.singletonMap("default-value", p.getDefaultValue())
103                                 : null,
104                         null,
105                         null))
106                 .collect(Collectors.toList());
107         return new XmlNodeImpl("configuration", null, null, children, null);
108     }
109 
110     public static org.codehaus.plexus.util.xml.Xpp3Dom convert(MojoDescriptor mojoDescriptor) {
111         PlexusConfiguration c = mojoDescriptor.getMojoConfiguration();
112 
113         List<XmlNode> children = new ArrayList<>();
114         PlexusConfiguration[] ces = c.getChildren();
115         if (ces != null) {
116             for (PlexusConfiguration ce : ces) {
117                 String value = ce.getValue(null);
118                 String defaultValue = ce.getAttribute("default-value", null);
119                 if (value != null || defaultValue != null) {
120                     XmlNodeImpl e = new XmlNodeImpl(
121                             ce.getName(),
122                             value,
123                             defaultValue != null ? Collections.singletonMap("default-value", defaultValue) : null,
124                             null,
125                             null);
126                     children.add(e);
127                 }
128             }
129         }
130 
131         XmlNodeImpl dom = new XmlNodeImpl("configuration", null, null, children, null);
132         return new org.codehaus.plexus.util.xml.Xpp3Dom(dom);
133     }
134 
135     // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process@executionId
136 
137     public MojoDescriptor getMojoDescriptor(String task, MavenSession session, MavenProject project)
138             throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
139                     MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
140                     PluginVersionResolutionException {
141         String goal = null;
142 
143         Plugin plugin = null;
144 
145         String[] tok = task.split(":");
146 
147         int numTokens = tok.length;
148 
149         if (numTokens >= 4) {
150             // We have everything that we need
151             //
152             // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
153             //
154             // groupId
155             // artifactId
156             // version
157             // goal
158             //
159             plugin = new Plugin();
160             plugin.setGroupId(tok[0]);
161             plugin.setArtifactId(tok[1]);
162             plugin.setVersion(tok[2]);
163             goal = tok[3];
164 
165             // This won't be valid, but it constructs something easy to read in the error message
166             for (int idx = 4; idx < tok.length; idx++) {
167                 goal += ":" + tok[idx];
168             }
169         } else if (numTokens == 3) {
170             // groupId:artifactId:goal or pluginPrefix:version:goal (since Maven 3.9.0)
171 
172             String firstToken = tok[0];
173             // groupId or pluginPrefix? heuristics: groupId contains dot (.) but not pluginPrefix
174             if (firstToken.contains(".")) {
175                 // We have everything that we need except the version
176                 //
177                 // org.apache.maven.plugins:maven-remote-resources-plugin:???:process
178                 //
179                 // groupId
180                 // artifactId
181                 // ???
182                 // goal
183                 //
184                 plugin = new Plugin();
185                 plugin.setGroupId(firstToken);
186                 plugin.setArtifactId(tok[1]);
187             } else {
188                 // pluginPrefix:version:goal, like remote-resources:3.5.0:process
189                 plugin = findPluginForPrefix(firstToken, session);
190                 plugin.setVersion(tok[1]);
191             }
192             goal = tok[2];
193         } else {
194             // We have a prefix and goal
195             //
196             // idea:idea
197             //
198             String prefix = tok[0];
199 
200             if (numTokens == 2) {
201                 goal = tok[1];
202             } else {
203                 // goal was missing - pass through to MojoNotFoundException
204                 goal = "";
205             }
206 
207             // This is the case where someone has executed a single goal from the command line
208             // of the form:
209             //
210             // mvn remote-resources:process
211             //
212             // From the metadata stored on the server which has been created as part of a standard
213             // Maven plugin deployment we will find the right PluginDescriptor from the remote
214             // repository.
215 
216             plugin = findPluginForPrefix(prefix, session);
217         }
218 
219         int executionIdx = goal.indexOf('@');
220         if (executionIdx > 0) {
221             goal = goal.substring(0, executionIdx);
222         }
223 
224         injectPluginDeclarationFromProject(plugin, project);
225 
226         // If there is no version to be found then we need to look in the repository metadata for
227         // this plugin and see what's specified as the latest release.
228         //
229         if (plugin.getVersion() == null) {
230             resolvePluginVersion(plugin, session, project);
231         }
232 
233         return pluginManager.getMojoDescriptor(
234                 plugin, goal, project.getRemotePluginRepositories(), session.getRepositorySession());
235     }
236 
237     // TODO take repo mans into account as one may be aggregating prefixes of many
238     // TODO collect at the root of the repository, read the one at the root, and fetch remote if something is missing
239     // or the user forces the issue
240 
241     public Plugin findPluginForPrefix(String prefix, MavenSession session) throws NoPluginFoundForPrefixException {
242         // [prefix]:[goal]
243 
244         if (session.getCurrentProject() != null) {
245             try {
246                 lifecyclePluginResolver.resolveMissingPluginVersions(session.getCurrentProject(), session);
247             } catch (PluginVersionResolutionException e) {
248                 // not critical here
249                 logger.debug(e.getMessage(), e);
250             }
251         }
252 
253         PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest(prefix, session);
254         PluginPrefixResult prefixResult = pluginPrefixResolver.resolve(prefixRequest);
255 
256         Plugin plugin = new Plugin();
257         plugin.setGroupId(prefixResult.getGroupId());
258         plugin.setArtifactId(prefixResult.getArtifactId());
259 
260         return plugin;
261     }
262 
263     private void resolvePluginVersion(Plugin plugin, MavenSession session, MavenProject project)
264             throws PluginVersionResolutionException {
265         PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(
266                 plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
267         plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
268     }
269 
270     private void injectPluginDeclarationFromProject(Plugin plugin, MavenProject project) {
271         Plugin pluginInPom = findPlugin(plugin, project.getBuildPlugins());
272 
273         if (pluginInPom == null && project.getPluginManagement() != null) {
274             pluginInPom = findPlugin(plugin, project.getPluginManagement().getPlugins());
275         }
276 
277         if (pluginInPom != null) {
278             if (plugin.getVersion() == null) {
279                 plugin.setVersion(pluginInPom.getVersion());
280             }
281 
282             plugin.setDependencies(new ArrayList<>(pluginInPom.getDependencies()));
283         }
284     }
285 
286     private Plugin findPlugin(Plugin plugin, Collection<Plugin> plugins) {
287         return findPlugin(plugin.getGroupId(), plugin.getArtifactId(), plugins);
288     }
289 }