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