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