View Javadoc
1   package org.apache.maven.plugin.dependency.fromDependencies;
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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
24  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
25  import org.apache.maven.plugin.MojoExecutionException;
26  import org.apache.maven.plugin.dependency.AbstractDependencyMojo;
27  import org.apache.maven.plugin.dependency.utils.DependencyStatusSets;
28  import org.apache.maven.plugin.dependency.utils.DependencyUtil;
29  import org.apache.maven.plugin.dependency.utils.resolvers.ArtifactsResolver;
30  import org.apache.maven.plugin.dependency.utils.resolvers.DefaultArtifactsResolver;
31  import org.apache.maven.plugin.dependency.utils.translators.ArtifactTranslator;
32  import org.apache.maven.plugin.dependency.utils.translators.ClassifierTypeTranslator;
33  import org.apache.maven.plugins.annotations.Component;
34  import org.apache.maven.plugins.annotations.Parameter;
35  import org.apache.maven.project.MavenProject;
36  import org.apache.maven.project.MavenProjectBuilder;
37  import org.apache.maven.project.ProjectBuildingException;
38  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
39  import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
40  import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
41  import org.apache.maven.shared.artifact.filter.collection.ClassifierFilter;
42  import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
43  import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
44  import org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
45  import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
46  import org.apache.maven.shared.artifact.filter.collection.TypeFilter;
47  import org.codehaus.plexus.util.StringUtils;
48  
49  import java.io.File;
50  import java.util.ArrayList;
51  import java.util.HashSet;
52  import java.util.Set;
53  
54  /**
55   * Class that encapsulates the plugin parameters, and contains methods that
56   * handle dependency filtering
57   *
58   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
59   * @version $Id: AbstractDependencyFilterMojo.html 937155 2015-01-21 21:53:50Z khmarbaise $
60   * @see org.apache.maven.plugin.dependency.AbstractDependencyMojo
61   */
62  public abstract class AbstractDependencyFilterMojo
63      extends AbstractDependencyMojo
64  {
65      /**
66       * Overwrite release artifacts
67       *
68       * @since 1.0
69       */
70      @Parameter( property = "overWriteReleases", defaultValue = "false" )
71      protected boolean overWriteReleases;
72  
73      /**
74       * Overwrite snapshot artifacts
75       *
76       * @since 1.0
77       */
78      @Parameter( property = "overWriteSnapshots", defaultValue = "false" )
79      protected boolean overWriteSnapshots;
80  
81      /**
82       * Overwrite artifacts that don't exist or are older than the source.
83       *
84       * @since 2.0
85       */
86      @Parameter( property = "overWriteIfNewer", defaultValue = "true" )
87      protected boolean overWriteIfNewer;
88  
89      /**
90       * If we should exclude transitive dependencies
91       *
92       * @since 2.0
93       */
94      @Parameter( property = "excludeTransitive", defaultValue = "false" )
95      protected boolean excludeTransitive;
96  
97      /**
98       * Comma Separated list of Types to include. Empty String indicates include
99       * everything (default).
100      *
101      * @since 2.0
102      */
103     @Parameter( property = "includeTypes", defaultValue = "" )
104     protected String includeTypes;
105 
106     /**
107      * Comma Separated list of Types to exclude. Empty String indicates don't
108      * exclude anything (default).
109      *
110      * @since 2.0
111      */
112     @Parameter( property = "excludeTypes", defaultValue = "" )
113     protected String excludeTypes;
114 
115     /**
116      * Scope to include. An Empty string indicates all scopes (default). The scopes being interpreted are the scopes as
117      * Maven sees them, not as specified in the pom. In summary:
118      * <ul>
119      * <li><code>runtime</code> scope gives runtime and compile dependencies,</li>
120      * <li><code>compile</code> scope gives compile, provided, and system dependencies,</li>
121      * <li><code>test</code> (default) scope gives all dependencies,</li>
122      * <li><code>provided</code> scope just gives provided dependencies,</li>
123      * <li><code>system</code> scope just gives system dependencies.</li>
124      * </ul>
125      * 
126      * @since 2.0
127      */
128     @Parameter( property = "includeScope", defaultValue = "" )
129     protected String includeScope;
130 
131     /**
132      * Scope to exclude. An Empty string indicates no scopes (default).
133      *
134      * @since 2.0
135      */
136     @Parameter( property = "excludeScope", defaultValue = "" )
137     protected String excludeScope;
138 
139     /**
140      * Comma Separated list of Classifiers to include. Empty String indicates
141      * include everything (default).
142      *
143      * @since 2.0
144      */
145     @Parameter( property = "includeClassifiers", defaultValue = "" )
146     protected String includeClassifiers;
147 
148     /**
149      * Comma Separated list of Classifiers to exclude. Empty String indicates
150      * don't exclude anything (default).
151      *
152      * @since 2.0
153      */
154     @Parameter( property = "excludeClassifiers", defaultValue = "" )
155     protected String excludeClassifiers;
156 
157     /**
158      * Specify classifier to look for. Example: sources
159      *
160      * @since 2.0
161      */
162     @Parameter( property = "classifier", defaultValue = "" )
163     protected String classifier;
164 
165     /**
166      * Specify type to look for when constructing artifact based on classifier.
167      * Example: java-source,jar,war
168      *
169      * @since 2.0
170      */
171     @Parameter( property = "type", defaultValue = "" )
172     protected String type;
173 
174     /**
175      * Comma separated list of Artifact names to exclude.
176      *
177      * @since 2.0
178      */
179     @Parameter( property = "excludeArtifactIds", defaultValue = "" )
180     protected String excludeArtifactIds;
181 
182     /**
183      * Comma separated list of Artifact names to include.
184      * Empty String indicates include
185      * everything (default).
186      *
187      * @since 2.0
188      */
189     @Parameter( property = "includeArtifactIds", defaultValue = "" )
190     protected String includeArtifactIds;
191 
192     /**
193      * Comma separated list of GroupId Names to exclude.
194      *
195      * @since 2.0
196      */
197     @Parameter( property = "excludeGroupIds", defaultValue = "" )
198     protected String excludeGroupIds;
199 
200     /**
201      * Comma separated list of GroupIds to include.
202      * Empty String indicates include
203      * everything (default).
204      *
205      * @since 2.0
206      */
207     @Parameter( property = "includeGroupIds", defaultValue = "" )
208     protected String includeGroupIds;
209 
210     /**
211      * Directory to store flag files
212      *
213      * @since 2.0
214      */
215     @Parameter( property = "markersDirectory",
216                 defaultValue = "${project.build.directory}/dependency-maven-plugin-markers" )
217     protected File markersDirectory;
218 
219     /**
220      * Prepend the groupId during copy.
221      *
222      * @since 2.2
223      */
224     @Parameter( property = "mdep.prependGroupId", defaultValue = "false" )
225     protected boolean prependGroupId = false;
226 
227     @Component
228     MavenProjectBuilder projectBuilder;
229 
230     /**
231      * Return an {@link ArtifactsFilter} indicating which artifacts must be filtered out.
232      * 
233      * @return an {@link ArtifactsFilter} indicating which artifacts must be filtered out.
234      */
235     protected abstract ArtifactsFilter getMarkedArtifactFilter();
236 
237     /**
238      * Retrieves dependencies, either direct only or all including transitive.
239      *
240      * @return A HashSet of artifacts
241      * @throws MojoExecutionException
242      */
243     protected Set<Artifact> getResolvedDependencies( boolean stopOnFailure )
244         throws MojoExecutionException
245 
246     {
247         DependencyStatusSets status = getDependencySets( stopOnFailure );
248 
249         return status.getResolvedDependencies();
250     }
251 
252     protected DependencyStatusSets getDependencySets( boolean stopOnFailure )
253         throws MojoExecutionException
254     {
255         return getDependencySets( stopOnFailure, false );
256     }
257 
258     /**
259      * Method creates filters and filters the projects dependencies. This method
260      * also transforms the dependencies if classifier is set. The dependencies
261      * are filtered in least specific to most specific order
262      *
263      * @param stopOnFailure
264      * @return DependencyStatusSets - Bean of TreeSets that contains information
265      *         on the projects dependencies
266      * @throws MojoExecutionException
267      */
268     protected DependencyStatusSets getDependencySets( boolean stopOnFailure, boolean includeParents )
269         throws MojoExecutionException
270     {
271         // add filters in well known order, least specific to most specific
272         FilterArtifacts filter = new FilterArtifacts();
273 
274         filter.addFilter( new ProjectTransitivityFilter( project.getDependencyArtifacts(), this.excludeTransitive ) );
275 
276         filter.addFilter( new ScopeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeScope ),
277                                            DependencyUtil.cleanToBeTokenizedString( this.excludeScope ) ) );
278 
279         filter.addFilter( new TypeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeTypes ),
280                                           DependencyUtil.cleanToBeTokenizedString( this.excludeTypes ) ) );
281 
282         filter.addFilter( new ClassifierFilter( DependencyUtil.cleanToBeTokenizedString( this.includeClassifiers ),
283                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeClassifiers ) ) );
284 
285         filter.addFilter( new GroupIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeGroupIds ),
286                                              DependencyUtil.cleanToBeTokenizedString( this.excludeGroupIds ) ) );
287 
288         filter.addFilter( new ArtifactIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeArtifactIds ),
289                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeArtifactIds ) ) );
290 
291         // start with all artifacts.
292         @SuppressWarnings( "unchecked" ) Set<Artifact> artifacts = project.getArtifacts();
293 
294         if ( includeParents )
295         {
296             // add dependencies parents
297             for ( Artifact dep : new ArrayList<Artifact>( artifacts ) )
298             {
299                 addParentArtifacts( buildProjectFromArtifact( dep ), artifacts );
300             }
301 
302             // add current project parent
303             addParentArtifacts( project, artifacts );
304         }
305 
306         // perform filtering
307         try
308         {
309             artifacts = filter.filter( artifacts );
310         }
311         catch ( ArtifactFilterException e )
312         {
313             throw new MojoExecutionException( e.getMessage(), e );
314         }
315 
316         // transform artifacts if classifier is set
317         DependencyStatusSets status;
318         if ( StringUtils.isNotEmpty( classifier ) )
319         {
320             status = getClassifierTranslatedDependencies( artifacts, stopOnFailure );
321         }
322         else
323         {
324             status = filterMarkedDependencies( artifacts );
325         }
326 
327         return status;
328     }
329 
330     private MavenProject buildProjectFromArtifact( Artifact artifact )
331         throws MojoExecutionException
332     {
333         try
334         {
335             return projectBuilder.buildFromRepository( artifact, remoteRepos, getLocal() );
336         }
337         catch ( ProjectBuildingException e )
338         {
339             throw new MojoExecutionException( e.getMessage(), e );
340         }
341     }
342 
343     private void addParentArtifacts( MavenProject project, Set<Artifact> artifacts )
344         throws MojoExecutionException
345     {
346         while ( project.hasParent() )
347         {
348             project = project.getParent();
349 
350             if ( project.getArtifact() == null )
351             {
352                 // Maven 2.x bug
353                 Artifact artifact =
354                     factory.createBuildArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(),
355                                                  project.getPackaging() );
356                 project.setArtifact( artifact );
357             }
358 
359             if ( !artifacts.add( project.getArtifact() ) )
360             {
361                 // artifact already in the set
362                 break;
363             }
364             try
365             {
366                 resolver.resolve( project.getArtifact(), this.remoteRepos, this.getLocal() );
367             }
368             catch ( ArtifactResolutionException e )
369             {
370                 throw new MojoExecutionException( e.getMessage(), e );
371             }
372             catch ( ArtifactNotFoundException e )
373             {
374                 throw new MojoExecutionException( e.getMessage(), e );
375             }
376         }
377     }
378     /**
379      * Transform artifacts
380      *
381      * @param artifacts
382      * @param stopOnFailure
383      * @return DependencyStatusSets - Bean of TreeSets that contains information
384      *         on the projects dependencies
385      * @throws MojoExecutionException
386      */
387     protected DependencyStatusSets getClassifierTranslatedDependencies( Set<Artifact> artifacts, boolean stopOnFailure )
388         throws MojoExecutionException
389     {
390         Set<Artifact> unResolvedArtifacts = new HashSet<Artifact>();
391         Set<Artifact> resolvedArtifacts = artifacts;
392         DependencyStatusSets status = new DependencyStatusSets();
393 
394         // possibly translate artifacts into a new set of artifacts based on the
395         // classifier and type
396         // if this did something, we need to resolve the new artifacts
397         if ( StringUtils.isNotEmpty( classifier ) )
398         {
399             ArtifactTranslator translator = new ClassifierTypeTranslator( this.classifier, this.type, this.factory );
400             artifacts = translator.translate( artifacts, getLog() );
401 
402             status = filterMarkedDependencies( artifacts );
403 
404             // the unskipped artifacts are in the resolved set.
405             artifacts = status.getResolvedDependencies();
406 
407             // resolve the rest of the artifacts
408             ArtifactsResolver artifactsResolver =
409                 new DefaultArtifactsResolver( this.resolver, this.getLocal(), this.remoteRepos, stopOnFailure );
410             resolvedArtifacts = artifactsResolver.resolve( artifacts, getLog() );
411 
412             // calculate the artifacts not resolved.
413             unResolvedArtifacts.addAll( artifacts );
414             unResolvedArtifacts.removeAll( resolvedArtifacts );
415         }
416 
417         // return a bean of all 3 sets.
418         status.setResolvedDependencies( resolvedArtifacts );
419         status.setUnResolvedDependencies( unResolvedArtifacts );
420 
421         return status;
422     }
423 
424     /**
425      * Filter the marked dependencies
426      *
427      * @param artifacts
428      * @return
429      * @throws MojoExecutionException
430      */
431     protected DependencyStatusSets filterMarkedDependencies( Set<Artifact> artifacts )
432         throws MojoExecutionException
433     {
434         // remove files that have markers already
435         FilterArtifacts filter = new FilterArtifacts();
436         filter.clearFilters();
437         filter.addFilter( getMarkedArtifactFilter() );
438 
439         Set<Artifact> unMarkedArtifacts;
440         try
441         {
442             unMarkedArtifacts = filter.filter( artifacts );
443         }
444         catch ( ArtifactFilterException e )
445         {
446             throw new MojoExecutionException( e.getMessage(), e );
447         }
448 
449         // calculate the skipped artifacts
450         Set<Artifact> skippedArtifacts = new HashSet<Artifact>();
451         skippedArtifacts.addAll( artifacts );
452         skippedArtifacts.removeAll( unMarkedArtifacts );
453 
454         return new DependencyStatusSets( unMarkedArtifacts, null, skippedArtifacts );
455     }
456 
457     /**
458      * @return Returns the markersDirectory.
459      */
460     public File getMarkersDirectory()
461     {
462         return this.markersDirectory;
463     }
464 
465     /**
466      * @param theMarkersDirectory The markersDirectory to set.
467      */
468     public void setMarkersDirectory( File theMarkersDirectory )
469     {
470         this.markersDirectory = theMarkersDirectory;
471     }
472 
473     // TODO: Set marker files.
474 
475     /**
476      * @return true, if the groupId should be prepended to the filename.
477      */
478     public boolean isPrependGroupId()
479     {
480         return prependGroupId;
481     }
482 
483     /**
484      * @param prependGroupId -
485      *                       true if the groupId must be prepended during the copy.
486      */
487     public void setPrependGroupId( boolean prependGroupId )
488     {
489         this.prependGroupId = prependGroupId;
490     }
491 }