View Javadoc

1   package org.apache.maven.lifecycle.internal;
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.filter.ArtifactFilter;
24  import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
25  import org.apache.maven.execution.ExecutionEvent;
26  import org.apache.maven.execution.MavenSession;
27  import org.apache.maven.lifecycle.LifecycleExecutionException;
28  import org.apache.maven.lifecycle.MissingProjectException;
29  import org.apache.maven.plugin.BuildPluginManager;
30  import org.apache.maven.plugin.MojoExecution;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.plugin.PluginConfigurationException;
34  import org.apache.maven.plugin.PluginManagerException;
35  import org.apache.maven.plugin.descriptor.MojoDescriptor;
36  import org.apache.maven.project.MavenProject;
37  import org.codehaus.plexus.component.annotations.Component;
38  import org.codehaus.plexus.component.annotations.Requirement;
39  import org.codehaus.plexus.util.StringUtils;
40  
41  import java.util.ArrayList;
42  import java.util.Arrays;
43  import java.util.Collection;
44  import java.util.Collections;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  import java.util.TreeSet;
49  
50  /**
51   * Executes an individual mojo
52   * 
53   * @since 3.0
54   * @author Jason van Zyl
55   * @author Benjamin Bentmann
56   * @author Kristian Rosenvold
57   *         <p/>
58   *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
59   */
60  @Component( role = MojoExecutor.class )
61  public class MojoExecutor
62  {
63  
64      @Requirement
65      private BuildPluginManager pluginManager;
66  
67      @Requirement
68      private LifecycleDependencyResolver lifeCycleDependencyResolver;
69  
70      @Requirement
71      private ExecutionEventCatapult eventCatapult;
72  
73      public MojoExecutor()
74      {
75      }
76  
77      public DependencyContext newDependencyContext( MavenSession session, List<MojoExecution> mojoExecutions )
78      {
79          Set<String> scopesToCollect = new TreeSet<String>();
80          Set<String> scopesToResolve = new TreeSet<String>();
81  
82          collectDependencyRequirements( scopesToResolve, scopesToCollect, mojoExecutions );
83  
84          return new DependencyContext( session.getCurrentProject(), scopesToCollect, scopesToResolve );
85      }
86  
87      private void collectDependencyRequirements( Set<String> scopesToResolve, Set<String> scopesToCollect,
88                                                  Collection<MojoExecution> mojoExecutions )
89      {
90          for ( MojoExecution mojoExecution : mojoExecutions )
91          {
92              MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
93  
94              scopesToResolve.addAll( toScopes( mojoDescriptor.getDependencyResolutionRequired() ) );
95  
96              scopesToCollect.addAll( toScopes( mojoDescriptor.getDependencyCollectionRequired() ) );
97          }
98      }
99  
100     private Collection<String> toScopes( String classpath )
101     {
102         if ( StringUtils.isNotEmpty( classpath ) )
103         {
104             if ( Artifact.SCOPE_COMPILE.equals( classpath ) )
105             {
106                 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED );
107             }
108             else if ( Artifact.SCOPE_RUNTIME.equals( classpath ) )
109             {
110                 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME );
111             }
112             else if ( Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals( classpath ) )
113             {
114                 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED,
115                                       Artifact.SCOPE_RUNTIME );
116             }
117             else if ( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals( classpath ) )
118             {
119                 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME );
120             }
121             else if ( Artifact.SCOPE_TEST.equals( classpath ) )
122             {
123                 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED,
124                                       Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST );
125             }
126         }
127         return Collections.emptyList();
128     }
129 
130     public void execute( MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex )
131         throws LifecycleExecutionException
132 
133     {
134         DependencyContext dependencyContext = newDependencyContext( session, mojoExecutions );
135 
136         PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() );
137 
138         for ( MojoExecution mojoExecution : mojoExecutions )
139         {
140             execute( session, mojoExecution, projectIndex, dependencyContext, phaseRecorder );
141         }
142     }
143 
144     public void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
145                          DependencyContext dependencyContext, PhaseRecorder phaseRecorder )
146         throws LifecycleExecutionException
147     {
148         execute( session, mojoExecution, projectIndex, dependencyContext );
149         phaseRecorder.observeExecution( mojoExecution );
150     }
151 
152     @SuppressWarnings( { "ThrowableInstanceNeverThrown" } )
153     private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
154                           DependencyContext dependencyContext )
155         throws LifecycleExecutionException
156     {
157         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
158 
159         if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
160         {
161             Throwable cause =
162                 new MissingProjectException( "Goal requires a project to execute"
163                     + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")."
164                     + " Please verify you invoked Maven from the correct directory." );
165             throw new LifecycleExecutionException( mojoExecution, null, cause );
166         }
167 
168         if ( mojoDescriptor.isOnlineRequired() && session.isOffline() )
169         {
170             if ( MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) )
171             {
172                 Throwable cause =
173                     new IllegalStateException( "Goal requires online mode for execution"
174                         + " but Maven is currently offline." );
175                 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), cause );
176             }
177             else
178             {
179                 eventCatapult.fire( ExecutionEvent.Type.MojoSkipped, session, mojoExecution );
180 
181                 return;
182             }
183         }
184 
185         List<MavenProject> forkedProjects = executeForkedExecutions( mojoExecution, session, projectIndex );
186 
187         ensureDependenciesAreResolved( mojoDescriptor, session, dependencyContext );
188 
189         eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution );
190 
191         try
192         {
193             try
194             {
195                 pluginManager.executeMojo( session, mojoExecution );
196             }
197             catch ( MojoFailureException e )
198             {
199                 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
200             }
201             catch ( MojoExecutionException e )
202             {
203                 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
204             }
205             catch ( PluginConfigurationException e )
206             {
207                 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
208             }
209             catch ( PluginManagerException e )
210             {
211                 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
212             }
213 
214             eventCatapult.fire( ExecutionEvent.Type.MojoSucceeded, session, mojoExecution );
215         }
216         catch ( LifecycleExecutionException e )
217         {
218             eventCatapult.fire( ExecutionEvent.Type.MojoFailed, session, mojoExecution );
219 
220             throw e;
221         }
222         finally
223         {
224             for ( MavenProject forkedProject : forkedProjects )
225             {
226                 forkedProject.setExecutionProject( null );
227             }
228         }
229     }
230 
231     private void ensureDependenciesAreResolved( MojoDescriptor mojoDescriptor, MavenSession session,
232                                                 DependencyContext dependencyContext )
233         throws LifecycleExecutionException
234 
235     {
236         MavenProject project = dependencyContext.getProject();
237         boolean aggregating = mojoDescriptor.isAggregator();
238 
239         if ( dependencyContext.isResolutionRequiredForCurrentProject() )
240         {
241             Collection<String> scopesToCollect = dependencyContext.getScopesToCollectForCurrentProject();
242             Collection<String> scopesToResolve = dependencyContext.getScopesToResolveForCurrentProject();
243 
244             lifeCycleDependencyResolver.resolveProjectDependencies( project, scopesToCollect, scopesToResolve, session,
245                                                                     aggregating, Collections.<Artifact> emptySet() );
246 
247             dependencyContext.synchronizeWithProjectState();
248         }
249 
250         if ( aggregating )
251         {
252             Collection<String> scopesToCollect = toScopes( mojoDescriptor.getDependencyCollectionRequired() );
253             Collection<String> scopesToResolve = toScopes( mojoDescriptor.getDependencyResolutionRequired() );
254 
255             if ( dependencyContext.isResolutionRequiredForAggregatedProjects( scopesToCollect, scopesToResolve ) )
256             {
257                 for ( MavenProject aggregatedProject : session.getProjects() )
258                 {
259                     if ( aggregatedProject != project )
260                     {
261                         lifeCycleDependencyResolver.resolveProjectDependencies( aggregatedProject, scopesToCollect,
262                                                                                 scopesToResolve, session, aggregating,
263                                                                                 Collections.<Artifact> emptySet() );
264                     }
265                 }
266             }
267         }
268 
269         ArtifactFilter artifactFilter = getArtifactFilter( mojoDescriptor );
270         List<MavenProject> projectsToResolve =
271             LifecycleDependencyResolver.getProjects( session.getCurrentProject(), session,
272                                                      mojoDescriptor.isAggregator() );
273         for ( MavenProject projectToResolve : projectsToResolve )
274         {
275             projectToResolve.setArtifactFilter( artifactFilter );
276         }
277     }
278 
279     private ArtifactFilter getArtifactFilter( MojoDescriptor mojoDescriptor )
280     {
281         String scopeToResolve = mojoDescriptor.getDependencyResolutionRequired();
282         String scopeToCollect = mojoDescriptor.getDependencyCollectionRequired();
283 
284         List<String> scopes = new ArrayList<String>( 2 );
285         if ( StringUtils.isNotEmpty( scopeToCollect ) )
286         {
287             scopes.add( scopeToCollect );
288         }
289         if ( StringUtils.isNotEmpty( scopeToResolve ) )
290         {
291             scopes.add( scopeToResolve );
292         }
293 
294         if ( scopes.isEmpty() )
295         {
296             return null;
297         }
298         else
299         {
300             return new CumulativeScopeArtifactFilter( scopes );
301         }
302     }
303 
304     public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session,
305                                                        ProjectIndex projectIndex )
306         throws LifecycleExecutionException
307     {
308         List<MavenProject> forkedProjects = Collections.emptyList();
309 
310         Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
311 
312         if ( !forkedExecutions.isEmpty() )
313         {
314             eventCatapult.fire( ExecutionEvent.Type.ForkStarted, session, mojoExecution );
315 
316             MavenProject project = session.getCurrentProject();
317 
318             forkedProjects = new ArrayList<MavenProject>( forkedExecutions.size() );
319 
320             try
321             {
322                 for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
323                 {
324                     String projectId = fork.getKey();
325 
326                     int index = projectIndex.getIndices().get( projectId );
327 
328                     MavenProject forkedProject = projectIndex.getProjects().get( projectId );
329 
330                     forkedProjects.add( forkedProject );
331 
332                     MavenProject executedProject = forkedProject.clone();
333 
334                     forkedProject.setExecutionProject( executedProject );
335 
336                     List<MojoExecution> mojoExecutions = fork.getValue();
337 
338                     if ( mojoExecutions.isEmpty() )
339                     {
340                         continue;
341                     }
342 
343                     try
344                     {
345                         session.setCurrentProject( executedProject );
346                         session.getProjects().set( index, executedProject );
347                         projectIndex.getProjects().put( projectId, executedProject );
348 
349                         eventCatapult.fire( ExecutionEvent.Type.ForkedProjectStarted, session, mojoExecution );
350 
351                         execute( session, mojoExecutions, projectIndex );
352 
353                         eventCatapult.fire( ExecutionEvent.Type.ForkedProjectSucceeded, session, mojoExecution );
354                     }
355                     catch ( LifecycleExecutionException e )
356                     {
357                         eventCatapult.fire( ExecutionEvent.Type.ForkedProjectFailed, session, mojoExecution );
358 
359                         throw e;
360                     }
361                     finally
362                     {
363                         projectIndex.getProjects().put( projectId, forkedProject );
364                         session.getProjects().set( index, forkedProject );
365                         session.setCurrentProject( project );
366                     }
367                 }
368 
369                 eventCatapult.fire( ExecutionEvent.Type.ForkSucceeded, session, mojoExecution );
370             }
371             catch ( LifecycleExecutionException e )
372             {
373                 eventCatapult.fire( ExecutionEvent.Type.ForkFailed, session, mojoExecution );
374 
375                 throw e;
376             }
377         }
378 
379         return forkedProjects;
380     }
381 }