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.help;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.Writer;
24  
25  import org.apache.maven.artifact.Artifact;
26  import org.apache.maven.execution.MavenSession;
27  import org.apache.maven.model.building.ModelBuildingRequest;
28  import org.apache.maven.plugin.AbstractMojo;
29  import org.apache.maven.plugin.MojoExecutionException;
30  import org.apache.maven.plugins.annotations.Component;
31  import org.apache.maven.plugins.annotations.Parameter;
32  import org.apache.maven.project.DefaultProjectBuildingRequest;
33  import org.apache.maven.project.MavenProject;
34  import org.apache.maven.project.ProjectBuilder;
35  import org.apache.maven.project.ProjectBuildingRequest;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.codehaus.plexus.util.WriterFactory;
38  import org.eclipse.aether.RepositoryException;
39  import org.eclipse.aether.RepositorySystem;
40  import org.eclipse.aether.RepositorySystemSession;
41  import org.eclipse.aether.artifact.DefaultArtifact;
42  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
43  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
44  import org.eclipse.aether.resolution.ArtifactRequest;
45  
46  /**
47   * Base class with some Help Mojo functionalities.
48   *
49   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
50   * @since 2.1
51   */
52  public abstract class AbstractHelpMojo extends AbstractMojo {
53      /** The maximum length of a display line. */
54      protected static final int LINE_LENGTH = 79;
55  
56      /** The line separator for the current OS. */
57      protected static final String LS = System.getProperty("line.separator");
58  
59      /**
60       * Maven Project Builder component.
61       */
62      @Component
63      protected ProjectBuilder projectBuilder;
64  
65      /**
66       * Component used to resolve artifacts and download their files from remote repositories.
67       */
68      @Component
69      protected RepositorySystem repositorySystem;
70  
71      /**
72       * Current Maven project.
73       */
74      @Parameter(defaultValue = "${project}", readonly = true, required = true)
75      protected MavenProject project;
76  
77      /**
78       * The current build session instance. This is used for
79       * plugin manager API calls.
80       */
81      @Parameter(defaultValue = "${session}", readonly = true, required = true)
82      protected MavenSession session;
83  
84      /**
85       * Optional parameter to write the output of this help in a given file, instead of writing to the console.
86       * <br>
87       * <b>Note</b>: Could be a relative path.
88       */
89      @Parameter(property = "output")
90      protected File output;
91  
92      /**
93       * Utility method to write a content in a given file.
94       *
95       * @param output is the wanted output file.
96       * @param content contains the content to be written to the file.
97       * @throws IOException if any
98       * @see #writeFile(File, String)
99       */
100     protected static void writeFile(File output, StringBuilder content) throws IOException {
101         writeFile(output, content.toString());
102     }
103 
104     /**
105      * Utility method to write a content in a given file.
106      *
107      * @param output is the wanted output file.
108      * @param content contains the content to be written to the file.
109      * @throws IOException if any
110      */
111     protected static void writeFile(File output, String content) throws IOException {
112         if (output == null) {
113             return;
114         }
115 
116         output.getParentFile().mkdirs();
117         try (Writer out = WriterFactory.newPlatformWriter(output)) {
118             out.write(content);
119         }
120     }
121 
122     /**
123      * Parses the given String into GAV artifact coordinate information, adding the given type.
124      *
125      * @param artifactString should respect the format <code>groupId:artifactId[:version]</code>
126      * @param type The extension for the artifact, must not be <code>null</code>.
127      * @return the <code>Artifact</code> object for the <code>artifactString</code> parameter.
128      * @throws MojoExecutionException if the <code>artifactString</code> doesn't respect the format.
129      */
130     protected org.eclipse.aether.artifact.Artifact getAetherArtifact(String artifactString, String type)
131             throws MojoExecutionException {
132         if (StringUtils.isEmpty(artifactString)) {
133             throw new IllegalArgumentException("artifact parameter could not be empty");
134         }
135 
136         String groupId; // required
137         String artifactId; // required
138         String version; // optional
139 
140         String[] artifactParts = artifactString.split(":");
141         switch (artifactParts.length) {
142             case 2:
143                 groupId = artifactParts[0];
144                 artifactId = artifactParts[1];
145                 version = Artifact.LATEST_VERSION;
146                 break;
147             case 3:
148                 groupId = artifactParts[0];
149                 artifactId = artifactParts[1];
150                 version = artifactParts[2];
151                 break;
152             default:
153                 throw new MojoExecutionException("The artifact parameter '" + artifactString
154                         + "' should be conform to: " + "'groupId:artifactId[:version]'.");
155         }
156 
157         return new DefaultArtifact(groupId, artifactId, type, version);
158     }
159 
160     /**
161      * Retrieves the Maven Project associated with the given artifact String, in the form of
162      * <code>groupId:artifactId[:version]</code>. This resolves the POM artifact at those coordinates and then builds
163      * the Maven project from it.
164      *
165      * @param artifactString Coordinates of the Maven project to get.
166      * @return New Maven project.
167      * @throws MojoExecutionException If there was an error while getting the Maven project.
168      */
169     protected MavenProject getMavenProject(String artifactString) throws MojoExecutionException {
170         try {
171             ProjectBuildingRequest pbr = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
172             pbr.setRemoteRepositories(project.getRemoteArtifactRepositories());
173             pbr.setPluginArtifactRepositories(project.getPluginArtifactRepositories());
174             pbr.setProject(null);
175             pbr.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
176             pbr.setResolveDependencies(true);
177 
178             org.eclipse.aether.artifact.Artifact artifact =
179                     resolveArtifact(getAetherArtifact(artifactString, "pom")).getArtifact();
180 
181             return projectBuilder.build(artifact.getFile(), pbr).getProject();
182         } catch (Exception e) {
183             throw new MojoExecutionException(
184                     "Unable to get the POM for the artifact '" + artifactString + "'. Verify the artifact parameter.",
185                     e);
186         }
187     }
188 
189     protected org.eclipse.aether.resolution.ArtifactResult resolveArtifact(
190             org.eclipse.aether.artifact.Artifact artifact) throws RepositoryException {
191         RepositorySystemSession repositorySession = session.getRepositorySession();
192 
193         // use descriptor to respect relocation
194         ArtifactDescriptorResult artifactDescriptor = repositorySystem.readArtifactDescriptor(
195                 repositorySession,
196                 new ArtifactDescriptorRequest(artifact, project.getRemoteProjectRepositories(), null));
197 
198         return repositorySystem.resolveArtifact(
199                 repositorySession,
200                 new ArtifactRequest(artifactDescriptor.getArtifact(), project.getRemoteProjectRepositories(), null));
201     }
202 }