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 862013 2013-05-14 22:24:45Z hboutemy $
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      *
185      * @since 2.0
186      */
187     @Parameter( property = "includeArtifactIds", defaultValue = "" )
188     protected String includeArtifactIds;
189 
190     /**
191      * Comma separated list of GroupId Names to exclude.
192      *
193      * @since 2.0
194      */
195     @Parameter( property = "excludeGroupIds", defaultValue = "" )
196     protected String excludeGroupIds;
197 
198     /**
199      * Comma separated list of GroupIds to include.
200      *
201      * @since 2.0
202      */
203     @Parameter( property = "includeGroupIds", defaultValue = "" )
204     protected String includeGroupIds;
205 
206     /**
207      * Directory to store flag files
208      *
209      * @since 2.0
210      */
211     @Parameter( property = "markersDirectory",
212                 defaultValue = "${project.build.directory}/dependency-maven-plugin-markers" )
213     protected File markersDirectory;
214 
215     /**
216      * Prepend the groupId during copy.
217      *
218      * @since 2.2
219      */
220     @Parameter( property = "mdep.prependGroupId", defaultValue = "false" )
221     protected boolean prependGroupId = false;
222 
223     @Component
224     MavenProjectBuilder projectBuilder;
225 
226     /**
227      * Return an {@link ArtifactsFilter} indicating which artifacts must be filtered out.
228      * 
229      * @return an {@link ArtifactsFilter} indicating which artifacts must be filtered out.
230      */
231     protected abstract ArtifactsFilter getMarkedArtifactFilter();
232 
233     /**
234      * Retrieves dependencies, either direct only or all including transitive.
235      *
236      * @return A HashSet of artifacts
237      * @throws MojoExecutionException
238      */
239     protected Set<Artifact> getResolvedDependencies( boolean stopOnFailure )
240         throws MojoExecutionException
241 
242     {
243         DependencyStatusSets status = getDependencySets( stopOnFailure );
244 
245         return status.getResolvedDependencies();
246     }
247 
248     protected DependencyStatusSets getDependencySets( boolean stopOnFailure )
249         throws MojoExecutionException
250     {
251         return getDependencySets( stopOnFailure, false );
252     }
253 
254     /**
255      * Method creates filters and filters the projects dependencies. This method
256      * also transforms the dependencies if classifier is set. The dependencies
257      * are filtered in least specific to most specific order
258      *
259      * @param stopOnFailure
260      * @return DependencyStatusSets - Bean of TreeSets that contains information
261      *         on the projects dependencies
262      * @throws MojoExecutionException
263      */
264     protected DependencyStatusSets getDependencySets( boolean stopOnFailure, boolean includeParents )
265         throws MojoExecutionException
266     {
267         // add filters in well known order, least specific to most specific
268         FilterArtifacts filter = new FilterArtifacts();
269 
270         filter.addFilter( new ProjectTransitivityFilter( project.getDependencyArtifacts(), this.excludeTransitive ) );
271 
272         filter.addFilter( new ScopeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeScope ),
273                                            DependencyUtil.cleanToBeTokenizedString( this.excludeScope ) ) );
274 
275         filter.addFilter( new TypeFilter( DependencyUtil.cleanToBeTokenizedString( this.includeTypes ),
276                                           DependencyUtil.cleanToBeTokenizedString( this.excludeTypes ) ) );
277 
278         filter.addFilter( new ClassifierFilter( DependencyUtil.cleanToBeTokenizedString( this.includeClassifiers ),
279                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeClassifiers ) ) );
280 
281         filter.addFilter( new GroupIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeGroupIds ),
282                                              DependencyUtil.cleanToBeTokenizedString( this.excludeGroupIds ) ) );
283 
284         filter.addFilter( new ArtifactIdFilter( DependencyUtil.cleanToBeTokenizedString( this.includeArtifactIds ),
285                                                 DependencyUtil.cleanToBeTokenizedString( this.excludeArtifactIds ) ) );
286 
287         // start with all artifacts.
288         @SuppressWarnings( "unchecked" ) Set<Artifact> artifacts = project.getArtifacts();
289 
290         if ( includeParents )
291         {
292             // add dependencies parents
293             for ( Artifact dep : new ArrayList<Artifact>( artifacts ) )
294             {
295                 addParentArtifacts( buildProjectFromArtifact( dep ), artifacts );
296             }
297 
298             // add current project parent
299             addParentArtifacts( project, artifacts );
300         }
301 
302         // perform filtering
303         try
304         {
305             artifacts = filter.filter( artifacts );
306         }
307         catch ( ArtifactFilterException e )
308         {
309             throw new MojoExecutionException( e.getMessage(), e );
310         }
311 
312         // transform artifacts if classifier is set
313         DependencyStatusSets status = null;
314         if ( StringUtils.isNotEmpty( classifier ) )
315         {
316             status = getClassifierTranslatedDependencies( artifacts, stopOnFailure );
317         }
318         else
319         {
320             status = filterMarkedDependencies( artifacts );
321         }
322 
323         return status;
324     }
325 
326     private MavenProject buildProjectFromArtifact( Artifact artifact )
327         throws MojoExecutionException
328     {
329         try
330         {
331             return projectBuilder.buildFromRepository( artifact, remoteRepos, getLocal() );
332         }
333         catch ( ProjectBuildingException e )
334         {
335             throw new MojoExecutionException( e.getMessage(), e );
336         }
337     }
338 
339     private void addParentArtifacts( MavenProject project, Set<Artifact> artifacts )
340         throws MojoExecutionException
341     {
342         while ( project.hasParent() )
343         {
344             project = project.getParent();
345 
346             if ( project.getArtifact() == null )
347             {
348                 // Maven 2.x bug
349                 Artifact artifact =
350                     factory.createBuildArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(),
351                                                  project.getPackaging() );
352                 project.setArtifact( artifact );
353             }
354 
355             if ( !artifacts.add( project.getArtifact() ) )
356             {
357                 // artifact already in the set
358                 break;
359             }
360             try
361             {
362                 resolver.resolve( project.getArtifact(), this.remoteRepos, this.getLocal() );
363             }
364             catch ( ArtifactResolutionException e )
365             {
366                 throw new MojoExecutionException( e.getMessage(), e );
367             }
368             catch ( ArtifactNotFoundException e )
369             {
370                 throw new MojoExecutionException( e.getMessage(), e );
371             }
372         }
373     }
374     /**
375      * Transform artifacts
376      *
377      * @param artifacts
378      * @param stopOnFailure
379      * @return DependencyStatusSets - Bean of TreeSets that contains information
380      *         on the projects dependencies
381      * @throws MojoExecutionException
382      */
383     protected DependencyStatusSets getClassifierTranslatedDependencies( Set<Artifact> artifacts, boolean stopOnFailure )
384         throws MojoExecutionException
385     {
386         Set<Artifact> unResolvedArtifacts = new HashSet<Artifact>();
387         Set<Artifact> resolvedArtifacts = artifacts;
388         DependencyStatusSets status = new DependencyStatusSets();
389 
390         // possibly translate artifacts into a new set of artifacts based on the
391         // classifier and type
392         // if this did something, we need to resolve the new artifacts
393         if ( StringUtils.isNotEmpty( classifier ) )
394         {
395             ArtifactTranslator translator = new ClassifierTypeTranslator( this.classifier, this.type, this.factory );
396             artifacts = translator.translate( artifacts, getLog() );
397 
398             status = filterMarkedDependencies( artifacts );
399 
400             // the unskipped artifacts are in the resolved set.
401             artifacts = status.getResolvedDependencies();
402 
403             // resolve the rest of the artifacts
404             ArtifactsResolver artifactsResolver =
405                 new DefaultArtifactsResolver( this.resolver, this.getLocal(), this.remoteRepos, stopOnFailure );
406             resolvedArtifacts = artifactsResolver.resolve( artifacts, getLog() );
407 
408             // calculate the artifacts not resolved.
409             unResolvedArtifacts.addAll( artifacts );
410             unResolvedArtifacts.removeAll( resolvedArtifacts );
411         }
412 
413         // return a bean of all 3 sets.
414         status.setResolvedDependencies( resolvedArtifacts );
415         status.setUnResolvedDependencies( unResolvedArtifacts );
416 
417         return status;
418     }
419 
420     /**
421      * Filter the marked dependencies
422      *
423      * @param artifacts
424      * @return
425      * @throws MojoExecutionException
426      */
427     protected DependencyStatusSets filterMarkedDependencies( Set<Artifact> artifacts )
428         throws MojoExecutionException
429     {
430         // remove files that have markers already
431         FilterArtifacts filter = new FilterArtifacts();
432         filter.clearFilters();
433         filter.addFilter( getMarkedArtifactFilter() );
434 
435         Set<Artifact> unMarkedArtifacts;
436         try
437         {
438             unMarkedArtifacts = filter.filter( artifacts );
439         }
440         catch ( ArtifactFilterException e )
441         {
442             throw new MojoExecutionException( e.getMessage(), e );
443         }
444 
445         // calculate the skipped artifacts
446         Set<Artifact> skippedArtifacts = new HashSet<Artifact>();
447         skippedArtifacts.addAll( artifacts );
448         skippedArtifacts.removeAll( unMarkedArtifacts );
449 
450         return new DependencyStatusSets( unMarkedArtifacts, null, skippedArtifacts );
451     }
452 
453     /**
454      * @return Returns the markersDirectory.
455      */
456     public File getMarkersDirectory()
457     {
458         return this.markersDirectory;
459     }
460 
461     /**
462      * @param theMarkersDirectory The markersDirectory to set.
463      */
464     public void setMarkersDirectory( File theMarkersDirectory )
465     {
466         this.markersDirectory = theMarkersDirectory;
467     }
468 
469     // TODO: Set marker files.
470 
471     /**
472      * @return true, if the groupId should be prepended to the filename.
473      */
474     public boolean isPrependGroupId()
475     {
476         return prependGroupId;
477     }
478 
479     /**
480      * @param prependGroupId -
481      *                       true if the groupId must be prepended during the copy.
482      */
483     public void setPrependGroupId( boolean prependGroupId )
484     {
485         this.prependGroupId = prependGroupId;
486     }
487 }