001 package org.apache.maven.lifecycle.internal; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import org.apache.maven.artifact.Artifact; 023 import org.apache.maven.artifact.resolver.filter.ArtifactFilter; 024 import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter; 025 import org.apache.maven.execution.ExecutionEvent; 026 import org.apache.maven.execution.MavenSession; 027 import org.apache.maven.lifecycle.LifecycleExecutionException; 028 import org.apache.maven.lifecycle.MissingProjectException; 029 import org.apache.maven.plugin.BuildPluginManager; 030 import org.apache.maven.plugin.MavenPluginManager; 031 import org.apache.maven.plugin.MojoExecution; 032 import org.apache.maven.plugin.MojoExecutionException; 033 import org.apache.maven.plugin.MojoFailureException; 034 import org.apache.maven.plugin.PluginConfigurationException; 035 import org.apache.maven.plugin.PluginIncompatibleException; 036 import org.apache.maven.plugin.PluginManagerException; 037 import org.apache.maven.plugin.descriptor.MojoDescriptor; 038 import org.apache.maven.project.MavenProject; 039 import org.codehaus.plexus.component.annotations.Component; 040 import org.codehaus.plexus.component.annotations.Requirement; 041 import org.codehaus.plexus.util.StringUtils; 042 043 import java.util.ArrayList; 044 import java.util.Arrays; 045 import java.util.Collection; 046 import java.util.Collections; 047 import java.util.List; 048 import java.util.Map; 049 import java.util.Set; 050 import java.util.TreeSet; 051 052 /** 053 * Executes an individual mojo 054 * 055 * @since 3.0 056 * @author Jason van Zyl 057 * @author Benjamin Bentmann 058 * @author Kristian Rosenvold 059 * <p/> 060 * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. 061 */ 062 @Component( role = MojoExecutor.class ) 063 public class MojoExecutor 064 { 065 066 @Requirement 067 private BuildPluginManager pluginManager; 068 069 @Requirement 070 private MavenPluginManager mavenPluginManager; 071 072 @Requirement 073 private LifecycleDependencyResolver lifeCycleDependencyResolver; 074 075 @Requirement 076 private ExecutionEventCatapult eventCatapult; 077 078 public MojoExecutor() 079 { 080 } 081 082 public DependencyContext newDependencyContext( MavenSession session, List<MojoExecution> mojoExecutions ) 083 { 084 Set<String> scopesToCollect = new TreeSet<String>(); 085 Set<String> scopesToResolve = new TreeSet<String>(); 086 087 collectDependencyRequirements( scopesToResolve, scopesToCollect, mojoExecutions ); 088 089 return new DependencyContext( session.getCurrentProject(), scopesToCollect, scopesToResolve ); 090 } 091 092 private void collectDependencyRequirements( Set<String> scopesToResolve, Set<String> scopesToCollect, 093 Collection<MojoExecution> mojoExecutions ) 094 { 095 for ( MojoExecution mojoExecution : mojoExecutions ) 096 { 097 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); 098 099 scopesToResolve.addAll( toScopes( mojoDescriptor.getDependencyResolutionRequired() ) ); 100 101 scopesToCollect.addAll( toScopes( mojoDescriptor.getDependencyCollectionRequired() ) ); 102 } 103 } 104 105 private Collection<String> toScopes( String classpath ) 106 { 107 if ( StringUtils.isNotEmpty( classpath ) ) 108 { 109 if ( Artifact.SCOPE_COMPILE.equals( classpath ) ) 110 { 111 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED ); 112 } 113 else if ( Artifact.SCOPE_RUNTIME.equals( classpath ) ) 114 { 115 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME ); 116 } 117 else if ( Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals( classpath ) ) 118 { 119 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, 120 Artifact.SCOPE_RUNTIME ); 121 } 122 else if ( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals( classpath ) ) 123 { 124 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME ); 125 } 126 else if ( Artifact.SCOPE_TEST.equals( classpath ) ) 127 { 128 return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, 129 Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST ); 130 } 131 } 132 return Collections.emptyList(); 133 } 134 135 public void execute( MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex ) 136 throws LifecycleExecutionException 137 138 { 139 DependencyContext dependencyContext = newDependencyContext( session, mojoExecutions ); 140 141 PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() ); 142 143 for ( MojoExecution mojoExecution : mojoExecutions ) 144 { 145 execute( session, mojoExecution, projectIndex, dependencyContext, phaseRecorder ); 146 } 147 } 148 149 public void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, 150 DependencyContext dependencyContext, PhaseRecorder phaseRecorder ) 151 throws LifecycleExecutionException 152 { 153 execute( session, mojoExecution, projectIndex, dependencyContext ); 154 phaseRecorder.observeExecution( mojoExecution ); 155 } 156 157 @SuppressWarnings( { "ThrowableInstanceNeverThrown" } ) 158 private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, 159 DependencyContext dependencyContext ) 160 throws LifecycleExecutionException 161 { 162 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); 163 164 try 165 { 166 mavenPluginManager.checkRequiredMavenVersion( mojoDescriptor.getPluginDescriptor() ); 167 } 168 catch ( PluginIncompatibleException e ) 169 { 170 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); 171 } 172 173 if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() ) 174 { 175 Throwable cause = 176 new MissingProjectException( "Goal requires a project to execute" 177 + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")." 178 + " Please verify you invoked Maven from the correct directory." ); 179 throw new LifecycleExecutionException( mojoExecution, null, cause ); 180 } 181 182 if ( mojoDescriptor.isOnlineRequired() && session.isOffline() ) 183 { 184 if ( MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) ) 185 { 186 Throwable cause = 187 new IllegalStateException( "Goal requires online mode for execution" 188 + " but Maven is currently offline." ); 189 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), cause ); 190 } 191 else 192 { 193 eventCatapult.fire( ExecutionEvent.Type.MojoSkipped, session, mojoExecution ); 194 195 return; 196 } 197 } 198 199 List<MavenProject> forkedProjects = executeForkedExecutions( mojoExecution, session, projectIndex ); 200 201 ensureDependenciesAreResolved( mojoDescriptor, session, dependencyContext ); 202 203 eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution ); 204 205 try 206 { 207 try 208 { 209 pluginManager.executeMojo( session, mojoExecution ); 210 } 211 catch ( MojoFailureException e ) 212 { 213 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); 214 } 215 catch ( MojoExecutionException e ) 216 { 217 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); 218 } 219 catch ( PluginConfigurationException e ) 220 { 221 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); 222 } 223 catch ( PluginManagerException e ) 224 { 225 throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e ); 226 } 227 228 eventCatapult.fire( ExecutionEvent.Type.MojoSucceeded, session, mojoExecution ); 229 } 230 catch ( LifecycleExecutionException e ) 231 { 232 eventCatapult.fire( ExecutionEvent.Type.MojoFailed, session, mojoExecution, e ); 233 234 throw e; 235 } 236 finally 237 { 238 for ( MavenProject forkedProject : forkedProjects ) 239 { 240 forkedProject.setExecutionProject( null ); 241 } 242 } 243 } 244 245 public void ensureDependenciesAreResolved( MojoDescriptor mojoDescriptor, MavenSession session, 246 DependencyContext dependencyContext ) 247 throws LifecycleExecutionException 248 249 { 250 MavenProject project = dependencyContext.getProject(); 251 boolean aggregating = mojoDescriptor.isAggregator(); 252 253 if ( dependencyContext.isResolutionRequiredForCurrentProject() ) 254 { 255 Collection<String> scopesToCollect = dependencyContext.getScopesToCollectForCurrentProject(); 256 Collection<String> scopesToResolve = dependencyContext.getScopesToResolveForCurrentProject(); 257 258 lifeCycleDependencyResolver.resolveProjectDependencies( project, scopesToCollect, scopesToResolve, session, 259 aggregating, Collections.<Artifact> emptySet() ); 260 261 dependencyContext.synchronizeWithProjectState(); 262 } 263 264 if ( aggregating ) 265 { 266 Collection<String> scopesToCollect = toScopes( mojoDescriptor.getDependencyCollectionRequired() ); 267 Collection<String> scopesToResolve = toScopes( mojoDescriptor.getDependencyResolutionRequired() ); 268 269 if ( dependencyContext.isResolutionRequiredForAggregatedProjects( scopesToCollect, scopesToResolve ) ) 270 { 271 for ( MavenProject aggregatedProject : session.getProjects() ) 272 { 273 if ( aggregatedProject != project ) 274 { 275 lifeCycleDependencyResolver.resolveProjectDependencies( aggregatedProject, scopesToCollect, 276 scopesToResolve, session, aggregating, 277 Collections.<Artifact> emptySet() ); 278 } 279 } 280 } 281 } 282 283 ArtifactFilter artifactFilter = getArtifactFilter( mojoDescriptor ); 284 List<MavenProject> projectsToResolve = 285 LifecycleDependencyResolver.getProjects( session.getCurrentProject(), session, 286 mojoDescriptor.isAggregator() ); 287 for ( MavenProject projectToResolve : projectsToResolve ) 288 { 289 projectToResolve.setArtifactFilter( artifactFilter ); 290 } 291 } 292 293 private ArtifactFilter getArtifactFilter( MojoDescriptor mojoDescriptor ) 294 { 295 String scopeToResolve = mojoDescriptor.getDependencyResolutionRequired(); 296 String scopeToCollect = mojoDescriptor.getDependencyCollectionRequired(); 297 298 List<String> scopes = new ArrayList<String>( 2 ); 299 if ( StringUtils.isNotEmpty( scopeToCollect ) ) 300 { 301 scopes.add( scopeToCollect ); 302 } 303 if ( StringUtils.isNotEmpty( scopeToResolve ) ) 304 { 305 scopes.add( scopeToResolve ); 306 } 307 308 if ( scopes.isEmpty() ) 309 { 310 return null; 311 } 312 else 313 { 314 return new CumulativeScopeArtifactFilter( scopes ); 315 } 316 } 317 318 public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session, 319 ProjectIndex projectIndex ) 320 throws LifecycleExecutionException 321 { 322 List<MavenProject> forkedProjects = Collections.emptyList(); 323 324 Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions(); 325 326 if ( !forkedExecutions.isEmpty() ) 327 { 328 eventCatapult.fire( ExecutionEvent.Type.ForkStarted, session, mojoExecution ); 329 330 MavenProject project = session.getCurrentProject(); 331 332 forkedProjects = new ArrayList<MavenProject>( forkedExecutions.size() ); 333 334 try 335 { 336 for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() ) 337 { 338 String projectId = fork.getKey(); 339 340 int index = projectIndex.getIndices().get( projectId ); 341 342 MavenProject forkedProject = projectIndex.getProjects().get( projectId ); 343 344 forkedProjects.add( forkedProject ); 345 346 MavenProject executedProject = forkedProject.clone(); 347 348 forkedProject.setExecutionProject( executedProject ); 349 350 List<MojoExecution> mojoExecutions = fork.getValue(); 351 352 if ( mojoExecutions.isEmpty() ) 353 { 354 continue; 355 } 356 357 try 358 { 359 session.setCurrentProject( executedProject ); 360 session.getProjects().set( index, executedProject ); 361 projectIndex.getProjects().put( projectId, executedProject ); 362 363 eventCatapult.fire( ExecutionEvent.Type.ForkedProjectStarted, session, mojoExecution ); 364 365 execute( session, mojoExecutions, projectIndex ); 366 367 eventCatapult.fire( ExecutionEvent.Type.ForkedProjectSucceeded, session, mojoExecution ); 368 } 369 catch ( LifecycleExecutionException e ) 370 { 371 eventCatapult.fire( ExecutionEvent.Type.ForkedProjectFailed, session, mojoExecution, e ); 372 373 throw e; 374 } 375 finally 376 { 377 projectIndex.getProjects().put( projectId, forkedProject ); 378 session.getProjects().set( index, forkedProject ); 379 session.setCurrentProject( project ); 380 } 381 } 382 383 eventCatapult.fire( ExecutionEvent.Type.ForkSucceeded, session, mojoExecution ); 384 } 385 catch ( LifecycleExecutionException e ) 386 { 387 eventCatapult.fire( ExecutionEvent.Type.ForkFailed, session, mojoExecution, e ); 388 389 throw e; 390 } 391 } 392 393 return forkedProjects; 394 } 395 }