View Javadoc
1   package org.apache.maven.plugin.cxx;
2   
3   /*
4    * Copyright (C) 2011-2016, Neticoa SAS France - Tous droits réservés.
5    * Author(s) : Franck Bonin, Neticoa SAS France
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   *
19   */
20   
21  import org.apache.maven.artifact.Artifact;
22  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
23  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
24  import org.apache.maven.plugin.MojoExecutionException;
25  import org.apache.maven.plugin.dependency.utils.DependencyStatusSets;
26  import org.apache.maven.plugin.dependency.utils.DependencyUtil;
27  import org.apache.maven.plugin.dependency.utils.filters.MarkerFileFilter;
28  import org.apache.maven.plugin.dependency.utils.markers.DefaultFileMarkerHandler;
29  import org.apache.maven.plugins.annotations.LifecyclePhase;
30  import org.apache.maven.plugins.annotations.Mojo;
31  import org.apache.maven.plugins.annotations.Parameter;
32  import org.apache.maven.plugins.annotations.Component;
33  import org.apache.maven.plugins.annotations.ResolutionScope;
34  import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
35  
36  /* rewrite of  UnpackDependenciesMojo from maven-dependency plugin, goal 'unpack-dependencies' */
37  //import org.apache.maven.plugin.dependency.fromDependencies.AbstractFromDependenciesMojo;
38  
39  import org.codehaus.plexus.util.StringUtils;
40  
41  import java.io.File;
42  import java.io.IOException;
43  import java.util.ArrayList;
44  import java.util.Iterator;
45  import java.util.List;
46  import java.util.HashSet;
47  import java.util.Set;
48  
49  import java.nio.file.Files;
50  import java.nio.file.Paths;
51  import java.nio.file.StandardCopyOption;
52  
53  import java.lang.reflect.Field;
54  import org.codehaus.plexus.util.ReflectionUtils;
55  import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
56  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
57  import org.codehaus.plexus.archiver.ArchiverException;
58  // our own personal org.codehaus.plexus.archiver api extension
59  import org.codehaus.plexus.archiver.ArchiveContentLister;
60  import org.codehaus.plexus.archiver.ArchiveContentEntry;
61  import org.codehaus.plexus.archiver.manager.ArchiveContentListerManager;
62  
63  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
64  import org.apache.maven.plugin.cxx.utils.ClassifierRegexFilter;
65  import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
66  import org.apache.maven.shared.artifact.filter.collection.ClassifierFilter;
67  import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
68  import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
69  import org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
70  import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
71  import org.apache.maven.shared.artifact.filter.collection.TypeFilter;  
72  
73  import org.apache.maven.project.MavenProject;
74  import org.apache.maven.project.MavenProjectBuilder;
75  import org.apache.maven.project.ProjectBuildingException;
76  
77  /**
78   * Goal that unpacks the project dependencies from the repository to a defined
79   * location. 
80   *
81   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>, Franck Bonin
82   * @since 0.0.6
83   */
84  @Mojo( name = "unpack-dependencies", requiresDependencyResolution = ResolutionScope.TEST,
85         defaultPhase = LifecyclePhase.PROCESS_SOURCES, threadSafe = true )
86  public class UnpackDependenciesMojo
87      extends org.apache.maven.plugin.dependency.fromDependencies.UnpackDependenciesMojo
88  {
89     
90      /**
91       * To look up ArchiveContentLister implementations
92       * 
93       * origin : org.apache.maven.plugin.dependency.fromDependencies.UnpackDependenciesMojo
94       */
95      @Component
96      protected ArchiveContentListerManager archiveContentListerManager;
97      
98      
99      /**
100      * Directory where dependencies shall be flattened
101      * 
102      * @since 0.0.6
103      */
104     @Parameter( property = "mdep.unpack.flattenDestDirs" )
105     protected List flattenDestDirs = new ArrayList();
106     
107     /**
108      * Comma Separated list of Classifiers to include. Empty String indicates
109      * include everything (default).
110      *
111      * @since 0.0.6
112      */
113     @Parameter( property = "includeRegexClassifiers", defaultValue = "" )
114     protected String includeRegexClassifiers;
115 
116     /**
117      * Comma Separated list of Classifiers to exclude. Empty String indicates
118      * don't exclude anything (default).
119      *
120      * @since 0.0.6
121      */
122     @Parameter( property = "excludeRegexClassifiers", defaultValue = "" )
123     protected String excludeRegexClassifiers;
124     
125     //doublon with CMakeMojo !!
126     /*protected String extractBuildConfig(String classifier)
127     {
128         //bin-${targetClassifier}-${buildConfig}
129         String[] parts = classifier.split("-");
130         return (parts.length >= 3)? parts[parts.length-1] : null;
131     }
132      
133     protected String extractSubClassifier(String classifier)
134     {
135         //bin-${targetClassifier}-${buildConfig}
136         String[] parts = classifier.split("-");
137         if (parts.length >= 3)
138         {
139             //parts[1] .. parts[length-2]
140             StringBuilder builder = new StringBuilder();
141             builder.append(parts[1]);
142             for(int i = 2; i <= parts.length-2; i++) 
143             {
144                 builder.append("-");
145                 builder.append(parts[i]);
146             }
147             return builder.toString();
148         }
149         return null;
150     }
151 
152     protected void flatCopy( Artifact artifact, File destDir )
153             throws MojoExecutionException
154     {
155         String artifactId = artifact.getArtifactId();
156         String classifer = artifact.getClassifier();
157         String subClassifier = extractSubClassifier(classifer);
158         String buildConfig = extractBuildConfig(classifer);    
159         
160         if (StringUtils.isNotEmpty(subClassifier) && StringUtils.isNotEmpty(buildConfig) )
161         {
162             getLog().debug("Artifact " + artifactId + " with classifier " +
163                 classifer + "( " + subClassifier + ", " + buildConfig + " ) could be flattened");
164           
165             Iterator it = flattenDestDirs.iterator();
166             HashSet<String> incudedSet = new HashSet<String>();
167             while( it.hasNext() )
168             {
169                 String flattenDestDir = it.next().toString();
170                 
171                 String sourceDir = destDir.getAbsolutePath() + File.separator + extractSubClassifier(classifer) +
172                     File.separator + extractBuildConfig(classifer) + File.separator + artifactId;
173                     
174                 getLog().debug("Artifact " + artifactId + " content " +
175                     
176                 FileSet afileSet = new FileSet();
177                 afileSet.setDirectory( sourceDir );
178                 // $FB pour éviter d'avoir TROP de fichiers exclude (inutile) dans la boucle for ci-après
179                 afileSet.setUseDefaultExcludes( false ); 
180                 if ( StringUtils.isNotEmpty( includes ) )
181                 {
182                     afileSet.setIncludes( Arrays.asList( includes.split( "," ) ) );
183                 }
184                 if ( StringUtils.isNotEmpty( excludes ) )
185                 {
186                     afileSet.setExcludes( Arrays.asList( excludes.split( "," ) ) );
187                 }
188                 
189                 FileSetManager aFileSetManager = new FileSetManager();
190                 String[] found = aFileSetManager.getIncludedFiles( afileSet);
191                 
192                 incudedSet.addAll( new HashSet<String>( Arrays.asList( found) ));
193                 
194                 if (! incudedSet.isEmpty() )
195                 {
196                     File newDirs = new File(flattenDestDir);
197                     if (Files.notExists(Paths.get(newDirs.getPath())))
198                     {
199                         getLog().info("dirs to generate : "+ newDirs.getAbsoluteFile());
200                         newDirs.mkdirs();
201                     }
202                 }
203                 
204                 getLog().info( "file from " + sourceDir + " to flatten to " + flattenDestDir + " are :");
205                 for ( Iterator<String> iter = incudedSet.iterator(); iter.hasNext(); )
206                 {
207                     String sSubFilePath = iter.next();
208                     getLog().info(sSubFilePath);
209                     String sSubFileName = (new File(sSubFilePath)).getName();
210                     String src = sourceDir + File.separator + sSubFilePath;
211                     String dst = flattenDestDir + File.separator + sSubFileName;
212                     try
213                     {
214                         Files.copy(Paths.get(src), Paths.get(dst), StandardCopyOption.REPLACE_EXISTING);
215                         getLog().info("copy " + src + " to " + dst);
216                     }
217                     catch ( IOException e )
218                     {
219                         getLog().error( "Copy of " + src + " to " + dst + " failed : " + e);
220                     }
221                 }
222             }
223         }
224 
225     */
226     /**
227      * flat copy the archive content.
228      * 
229      * origin : derived from org.apache.maven.plugin.dependency.AbstractDependencyMojo::unpack()
230      *
231      * @param artifact File to be unpacked.
232      * @param srcRoot  Location where the whole archive was unpacked.
233      * @param location Location where to put the unpacked files.
234      * @param includes Comma separated list of file patterns to include i.e. <code>**&#47;.xml,
235      *                 **&#47;*.properties</code>
236      * @param excludes Comma separated list of file patterns to exclude i.e. <code>**&#47;*.xml,
237      *                 **&#47;*.properties</code>
238      */
239     protected void listAndFlatCopy( Artifact artifact, File srcRoot, File location, String includes, String excludes )
240         throws MojoExecutionException
241     {
242         File file = artifact.getFile(); 
243         try
244         {
245             //logUnpack( file, location, includes, excludes );
246 
247             location.mkdirs();
248 
249             if ( file.isDirectory() )
250             {
251                 // usual case is a future jar packaging, but there are special cases: classifier and other packaging
252                 throw new MojoExecutionException( "Artifact has not been packaged yet. When used on reactor artifact, "
253                     + "unpack should be executed after packaging: see MDEP-98." );
254             }
255 
256             ArchiveContentLister archiveContentLister;
257 
258             try
259             {
260                 archiveContentLister = archiveContentListerManager.getArchiveContentLister( artifact.getType() );
261                 getLog().debug( "Found archiveContentLister by type: " + archiveContentLister );
262             }
263             catch ( NoSuchArchiverException e )
264             {
265                 archiveContentLister = archiveContentListerManager.getArchiveContentLister( file );
266                 getLog().debug( "Found unArchiver by extension: " + archiveContentLister );
267             }
268 
269             //unArchiver.setUseJvmChmod( useJvmChmod );
270 
271             //unArchiver.setIgnorePermissions( ignorePermissions );
272 
273             archiveContentLister.setSourceFile( file );
274 
275             //unArchiver.setDestDirectory( location );
276 
277             if ( StringUtils.isNotEmpty( excludes ) || StringUtils.isNotEmpty( includes ) )
278             {
279                 // Create the selectors that will filter
280                 // based on include/exclude parameters
281                 // MDEP-47
282                 IncludeExcludeFileSelector[] selectors =
283                     new IncludeExcludeFileSelector[]{ new IncludeExcludeFileSelector() };
284 
285                 if ( StringUtils.isNotEmpty( excludes ) )
286                 {
287                     selectors[0].setExcludes( excludes.split( "," ) );
288                 }
289 
290                 if ( StringUtils.isNotEmpty( includes ) )
291                 {
292                     selectors[0].setIncludes( includes.split( "," ) );
293                 }
294 
295                 archiveContentLister.setFileSelectors( selectors );
296             }
297             if ( this.silent )
298             {
299                 silenceArchiveContentLister( archiveContentLister );
300             }
301 
302             List<ArchiveContentEntry> contents = archiveContentLister.list();
303             
304             for ( ArchiveContentEntry content : contents )
305             {
306                 if ( content.getType() == ArchiveContentEntry.FILE )
307                 {
308                     String sSubFileName = ( new File( content.getName() ) ).getName();
309                     String src = srcRoot.getAbsolutePath() + File.separator + content.getName();
310                     String dst = location +  File.separator + sSubFileName;
311                     try
312                     {
313                         Files.copy( Paths.get( src ), Paths.get( dst ), StandardCopyOption.REPLACE_EXISTING );
314                         getLog().debug( "Copy " + src + " to " + dst );
315                     }
316                     catch ( IOException e )
317                     {
318                         getLog().error( "Copy of " + src + " to " + dst + " failed : " + e );
319                     }    
320                 }
321             }            
322             
323         }
324         catch ( NoSuchArchiverException e )
325         {
326             throw new MojoExecutionException( "Unknown archiver type", e );
327         }
328         catch ( ArchiverException e )
329         {
330             throw new MojoExecutionException(
331                 "Error unpacking file: " + file + " to: " + location + "\r\n" + e.toString(), e );
332         }
333     }
334     
335     /**
336      * origin : derived from org.apache.maven.plugin.dependency.AbstractDependencyMojo::silenceUnarchiver()
337      */
338     private void silenceArchiveContentLister( ArchiveContentLister archiveContentLister )
339     {
340         // dangerous but handle any errors. It's the only way to silence the unArchiver.
341         try
342         {
343             Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(
344                 "logger", archiveContentLister.getClass() );
345 
346             field.setAccessible( true );
347 
348             field.set( archiveContentLister, this.getLog() );
349         }
350         catch ( Exception e )
351         {
352             // was a nice try. Don't bother logging because the log is silent.
353         }
354     }
355     
356     /**
357      * origin : org.apache.maven.plugin.dependency.fromDependencies.AbstractDependencyFilterMojo
358      */
359     @Component
360     MavenProjectBuilder myProjectBuilder;
361     
362     /**
363      * origin : org.apache.maven.plugin.dependency.fromDependencies.AbstractDependencyFilterMojo
364      */
365     private MavenProject buildProjectFromArtifact( Artifact artifact )
366         throws MojoExecutionException
367     {
368         try
369         {
370             return myProjectBuilder.buildFromRepository( artifact, remoteRepos, getLocal() );
371         }
372         catch ( ProjectBuildingException e )
373         {
374             throw new MojoExecutionException( e.getMessage(), e );
375         }
376     }
377     
378     /**
379      * origin : org.apache.maven.plugin.dependency.fromDependencies.AbstractDependencyFilterMojo
380      */
381     private void addParentArtifacts( MavenProject project, Set<Artifact> artifacts )
382         throws MojoExecutionException
383     {
384         while ( project.hasParent() )
385         {
386             project = project.getParent();
387 
388             if ( project.getArtifact() == null )
389             {
390                 // Maven 2.x bug
391                 Artifact artifact =
392                     factory.createBuildArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(),
393                                                  project.getPackaging() );
394                 project.setArtifact( artifact );
395             }
396 
397             if ( !artifacts.add( project.getArtifact() ) )
398             {
399                 // artifact already in the set
400                 break;
401             }
402             try
403             {
404                 resolver.resolve( project.getArtifact(), this.remoteRepos, this.getLocal() );
405             }
406             catch ( ArtifactResolutionException e )
407             {
408                 throw new MojoExecutionException( e.getMessage(), e );
409             }
410             catch ( ArtifactNotFoundException e )
411             {
412                 throw new MojoExecutionException( e.getMessage(), e );
413             }
414         }
415     }
416 
417     /**
418      * Method creates filters and filters the projects dependencies. This method
419      * also transforms the dependencies if classifier is set. The dependencies
420      * are filtered in least specific to most specific order
421      * 
422      * origin : derived from org.apache.maven.plugin.dependency.fromDependencies.AbstractDependencyFilterMojo
423      *
424      * @param stopOnFailure
425      * @return DependencyStatusSets - Bean of TreeSets that contains information
426      *         on the projects dependencies
427      * @throws MojoExecutionException
428      */
429     protected DependencyStatusSets getDependencySets( boolean stopOnFailure, boolean includeParents )
430         throws MojoExecutionException
431     {
432         // add filters in well known order, least specific to most specific
433         FilterArtifacts filter = new FilterArtifacts();
434 
435         filter.addFilter( new ProjectTransitivityFilter( project.getDependencyArtifacts(), this.excludeTransitive ) );
436 
437         filter.addFilter( new ScopeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeScope ),
438                                            DependencyUtil.cleanToBeTokenizedString( this.excludeScope ) ) );
439 
440         filter.addFilter( new TypeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeTypes ),
441                                           DependencyUtil.cleanToBeTokenizedString( this.excludeTypes ) ) );
442 
443         filter.addFilter( new ClassifierFilter( DependencyUtil.cleanToBeTokenizedString( this.includeClassifiers ),
444                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeClassifiers ) ) );
445                                                 
446         filter.addFilter( new ClassifierRegexFilter (
447             DependencyUtil.cleanToBeTokenizedString( this.includeRegexClassifiers ),
448             DependencyUtil.cleanToBeTokenizedString( this.excludeRegexClassifiers ) ) );  
449 
450         filter.addFilter( new GroupIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeGroupIds ),
451                                              DependencyUtil.cleanToBeTokenizedString( this.excludeGroupIds ) ) );
452 
453         filter.addFilter( new ArtifactIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeArtifactIds ),
454                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeArtifactIds ) ) );
455                                                                                
456 
457         // start with all artifacts.
458         @SuppressWarnings( "unchecked" ) Set<Artifact> artifacts = project.getArtifacts();
459 
460         if ( includeParents )
461         {
462             // add dependencies parents
463             for ( Artifact dep : new ArrayList<Artifact>( artifacts ) )
464             {
465                 addParentArtifacts( buildProjectFromArtifact( dep ), artifacts );
466             }
467 
468             // add current project parent
469             addParentArtifacts( project, artifacts );
470         }
471 
472         // perform filtering
473         try
474         {
475             artifacts = filter.filter( artifacts );
476         }
477         catch ( ArtifactFilterException e )
478         {
479             throw new MojoExecutionException( e.getMessage(), e );
480         }
481 
482         // transform artifacts if classifier is set
483         DependencyStatusSets status;
484         if ( StringUtils.isNotEmpty( classifier ) )
485         {
486             status = getClassifierTranslatedDependencies( artifacts, stopOnFailure );
487         }
488         else
489         {
490             status = filterMarkedDependencies( artifacts );
491         }
492 
493         return status;
494     }
495     
496     /**
497      * Main entry into mojo. This method gets the dependencies and iterates
498      * through each one passing it to DependencyUtil.unpackFile().
499      * 
500      *  origin : derived from org.apache.maven.plugin.dependency.fromDependencies.UnpackDependenciesMojo
501      *
502      * @throws MojoExecutionException with a message if an error occurs.
503      * @see #getDependencySets
504      * @see #unpack
505      * @see #listAndFlatCopy
506      */
507     protected void doExecute()
508         throws MojoExecutionException
509     {
510         DependencyStatusSets dss = getDependencySets( this.failOnMissingClassifierArtifact );
511 
512         for ( Artifact artifact : dss.getResolvedDependencies() )
513         {
514             File destDir;
515             destDir = DependencyUtil.getFormattedOutputDirectory( useSubDirectoryPerScope, useSubDirectoryPerType,
516                                                                   useSubDirectoryPerArtifact, useRepositoryLayout,
517                                                                   stripVersion, outputDirectory, artifact );
518 
519             unpack( artifact, destDir, getIncludes(), getExcludes() );
520             DefaultFileMarkerHandler handler = new DefaultFileMarkerHandler( artifact, this.markersDirectory );
521             handler.setMarker();
522             
523             // flat copy part :
524             Iterator it = flattenDestDirs.iterator();
525             HashSet<String> incudedSet = new HashSet<String>();
526             while ( it.hasNext() )
527             {
528                 String flattenDestDir = it.next().toString();
529                 listAndFlatCopy( artifact, destDir, new File( flattenDestDir ), getIncludes(), getExcludes() );
530             }
531 
532         }
533 
534         for ( Artifact artifact : dss.getSkippedDependencies() )
535         {
536             getLog().info( artifact.getFile().getName() + " already exists in destination." );
537         }
538     }
539 
540     protected ArtifactsFilter getMarkedArtifactFilter()
541     {
542         return new MarkerFileFilter( this.overWriteReleases, this.overWriteSnapshots, this.overWriteIfNewer,
543                                      new DefaultFileMarkerHandler( this.markersDirectory ) );
544     }
545 }