View Javadoc
1   package org.apache.maven.plugins.dependency;
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.io.IOException;
24  import java.lang.reflect.Field;
25  import java.util.List;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.execution.MavenSession;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.plugins.annotations.Component;
34  import org.apache.maven.plugins.annotations.Parameter;
35  import org.apache.maven.plugins.dependency.utils.DependencySilentLog;
36  import org.apache.maven.project.DefaultProjectBuildingRequest;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuildingRequest;
39  import org.codehaus.plexus.archiver.ArchiverException;
40  import org.codehaus.plexus.archiver.UnArchiver;
41  import org.codehaus.plexus.archiver.manager.ArchiverManager;
42  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
43  import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
44  import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
45  import org.codehaus.plexus.util.FileUtils;
46  import org.codehaus.plexus.util.ReflectionUtils;
47  import org.codehaus.plexus.util.StringUtils;
48  
49  /**
50   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
51   */
52  public abstract class AbstractDependencyMojo
53      extends AbstractMojo
54  {
55      /**
56       * To look up Archiver/UnArchiver implementations
57       */
58      @Component
59      private ArchiverManager archiverManager;
60  
61      /**
62       * <p>
63       * will use the jvm chmod, this is available for user and all level group level will be ignored
64       * </p>
65       * <b>since 2.6 is on by default</b>
66       * 
67       * @since 2.5.1
68       */
69      @Parameter( property = "dependency.useJvmChmod", defaultValue = "true" )
70      private boolean useJvmChmod = true;
71  
72      /**
73       * ignore to set file permissions when unpacking a dependency
74       * 
75       * @since 2.7
76       */
77      @Parameter( property = "dependency.ignorePermissions", defaultValue = "false" )
78      private boolean ignorePermissions;
79  
80      /**
81       * POM
82       */
83      @Parameter( defaultValue = "${project}", readonly = true, required = true )
84      private MavenProject project;
85  
86      /**
87       * Remote repositories which will be searched for artifacts.
88       */
89      @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
90      private List<ArtifactRepository> remoteRepositories;
91  
92      /**
93       * Contains the full list of projects in the reactor.
94       */
95      @Parameter( defaultValue = "${reactorProjects}", readonly = true )
96      protected List<MavenProject> reactorProjects;
97  
98      /**
99       * The Maven session
100      */
101     @Parameter( defaultValue = "${session}", readonly = true, required = true )
102     protected MavenSession session;
103 
104     /**
105      * If the plugin should be silent.
106      *
107      * @since 2.0
108      */
109     @Parameter( property = "silent", defaultValue = "false" )
110     private boolean silent;
111 
112     /**
113      * Output absolute filename for resolved artifacts
114      *
115      * @since 2.0
116      */
117     @Parameter( property = "outputAbsoluteArtifactFilename", defaultValue = "false" )
118     protected boolean outputAbsoluteArtifactFilename;
119 
120     /**
121      * Skip plugin execution completely.
122      *
123      * @since 2.7
124      */
125     @Parameter( property = "mdep.skip", defaultValue = "false" )
126     private boolean skip;
127 
128     // Mojo methods -----------------------------------------------------------
129 
130     /*
131      * @see org.apache.maven.plugin.Mojo#execute()
132      */
133     @Override
134     public final void execute()
135         throws MojoExecutionException, MojoFailureException
136     {
137         if ( isSkip() )
138         {
139             getLog().info( "Skipping plugin execution" );
140             return;
141         }
142 
143         doExecute();
144     }
145 
146     /**
147      * @throws MojoExecutionException {@link MojoExecutionException}
148      * @throws MojoFailureException {@link MojoFailureException}
149      */
150     protected abstract void doExecute()
151         throws MojoExecutionException, MojoFailureException;
152 
153     /**
154      * @return Returns the archiverManager.
155      */
156     public ArchiverManager getArchiverManager()
157     {
158         return this.archiverManager;
159     }
160 
161     /**
162      * Does the actual copy of the file and logging.
163      *
164      * @param artifact represents the file to copy.
165      * @param destFile file name of destination file.
166      * @throws MojoExecutionException with a message if an error occurs.
167      */
168     protected void copyFile( File artifact, File destFile )
169         throws MojoExecutionException
170     {
171         try
172         {
173             getLog().info( "Copying "
174                 + ( this.outputAbsoluteArtifactFilename ? artifact.getAbsolutePath() : artifact.getName() ) + " to "
175                 + destFile );
176 
177             if ( artifact.isDirectory() )
178             {
179                 // usual case is a future jar packaging, but there are special cases: classifier and other packaging
180                 throw new MojoExecutionException( "Artifact has not been packaged yet. When used on reactor artifact, "
181                     + "copy should be executed after packaging: see MDEP-187." );
182             }
183 
184             FileUtils.copyFile( artifact, destFile );
185         }
186         catch ( IOException e )
187         {
188             throw new MojoExecutionException( "Error copying artifact from " + artifact + " to " + destFile, e );
189         }
190     }
191 
192     /**
193      * @param artifact {@link Artifact}
194      * @param location The location.
195      * @param encoding The encoding.
196      * @throws MojoExecutionException in case of an error.
197      */
198     protected void unpack( Artifact artifact, File location, String encoding )
199         throws MojoExecutionException
200     {
201         unpack( artifact, location, null, null, encoding );
202     }
203 
204     /**
205      * Unpacks the archive file.
206      *
207      * @param artifact File to be unpacked.
208      * @param location Location where to put the unpacked files.
209      * @param includes Comma separated list of file patterns to include i.e. <code>**&#47;.xml,
210      *                 **&#47;*.properties</code>
211      * @param excludes Comma separated list of file patterns to exclude i.e. <code>**&#47;*.xml,
212      *                 **&#47;*.properties</code>
213      * @param encoding Encoding of artifact. Set {@code null} for default encoding.
214      * @throws MojoExecutionException In case of errors.
215      */
216     protected void unpack( Artifact artifact, File location, String includes, String excludes, String encoding )
217         throws MojoExecutionException
218     {
219         unpack( artifact, artifact.getType(), location, includes, excludes, encoding );
220     }
221 
222     /**
223      * @param artifact {@link Artifact}
224      * @param type The type.
225      * @param location The location.
226      * @param includes includes list.
227      * @param excludes excludes list.
228      * @param encoding the encoding.
229      * @throws MojoExecutionException in case of an error.
230      */
231     protected void unpack( Artifact artifact, String type, File location, String includes, String excludes,
232                            String encoding )
233         throws MojoExecutionException
234     {
235         File file = artifact.getFile();
236         try
237         {
238             logUnpack( file, location, includes, excludes );
239 
240             location.mkdirs();
241             if ( !location.exists() )
242             {
243                 throw new MojoExecutionException( "Location to write unpacked files to could not be created: "
244                     + location );
245             }
246 
247             if ( file.isDirectory() )
248             {
249                 // usual case is a future jar packaging, but there are special cases: classifier and other packaging
250                 throw new MojoExecutionException( "Artifact has not been packaged yet. When used on reactor artifact, "
251                     + "unpack should be executed after packaging: see MDEP-98." );
252             }
253 
254             UnArchiver unArchiver;
255 
256             try
257             {
258                 unArchiver = archiverManager.getUnArchiver( type );
259                 getLog().debug( "Found unArchiver by type: " + unArchiver );
260             }
261             catch ( NoSuchArchiverException e )
262             {
263                 unArchiver = archiverManager.getUnArchiver( file );
264                 getLog().debug( "Found unArchiver by extension: " + unArchiver );
265             }
266 
267             if ( encoding != null && unArchiver instanceof ZipUnArchiver )
268             {
269                 ( (ZipUnArchiver) unArchiver ).setEncoding( encoding );
270                 getLog().info( "Unpacks '" + type + "' with encoding '" + encoding + "'." );
271             }
272 
273             unArchiver.setUseJvmChmod( useJvmChmod );
274 
275             unArchiver.setIgnorePermissions( ignorePermissions );
276 
277             unArchiver.setSourceFile( file );
278 
279             unArchiver.setDestDirectory( location );
280 
281             if ( StringUtils.isNotEmpty( excludes ) || StringUtils.isNotEmpty( includes ) )
282             {
283                 // Create the selectors that will filter
284                 // based on include/exclude parameters
285                 // MDEP-47
286                 IncludeExcludeFileSelector[] selectors =
287                     new IncludeExcludeFileSelector[] { new IncludeExcludeFileSelector() };
288 
289                 if ( StringUtils.isNotEmpty( excludes ) )
290                 {
291                     selectors[0].setExcludes( excludes.split( "," ) );
292                 }
293 
294                 if ( StringUtils.isNotEmpty( includes ) )
295                 {
296                     selectors[0].setIncludes( includes.split( "," ) );
297                 }
298 
299                 unArchiver.setFileSelectors( selectors );
300             }
301             if ( this.silent )
302             {
303                 silenceUnarchiver( unArchiver );
304             }
305 
306             unArchiver.extract();
307         }
308         catch ( NoSuchArchiverException e )
309         {
310             throw new MojoExecutionException( "Unknown archiver type", e );
311         }
312         catch ( ArchiverException e )
313         {
314             throw new MojoExecutionException( "Error unpacking file: " + file + " to: " + location + "\r\n"
315                 + e.toString(), e );
316         }
317     }
318 
319     private void silenceUnarchiver( UnArchiver unArchiver )
320     {
321         // dangerous but handle any errors. It's the only way to silence the unArchiver.
322         try
323         {
324             Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( "logger", unArchiver.getClass() );
325 
326             field.setAccessible( true );
327 
328             field.set( unArchiver, this.getLog() );
329         }
330         catch ( Exception e )
331         {
332             // was a nice try. Don't bother logging because the log is silent.
333         }
334     }
335 
336     /**
337      * @return Returns a new ProjectBuildingRequest populated from the current session and the current project remote
338      *         repositories, used to resolve artifacts.
339      */
340     public ProjectBuildingRequest newResolveArtifactProjectBuildingRequest()
341     {
342         ProjectBuildingRequest buildingRequest =
343             new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
344 
345         buildingRequest.setRemoteRepositories( remoteRepositories );
346 
347         return buildingRequest;
348     }
349 
350     /**
351      * @return Returns the project.
352      */
353     public MavenProject getProject()
354     {
355         return this.project;
356     }
357 
358     /**
359      * @param archiverManager The archiverManager to set.
360      */
361     public void setArchiverManager( ArchiverManager archiverManager )
362     {
363         this.archiverManager = archiverManager;
364     }
365 
366     /**
367      * @return {@link #useJvmChmod}
368      */
369     public boolean isUseJvmChmod()
370     {
371         return useJvmChmod;
372     }
373 
374     /**
375      * @param useJvmChmod {@link #useJvmChmod}
376      */
377     public void setUseJvmChmod( boolean useJvmChmod )
378     {
379         this.useJvmChmod = useJvmChmod;
380     }
381 
382     /**
383      * @return {@link #skip}
384      */
385     public boolean isSkip()
386     {
387         return skip;
388     }
389 
390     /**
391      * @param skip {@link #skip}
392      */
393     public void setSkip( boolean skip )
394     {
395         this.skip = skip;
396     }
397 
398     /**
399      * @return {@link #silent}
400      */
401     protected final boolean isSilent()
402     {
403         return silent;
404     }
405 
406     /**
407      * @param silent {@link #silent}
408      */
409     public void setSilent( boolean silent )
410     {
411         this.silent = silent;
412         if ( silent )
413         {
414             setLog( new DependencySilentLog() );
415         }
416     }
417 
418     private void logUnpack( File file, File location, String includes, String excludes )
419     {
420         if ( !getLog().isInfoEnabled() )
421         {
422             return;
423         }
424 
425         StringBuilder msg = new StringBuilder();
426         msg.append( "Unpacking " );
427         msg.append( file );
428         msg.append( " to " );
429         msg.append( location );
430 
431         if ( includes != null && excludes != null )
432         {
433             msg.append( " with includes \"" );
434             msg.append( includes );
435             msg.append( "\" and excludes \"" );
436             msg.append( excludes );
437             msg.append( "\"" );
438         }
439         else if ( includes != null )
440         {
441             msg.append( " with includes \"" );
442             msg.append( includes );
443             msg.append( "\"" );
444         }
445         else if ( excludes != null )
446         {
447             msg.append( " with excludes \"" );
448             msg.append( excludes );
449             msg.append( "\"" );
450         }
451 
452         getLog().info( msg.toString() );
453     }
454 }