View Javadoc
1   package org.codehaus.mojo.exec;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.nio.file.Path;
24  import java.nio.file.Paths;
25  import java.util.List;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.execution.MavenSession;
29  import org.apache.maven.model.Resource;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugins.annotations.Parameter;
33  import org.apache.maven.project.MavenProject;
34  import org.codehaus.plexus.util.cli.CommandLineUtils;
35  
36  /**
37   * This class is used for unifying functionality between the 2 mojo exec plugins ('java' and 'exec'). It handles parsing
38   * the arguments and adding source/test folders.
39   *
40   * @author Philippe Jacot (PJA)
41   * @author Jerome Lacoste
42   */
43  public abstract class AbstractExecMojo
44      extends AbstractMojo
45  {
46      /**
47       * The enclosing project.
48       */
49      @Parameter( defaultValue = "${project}", readonly = true )
50      protected MavenProject project;
51      
52      @Parameter( defaultValue = "${session}", readonly = true, required = true )
53      private MavenSession session;
54  
55      @Parameter( readonly = true, defaultValue = "${plugin.artifacts}" )
56      private List<Artifact> pluginDependencies;
57  
58      /**
59       * If provided the ExecutableDependency identifies which of the plugin dependencies contains the executable class.
60       * This will have the effect of only including plugin dependencies required by the identified ExecutableDependency.
61       *
62       * <p>
63       * If includeProjectDependencies is set to <code>true</code>, all of the project dependencies will be included on
64       * the executable's classpath. Whether a particular project dependency is a dependency of the identified
65       * ExecutableDependency will be irrelevant to its inclusion in the classpath.
66       * </p>
67       *
68       * @since 1.1-beta-1
69       */
70      @Parameter
71      protected ExecutableDependency executableDependency;
72  
73      /**
74       * This folder is added to the list of those folders containing source to be compiled. Use this if your plugin
75       * generates source code.
76       */
77      @Parameter( property = "sourceRoot" )
78      private File sourceRoot;
79  
80      /**
81       * This folder is added to the list of those folders containing source to be compiled for testing. Use this if your
82       * plugin generates test source code.
83       */
84      @Parameter( property = "testSourceRoot" )
85      private File testSourceRoot;
86  
87      /**
88       * Arguments separated by space for the executed program. For example: "-j 20"
89       */
90      @Parameter( property = "exec.args" )
91      private String commandlineArgs;
92  
93      /**
94       * Defines the scope of the classpath passed to the plugin. Set to compile,test,runtime or system depending on your
95       * needs. Since 1.1.2, the default value is 'runtime' instead of 'compile'.
96       */
97      @Parameter( property = "exec.classpathScope", defaultValue = "runtime" )
98      protected String classpathScope;
99  
100     /**
101      * Skip the execution. Starting with version 1.4.0 the former name <code>skip</code> has been changed into
102      * <code>exec.skip</code>.
103      * 
104      * @since 1.0.1
105      */
106     // TODO: Remove the alias in version 1.5.0 of the plugin.
107     @Parameter( property = "exec.skip", defaultValue = "false", alias = "skip" )
108     private boolean skip;
109 
110     /**
111      * Add project resource directories to classpath. This is especially useful if the exec plugin is used for a code
112      * generator that reads its settings from the classpath.
113      * 
114      * @since 1.5.1
115      */
116     @Parameter( property = "addResourcesToClasspath", defaultValue = "false" )
117     private boolean addResourcesToClasspath;
118 
119     /**
120      * Add project output directory to classpath. This might be undesirable when the exec plugin is run before the
121      * compile step. Default is <code>true</code>.
122      * 
123      * @since 1.5.1
124      */
125     @Parameter( property = "addOutputToClasspath", defaultValue = "true" )
126     private boolean addOutputToClasspath;
127 
128     /**
129      * Collects the project artifacts in the specified List and the project specific classpath (build output and build
130      * test output) Files in the specified List, depending on the plugin classpathScope value.
131      *
132      * @param artifacts the list where to collect the scope specific artifacts
133      * @param theClasspathFiles the list where to collect the scope specific output directories
134      */
135     protected void collectProjectArtifactsAndClasspath( List<Artifact> artifacts, List<Path> theClasspathFiles )
136     {
137         if ( addResourcesToClasspath )
138         {
139             for ( Resource r : project.getBuild().getResources() )
140             {
141                 theClasspathFiles.add( Paths.get( r.getDirectory() ) );
142             }
143         }
144 
145         if ( "compile".equals( classpathScope ) )
146         {
147             artifacts.addAll( project.getCompileArtifacts() );
148             if ( addOutputToClasspath )
149             {
150                 theClasspathFiles.add( Paths.get( project.getBuild().getOutputDirectory() ) );
151             }
152         }
153         else if ( "test".equals( classpathScope ) )
154         {
155             artifacts.addAll( project.getTestArtifacts() );
156             if ( addOutputToClasspath )
157             {
158                 theClasspathFiles.add( Paths.get( project.getBuild().getTestOutputDirectory() ) );
159                 theClasspathFiles.add( Paths.get( project.getBuild().getOutputDirectory() ) );
160             }
161         }
162         else if ( "runtime".equals( classpathScope ) )
163         {
164             artifacts.addAll( project.getRuntimeArtifacts() );
165             if ( addOutputToClasspath )
166             {
167                 theClasspathFiles.add( Paths.get( project.getBuild().getOutputDirectory() ) );
168             }
169         }
170         else if ( "system".equals( classpathScope ) )
171         {
172             artifacts.addAll( project.getSystemArtifacts() );
173         }
174         else
175         {
176             throw new IllegalStateException( "Invalid classpath scope: " + classpathScope );
177         }
178 
179         getLog().debug( "Collected project artifacts " + artifacts );
180         getLog().debug( "Collected project classpath " + theClasspathFiles );
181     }
182 
183     /**
184      * Parses the argument string given by the user. Strings are recognized as everything between STRING_WRAPPER.
185      * PARAMETER_DELIMITER is ignored inside a string. STRING_WRAPPER and PARAMETER_DELIMITER can be escaped using
186      * ESCAPE_CHAR.
187      *
188      * @return Array of String representing the arguments
189      * @throws MojoExecutionException for wrong formatted arguments
190      */
191     protected String[] parseCommandlineArgs()
192         throws MojoExecutionException
193     {
194         if ( commandlineArgs == null )
195         {
196             return null;
197         }
198         else
199         {
200             try
201             {
202                 return CommandLineUtils.translateCommandline( commandlineArgs );
203             }
204             catch ( Exception e )
205             {
206                 throw new MojoExecutionException( e.getMessage() );
207             }
208         }
209     }
210 
211     /**
212      * @return true of the mojo has command line arguments
213      */
214     protected boolean hasCommandlineArgs()
215     {
216         return ( commandlineArgs != null );
217     }
218 
219     /**
220      * Register compile and compile tests source roots if necessary
221      */
222     protected void registerSourceRoots()
223     {
224         if ( sourceRoot != null )
225         {
226             getLog().info( "Registering compile source root " + sourceRoot );
227             project.addCompileSourceRoot( sourceRoot.toString() );
228         }
229 
230         if ( testSourceRoot != null )
231         {
232             getLog().info( "Registering compile test source root " + testSourceRoot );
233             project.addTestCompileSourceRoot( testSourceRoot.toString() );
234         }
235     }
236 
237     /**
238      * Check if the execution should be skipped
239      *
240      * @return true to skip
241      */
242     protected boolean isSkip()
243     {
244         return skip;
245     }
246 
247     protected final MavenSession getSession()
248     {
249         return session;
250     }
251 
252     protected final List<Artifact> getPluginDependencies()
253     {
254         return pluginDependencies;
255     }
256 
257     /**
258      * Examine the plugin dependencies to find the executable artifact.
259      * 
260      * @return an artifact which refers to the actual executable tool (not a POM)
261      * @throws MojoExecutionException if no executable artifact was found
262      */
263     protected Artifact findExecutableArtifact()
264         throws MojoExecutionException
265     {
266         // ILimitedArtifactIdentifier execToolAssembly = this.getExecutableToolAssembly();
267 
268         Artifact executableTool = null;
269         for ( Artifact pluginDep : this.pluginDependencies )
270         {
271             if ( this.executableDependency.matches( pluginDep ) )
272             {
273                 executableTool = pluginDep;
274                 break;
275             }
276         }
277 
278         if ( executableTool == null )
279         {
280             throw new MojoExecutionException( "No dependency of the plugin matches the specified executableDependency."
281                 + "  Specified executableToolAssembly is: " + executableDependency.toString() );
282         }
283 
284         return executableTool;
285     }
286 }