| package org.apache.maven.lifecycle; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.maven.BuildFailureException; |
| import org.apache.maven.ConfigurationInterpolationException; |
| import org.apache.maven.ConfigurationInterpolator; |
| import org.apache.maven.artifact.handler.ArtifactHandler; |
| import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; |
| import org.apache.maven.artifact.resolver.ArtifactNotFoundException; |
| import org.apache.maven.artifact.resolver.ArtifactResolutionException; |
| import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; |
| import org.apache.maven.execution.MavenSession; |
| import org.apache.maven.execution.ReactorManager; |
| import org.apache.maven.extension.ExtensionManager; |
| import org.apache.maven.lifecycle.mapping.LifecycleMapping; |
| import org.apache.maven.model.Extension; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.model.PluginExecution; |
| import org.apache.maven.model.ReportPlugin; |
| import org.apache.maven.model.ReportSet; |
| import org.apache.maven.monitor.event.EventDispatcher; |
| import org.apache.maven.monitor.event.MavenEvents; |
| import org.apache.maven.plugin.InvalidPluginException; |
| import org.apache.maven.plugin.MojoExecution; |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugin.MojoFailureException; |
| import org.apache.maven.plugin.PluginConfigurationException; |
| import org.apache.maven.plugin.PluginManager; |
| import org.apache.maven.plugin.PluginManagerException; |
| import org.apache.maven.plugin.PluginNotFoundException; |
| import org.apache.maven.plugin.descriptor.MojoDescriptor; |
| import org.apache.maven.plugin.descriptor.PluginDescriptor; |
| import org.apache.maven.plugin.lifecycle.Execution; |
| import org.apache.maven.plugin.lifecycle.Phase; |
| import org.apache.maven.plugin.version.PluginVersionNotFoundException; |
| import org.apache.maven.plugin.version.PluginVersionResolutionException; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.maven.project.MavenProjectBuilder; |
| import org.apache.maven.project.artifact.InvalidDependencyVersionException; |
| import org.apache.maven.project.interpolation.ModelInterpolationException; |
| import org.apache.maven.project.interpolation.ModelInterpolator; |
| import org.apache.maven.reporting.MavenReport; |
| import org.apache.maven.settings.Settings; |
| import org.codehaus.plexus.PlexusConstants; |
| import org.codehaus.plexus.PlexusContainer; |
| import org.codehaus.plexus.PlexusContainerException; |
| import org.codehaus.plexus.component.repository.exception.ComponentLookupException; |
| import org.codehaus.plexus.configuration.PlexusConfiguration; |
| import org.codehaus.plexus.context.Context; |
| import org.codehaus.plexus.context.ContextException; |
| import org.codehaus.plexus.logging.AbstractLogEnabled; |
| import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; |
| import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable; |
| import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException; |
| import org.codehaus.plexus.util.StringUtils; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| import org.codehaus.plexus.util.xml.pull.XmlPullParserException; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| import java.util.StringTokenizer; |
| |
| /** |
| * @author <a href="mailto:jason@maven.org">Jason van Zyl</a> |
| * @author <a href="mailto:brett@apache.org">Brett Porter</a> |
| * @version $Id$ |
| * @todo because of aggregation, we ended up with cli-ish stuff in here (like line() and the project logging, without much of the event handling) |
| */ |
| public class DefaultLifecycleExecutor |
| extends AbstractLogEnabled |
| implements LifecycleExecutor, Initializable, Contextualizable |
| { |
| // ---------------------------------------------------------------------- |
| // Components |
| // ---------------------------------------------------------------------- |
| |
| private PluginManager pluginManager; |
| |
| private ExtensionManager extensionManager; |
| |
| private List lifecycles; |
| |
| private ArtifactHandlerManager artifactHandlerManager; |
| |
| private List defaultReports; |
| |
| private Map phaseToLifecycleMap; |
| |
| private MavenProjectBuilder mavenProjectBuilder; |
| |
| private ModelInterpolator modelInterpolator; |
| |
| private ConfigurationInterpolator configInterpolator; |
| |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| /** |
| * Execute a task. Each task may be a phase in the lifecycle or the |
| * execution of a mojo. |
| * |
| * @param session |
| * @param rm |
| * @param dispatcher |
| */ |
| public void execute( final MavenSession session, final ReactorManager rm, final EventDispatcher dispatcher ) |
| throws BuildFailureException, LifecycleExecutionException |
| { |
| // TODO: This is dangerous, particularly when it's just a collection of loose-leaf projects being built |
| // within the same reactor (using an inclusion pattern to gather them up)... |
| MavenProject rootProject = rm.getTopLevelProject(); |
| |
| List goals = session.getGoals(); |
| |
| if ( goals.isEmpty() && rootProject != null ) |
| { |
| String goal = rootProject.getDefaultGoal(); |
| |
| if ( goal != null ) |
| { |
| goals = Collections.singletonList( goal ); |
| } |
| } |
| |
| if ( goals.isEmpty() ) |
| { |
| StringBuffer buffer = new StringBuffer( 1024 ); |
| |
| buffer.append( "\n\n" ); |
| buffer.append( "You must specify at least one goal or lifecycle phase to perform build steps.\n" ); |
| buffer.append( "The following list illustrates some commonly used build commands:\n\n" ); |
| buffer.append( " mvn clean\n" ); |
| buffer.append( " Deletes any build output (e.g. class files or JARs).\n" ); |
| buffer.append( " mvn test\n" ); |
| buffer.append( " Runs the unit tests for the project.\n" ); |
| buffer.append( " mvn install\n" ); |
| buffer.append( " Copies the project artifacts into your local repository.\n" ); |
| buffer.append( " mvn deploy\n" ); |
| buffer.append( " Copies the project artifacts into the remote repository.\n" ); |
| buffer.append( " mvn site\n" ); |
| buffer.append( " Creates project documentation (e.g. reports or Javadoc).\n\n" ); |
| buffer.append( "Please see\n" ); |
| buffer.append( "http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html\n" ); |
| buffer.append( "for a complete description of available lifecycle phases.\n\n" ); |
| buffer.append( "Use \"mvn --help\" to show general usage information about Maven's command line.\n\n" ); |
| |
| throw new BuildFailureException( buffer.toString() ); |
| } |
| |
| List taskSegments = segmentTaskListByAggregationNeeds( goals, session, rootProject ); |
| |
| // TODO: probably don't want to do all this up front |
| findExtensions( session ); |
| |
| executeTaskSegments( taskSegments, rm, session, rootProject, dispatcher ); |
| } |
| |
| private void findExtensions( final MavenSession session ) |
| throws LifecycleExecutionException |
| { |
| // TODO: MNG-4081. What about extensions within the current reactor?? |
| Map<String, ArtifactHandler> handlers = new HashMap<String, ArtifactHandler>(); |
| for ( MavenProject project : session.getSortedProjects() ) |
| { |
| for ( Iterator j = project.getBuildExtensions().iterator(); j.hasNext(); ) |
| { |
| Extension extension = (Extension) j.next(); |
| try |
| { |
| getLogger().debug( "Adding extension: " + extension ); |
| extensionManager.addExtension( extension, project, session.getProjectBuilderConfiguration() ); |
| } |
| catch ( PlexusContainerException e ) |
| { |
| throw new LifecycleExecutionException( "Unable to initialise extensions", e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| } |
| |
| } |
| |
| extensionManager.registerWagons(); |
| |
| handlers.putAll( extensionManager.getArtifactTypeHandlers() ); |
| |
| for ( MavenProject project : session.getSortedProjects() ) |
| { |
| try |
| { |
| handlers.putAll( findArtifactTypeHandlersInPlugins( project, session ) ); |
| |
| // shudder... |
| for ( ArtifactHandler handler : handlers.values() ) |
| { |
| if ( project.getPackaging().equals( handler.getPackaging() ) ) |
| { |
| project.getArtifact().setArtifactHandler( handler ); |
| |
| // NOTE: Adding this (maven 2.2.1) to short-circuit things. This means first match is used, NOT LAST. |
| break; |
| } |
| } |
| } |
| catch ( PluginNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| } |
| |
| artifactHandlerManager.addHandlers( handlers ); |
| } |
| |
| private void executeTaskSegments( final List taskSegments, final ReactorManager rm, final MavenSession session, |
| final MavenProject rootProject, final EventDispatcher dispatcher ) |
| throws LifecycleExecutionException, BuildFailureException |
| { |
| for ( Iterator it = taskSegments.iterator(); it.hasNext(); ) |
| { |
| TaskSegment segment = (TaskSegment) it.next(); |
| |
| if ( segment.aggregate() ) |
| { |
| if ( !rm.isBlackListed( rootProject ) ) |
| { |
| line(); |
| |
| getLogger().info( "Building " + rootProject.getName() ); |
| |
| getLogger().info( " " + segment ); |
| |
| line(); |
| |
| // !! This is ripe for refactoring to an aspect. |
| // Event monitoring. |
| String event = MavenEvents.PROJECT_EXECUTION; |
| |
| long buildStartTime = System.currentTimeMillis(); |
| |
| String target = rootProject.getId() + " ( " + segment + " )"; |
| |
| dispatcher.dispatchStart( event, target ); |
| |
| try |
| { |
| session.setCurrentProject( rootProject ); |
| |
| // only call once, with the top-level project (assumed to be provided as a parameter)... |
| for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); ) |
| { |
| String task = (String) goalIterator.next(); |
| |
| executeGoalAndHandleFailures( task, session, rootProject, dispatcher, event, rm, buildStartTime, |
| target ); |
| } |
| |
| rm.registerBuildSuccess( rootProject, System.currentTimeMillis() - buildStartTime ); |
| |
| } |
| finally |
| { |
| session.setCurrentProject( null ); |
| } |
| |
| dispatcher.dispatchEnd( event, target ); |
| } |
| else |
| { |
| line(); |
| |
| getLogger().info( "SKIPPING " + rootProject.getName() ); |
| |
| getLogger().info( " " + segment ); |
| |
| getLogger().info( |
| "This project has been banned from further executions due to previous failures." ); |
| |
| line(); |
| } |
| } |
| else |
| { |
| List sortedProjects = session.getSortedProjects(); |
| |
| // iterate over projects, and execute on each... |
| for ( Iterator projectIterator = sortedProjects.iterator(); projectIterator.hasNext(); ) |
| { |
| MavenProject currentProject = (MavenProject) projectIterator.next(); |
| |
| if ( !rm.isBlackListed( currentProject ) ) |
| { |
| line(); |
| |
| getLogger().info( "Building " + currentProject.getName() ); |
| |
| getLogger().info( " " + segment ); |
| |
| line(); |
| |
| // !! This is ripe for refactoring to an aspect. |
| // Event monitoring. |
| String event = MavenEvents.PROJECT_EXECUTION; |
| |
| long buildStartTime = System.currentTimeMillis(); |
| |
| String target = currentProject.getId() + " ( " + segment + " )"; |
| dispatcher.dispatchStart( event, target ); |
| |
| try |
| { |
| session.setCurrentProject( currentProject ); |
| |
| for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); ) |
| { |
| String task = (String) goalIterator.next(); |
| |
| executeGoalAndHandleFailures( task, session, currentProject, dispatcher, event, rm, |
| buildStartTime, target ); |
| } |
| |
| } |
| finally |
| { |
| session.setCurrentProject( null ); |
| } |
| |
| rm.registerBuildSuccess( currentProject, System.currentTimeMillis() - buildStartTime ); |
| |
| dispatcher.dispatchEnd( event, target ); |
| } |
| else |
| { |
| line(); |
| |
| getLogger().info( "SKIPPING " + currentProject.getName() ); |
| |
| getLogger().info( " " + segment ); |
| |
| getLogger().info( |
| "This project has been banned from further executions due to previous failures." ); |
| |
| line(); |
| } |
| } |
| } |
| } |
| } |
| |
| private void executeGoalAndHandleFailures( final String task, final MavenSession session, final MavenProject project, |
| final EventDispatcher dispatcher, final String event, final ReactorManager rm, |
| final long buildStartTime, final String target ) |
| throws BuildFailureException, LifecycleExecutionException |
| { |
| try |
| { |
| executeGoal( task, session, project ); |
| } |
| catch ( LifecycleExecutionException e ) |
| { |
| dispatcher.dispatchError( event, target, e ); |
| |
| if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) ) |
| { |
| throw e; |
| } |
| } |
| catch ( BuildFailureException e ) |
| { |
| dispatcher.dispatchError( event, target, e ); |
| |
| if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) ) |
| { |
| throw e; |
| } |
| } |
| } |
| |
| private boolean handleExecutionFailure( final ReactorManager rm, final MavenProject project, final Exception e, final String task, |
| final long buildStartTime ) |
| { |
| rm.registerBuildFailure( project, e, task, System.currentTimeMillis() - buildStartTime ); |
| |
| if ( ReactorManager.FAIL_FAST.equals( rm.getFailureBehavior() ) ) |
| { |
| return true; |
| } |
| else if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) ) |
| { |
| rm.blackList( project ); |
| } |
| // if NEVER, don't blacklist |
| return false; |
| } |
| |
| private List segmentTaskListByAggregationNeeds( final List tasks, final MavenSession session, final MavenProject project ) |
| throws LifecycleExecutionException, BuildFailureException |
| { |
| List segments = new ArrayList(); |
| |
| if ( project != null ) |
| { |
| |
| TaskSegment currentSegment = null; |
| for ( Iterator it = tasks.iterator(); it.hasNext(); ) |
| { |
| String task = (String) it.next(); |
| |
| // if it's a phase, then we don't need to check whether it's an aggregator. |
| // simply add it to the current task partition. |
| if ( getPhaseToLifecycleMap().containsKey( task ) ) |
| { |
| if ( currentSegment != null && currentSegment.aggregate() ) |
| { |
| segments.add( currentSegment ); |
| currentSegment = null; |
| } |
| |
| if ( currentSegment == null ) |
| { |
| currentSegment = new TaskSegment(); |
| } |
| |
| currentSegment.add( task ); |
| } |
| else |
| { |
| MojoDescriptor mojo = null; |
| try |
| { |
| // definitely a CLI goal, can use prefix |
| mojo = getMojoDescriptor( task, session, project, task, true, false ); |
| } |
| catch ( PluginNotFoundException e ) |
| { |
| // TODO: shouldn't hit this, investigate using the same resolution logic as otheres for plugins in the reactor |
| getLogger().info( |
| "Cannot find mojo descriptor for: \'" + task + "\' - Treating as non-aggregator." ); |
| getLogger().debug( "", e ); |
| } |
| |
| // if the mojo descriptor was found, determine aggregator status according to: |
| // 1. whether the mojo declares itself an aggregator |
| // 2. whether the mojo DOES NOT require a project to function (implicitly avoid reactor) |
| if ( mojo != null && ( mojo.isAggregator() || !mojo.isProjectRequired() ) ) |
| { |
| if ( currentSegment != null && !currentSegment.aggregate() ) |
| { |
| segments.add( currentSegment ); |
| currentSegment = null; |
| } |
| |
| if ( currentSegment == null ) |
| { |
| currentSegment = new TaskSegment( true ); |
| } |
| |
| currentSegment.add( task ); |
| } |
| else |
| { |
| if ( currentSegment != null && currentSegment.aggregate() ) |
| { |
| segments.add( currentSegment ); |
| currentSegment = null; |
| } |
| |
| if ( currentSegment == null ) |
| { |
| currentSegment = new TaskSegment(); |
| } |
| |
| currentSegment.add( task ); |
| } |
| } |
| } |
| |
| segments.add( currentSegment ); |
| } |
| else |
| { |
| TaskSegment segment = new TaskSegment( false ); |
| for ( Iterator i = tasks.iterator(); i.hasNext(); ) |
| { |
| segment.add( (String) i.next() ); |
| } |
| segments.add( segment ); |
| } |
| |
| return segments; |
| } |
| |
| private void executeGoal( final String task, final MavenSession session, final MavenProject project ) |
| throws LifecycleExecutionException, BuildFailureException |
| { |
| try |
| { |
| Stack forkEntryPoints = new Stack(); |
| if ( getPhaseToLifecycleMap().containsKey( task ) ) |
| { |
| Lifecycle lifecycle = getLifecycleForPhase( task ); |
| |
| // we have a lifecycle phase, so lets bind all the necessary goals |
| Map lifecycleMappings = constructLifecycleMappings( session, task, project, lifecycle ); |
| executeGoalWithLifecycle( task, forkEntryPoints, session, lifecycleMappings, project, lifecycle ); |
| } |
| else |
| { |
| executeStandaloneGoal( task, forkEntryPoints, session, project ); |
| } |
| } |
| catch ( PluginNotFoundException e ) |
| { |
| throw new BuildFailureException( "A required plugin was not found: " + e.getMessage(), e ); |
| } |
| } |
| |
| private void executeGoalWithLifecycle( final String task, final Stack forkEntryPoints, final MavenSession session, |
| final Map lifecycleMappings, final MavenProject project, final Lifecycle lifecycle ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| List goals = processGoalChain( task, lifecycleMappings, lifecycle ); |
| |
| if ( !goals.isEmpty() ) |
| { |
| executeGoals( goals, forkEntryPoints, session, project ); |
| } |
| else |
| { |
| getLogger().info( "No goals needed for project - skipping" ); |
| } |
| } |
| |
| private void executeStandaloneGoal( final String task, final Stack forkEntryPoints, final MavenSession session, final MavenProject project ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| // guaranteed to come from the CLI and not be part of a phase |
| MojoDescriptor mojoDescriptor = getMojoDescriptor( task, session, project, task, true, false ); |
| executeGoals( Collections.singletonList( new MojoExecution( mojoDescriptor, MojoExecution.CLI_EXECUTION_ID ) ), |
| forkEntryPoints, session, project ); |
| } |
| |
| private void executeGoals( final List goals, final Stack forkEntryPoints, final MavenSession session, final MavenProject project ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| for ( Iterator i = goals.iterator(); i.hasNext(); ) |
| { |
| MojoExecution mojoExecution = (MojoExecution) i.next(); |
| |
| MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); |
| |
| PlexusConfiguration configuration = mojoDescriptor.getMojoConfiguration(); |
| boolean usesReactorProjects = mojoDescriptor.isAggregator() || usesSessionOrReactorProjects( configuration ); |
| |
| if ( usesReactorProjects ) |
| { |
| calculateAllConcreteStates( session ); |
| } |
| else |
| { |
| calculateConcreteState( project, session, true ); |
| } |
| |
| calculateConcreteConfiguration( mojoExecution, project, session ); |
| |
| List reportExecutions = null; |
| if ( mojoDescriptor.isRequiresReports() ) |
| { |
| reportExecutions = getReportExecutions( project, forkEntryPoints, mojoExecution, session ); |
| } |
| |
| boolean hasFork = false; |
| if ( mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null ) |
| { |
| hasFork = true; |
| } |
| else if ( reportExecutions != null ) |
| { |
| for ( Iterator it = reportExecutions.iterator(); it.hasNext(); ) |
| { |
| MojoExecution reportExecution = (MojoExecution) it.next(); |
| MojoDescriptor reportDescriptor = reportExecution.getMojoDescriptor(); |
| if ( reportDescriptor.getExecutePhase() != null || reportDescriptor.getExecuteGoal() != null ) |
| { |
| hasFork = true; |
| } |
| } |
| } |
| |
| if ( hasFork ) |
| { |
| // NOTE: This must always happen, regardless of treatment of reactorProjects below, because |
| // if we're in a forked execution right now, the current project will itself be an execution project of |
| // something in the reactorProjects list, and won't have a next-stage executionProject created |
| // for it otherwise, which leaves the project == null for the upcoming forked execution. |
| createExecutionProject( project, session, true ); |
| |
| if ( usesReactorProjects ) |
| { |
| List reactorProjects = session.getSortedProjects(); |
| for ( Iterator it = reactorProjects.iterator(); it.hasNext(); ) |
| { |
| MavenProject reactorProject = (MavenProject) it.next(); |
| createExecutionProject( reactorProject, session, false ); |
| } |
| } |
| } |
| |
| if ( mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null ) |
| { |
| forkEntryPoints.push( mojoDescriptor ); |
| |
| forkLifecycle( mojoDescriptor, forkEntryPoints, session, project, mojoExecution.getExecutionId() ); |
| |
| forkEntryPoints.pop(); |
| } |
| |
| if ( mojoDescriptor.isRequiresReports() ) |
| { |
| List reports = getReports( reportExecutions, project, mojoExecution, session ); |
| |
| mojoExecution.setReports( reports ); |
| |
| for ( Iterator j = mojoExecution.getForkedExecutions().iterator(); j.hasNext(); ) |
| { |
| MojoExecution forkedExecution = (MojoExecution) j.next(); |
| MojoDescriptor descriptor = forkedExecution.getMojoDescriptor(); |
| |
| if ( descriptor.getExecutePhase() != null ) |
| { |
| forkEntryPoints.push( descriptor ); |
| |
| forkLifecycle( descriptor, forkEntryPoints, session, project, forkedExecution.getExecutionId() ); |
| |
| forkEntryPoints.pop(); |
| } |
| } |
| } |
| |
| if ( hasFork ) |
| { |
| // NOTE: This must always happen, regardless of treatment of reactorProjects below, because |
| // if we're in a forked execution right now, the current project will itself be an execution project of |
| // something in the reactorProjects list, and may not have had its own executionProject instance reset to |
| // a concrete state again after the previous forked executions. |
| calculateConcreteState( project.getExecutionProject(), session, true ); |
| |
| // FIXME: Would be nice to find a way to cause the execution project to stay in a concrete state... |
| // TODO: Test this! It should be fixed, but I don't want to destabilize until I have the issue I'm working on fixed. |
| if ( usesReactorProjects ) |
| { |
| calculateAllConcreteStates( session ); |
| List reactorProjects = session.getSortedProjects(); |
| for ( Iterator it = reactorProjects.iterator(); it.hasNext(); ) |
| { |
| MavenProject reactorProject = (MavenProject) it.next(); |
| calculateConcreteState( reactorProject.getExecutionProject(), session, false ); |
| } |
| } |
| } |
| |
| try |
| { |
| pluginManager.executeMojo( project, mojoExecution, session ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( "Internal error in the plugin manager executing goal '" + |
| mojoDescriptor.getId() + "': " + e.getMessage(), e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidDependencyVersionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( MojoFailureException e ) |
| { |
| throw new BuildFailureException( e.getMessage(), e ); |
| } |
| catch ( MojoExecutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( PluginConfigurationException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| } |
| } |
| |
| private void createExecutionProject( final MavenProject project, final MavenSession session, final boolean processProjectReferences ) |
| throws LifecycleExecutionException |
| { |
| MavenProject executionProject = new MavenProject( project ); |
| |
| calculateConcreteState( executionProject, session, processProjectReferences ); |
| |
| project.setExecutionProject( executionProject ); |
| } |
| |
| private boolean usesSessionOrReactorProjects( final PlexusConfiguration configuration ) |
| { |
| String value = configuration != null ? String.valueOf( configuration ) : null; |
| |
| if ( value != null ) |
| { |
| if ( value.indexOf( "${session" ) > -1 || value.indexOf( "${reactorProjects}" ) > -1 ) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private void calculateConcreteConfiguration( final MojoExecution mojoExecution, final MavenProject project, final MavenSession session ) |
| throws LifecycleExecutionException |
| { |
| if ( mojoExecution.getConfiguration() == null ) |
| { |
| return; |
| } |
| |
| try |
| { |
| mojoExecution.setConfiguration( (Xpp3Dom) configInterpolator.interpolate( |
| mojoExecution.getConfiguration(), |
| project, |
| session.getProjectBuilderConfiguration() ) ); |
| } |
| catch ( ConfigurationInterpolationException e ) |
| { |
| throw new LifecycleExecutionException( "Error interpolating configuration for: '" + mojoExecution.getMojoDescriptor().getRoleHint() + |
| "' (execution: '" + mojoExecution.getExecutionId() + "')", e ); |
| } |
| } |
| |
| private void calculateAllConcreteStates( final MavenSession session ) |
| throws LifecycleExecutionException |
| { |
| List projects = session.getSortedProjects(); |
| if ( projects != null ) |
| { |
| for ( Iterator it = projects.iterator(); it.hasNext(); ) |
| { |
| calculateConcreteState( (MavenProject) it.next(), session, false ); |
| } |
| } |
| } |
| |
| private void calculateConcreteState( final MavenProject project, final MavenSession session, final boolean processReferences ) |
| throws LifecycleExecutionException |
| { |
| if ( mavenProjectBuilder != null && project != null ) |
| { |
| try |
| { |
| mavenProjectBuilder.calculateConcreteState( project, session.getProjectBuilderConfiguration(), processReferences ); |
| } |
| catch ( ModelInterpolationException e ) |
| { |
| throw new LifecycleExecutionException( "Failed to calculate concrete state for project: " + project, |
| e ); |
| } |
| } |
| } |
| |
| // private void restoreAllDynamicStates( MavenSession session ) |
| // throws LifecycleExecutionException |
| // { |
| // List reactorProjects = session.getSortedProjects(); |
| // if ( reactorProjects != null ) |
| // { |
| // for ( Iterator it = reactorProjects.iterator(); it.hasNext(); ) |
| // { |
| // MavenProject project = (MavenProject) it.next(); |
| // restoreDynamicState( project, session, false ); |
| // } |
| // } |
| // } |
| // |
| // private void restoreDynamicState( MavenProject project, MavenSession session, boolean processReferences ) |
| // throws LifecycleExecutionException |
| // { |
| // try |
| // { |
| // mavenProjectBuilder.restoreDynamicState( project, session.getProjectBuilderConfiguration(), processReferences ); |
| // } |
| // catch ( ModelInterpolationException e ) |
| // { |
| // throw new LifecycleExecutionException( "Failed to restore dynamic state for project: " + project, e ); |
| // } |
| // } |
| |
| private List getReportExecutions( final MavenProject project, final Stack forkEntryPoints, final MojoExecution mojoExecution, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| List reportPlugins = project.getReportPlugins(); |
| |
| if ( project.getModel().getReports() != null ) |
| { |
| getLogger().error( |
| "Plugin contains a <reports/> section: this is IGNORED - please use <reporting/> instead." ); |
| } |
| |
| if ( project.getReporting() == null || !project.getReporting().isExcludeDefaults() ) |
| { |
| if ( reportPlugins == null ) |
| { |
| reportPlugins = new ArrayList(); |
| } |
| else |
| { |
| reportPlugins = new ArrayList( reportPlugins ); |
| } |
| |
| for ( Iterator i = defaultReports.iterator(); i.hasNext(); ) |
| { |
| String report = (String) i.next(); |
| |
| StringTokenizer tok = new StringTokenizer( report, ":" ); |
| int count = tok.countTokens(); |
| if ( count != 2 && count != 3 ) |
| { |
| getLogger().warn( "Invalid default report ignored: '" + report + "' (must be groupId:artifactId[:version])" ); |
| } |
| else |
| { |
| String groupId = tok.nextToken(); |
| String artifactId = tok.nextToken(); |
| String version = tok.hasMoreTokens() ? tok.nextToken() : null; |
| |
| boolean found = false; |
| for ( Iterator j = reportPlugins.iterator(); j.hasNext() && !found; ) |
| { |
| ReportPlugin reportPlugin = (ReportPlugin) j.next(); |
| if ( reportPlugin.getGroupId().equals( groupId ) && |
| reportPlugin.getArtifactId().equals( artifactId ) ) |
| { |
| found = true; |
| } |
| } |
| |
| if ( !found ) |
| { |
| ReportPlugin reportPlugin = new ReportPlugin(); |
| reportPlugin.setGroupId( groupId ); |
| reportPlugin.setArtifactId( artifactId ); |
| reportPlugin.setVersion( version ); |
| reportPlugins.add( reportPlugin ); |
| } |
| } |
| } |
| } |
| |
| List reports = new ArrayList(); |
| if ( reportPlugins != null ) |
| { |
| for ( Iterator it = reportPlugins.iterator(); it.hasNext(); ) |
| { |
| ReportPlugin reportPlugin = (ReportPlugin) it.next(); |
| |
| List reportSets = reportPlugin.getReportSets(); |
| |
| if ( reportSets == null || reportSets.isEmpty() ) |
| { |
| reports.addAll( getReportExecutions( reportPlugin, forkEntryPoints, null, project, session, mojoExecution ) ); |
| } |
| else |
| { |
| for ( Iterator j = reportSets.iterator(); j.hasNext(); ) |
| { |
| ReportSet reportSet = (ReportSet) j.next(); |
| |
| reports.addAll( getReportExecutions( reportPlugin, forkEntryPoints, reportSet, project, session, mojoExecution ) ); |
| } |
| } |
| } |
| } |
| return reports; |
| } |
| |
| private List getReportExecutions( final ReportPlugin reportPlugin, |
| final Stack forkEntryPoints, |
| final ReportSet reportSet, |
| final MavenProject project, |
| final MavenSession session, |
| final MojoExecution mojoExecution ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| PluginDescriptor pluginDescriptor = verifyReportPlugin( reportPlugin, project, session ); |
| |
| List reports = new ArrayList(); |
| for ( Iterator i = pluginDescriptor.getMojos().iterator(); i.hasNext(); ) |
| { |
| MojoDescriptor mojoDescriptor = (MojoDescriptor) i.next(); |
| if ( forkEntryPoints.contains( mojoDescriptor ) ) |
| { |
| getLogger().debug( "Omitting report: " + mojoDescriptor.getFullGoalName() + " from reports list. It initiated part of the fork currently executing." ); |
| continue; |
| } |
| |
| // TODO: check ID is correct for reports |
| // if the POM configured no reports, give all from plugin |
| if ( reportSet == null || reportSet.getReports().contains( mojoDescriptor.getGoal() ) ) |
| { |
| String id = null; |
| if ( reportSet != null ) |
| { |
| id = reportSet.getId(); |
| } |
| else |
| { |
| id = mojoExecution.getExecutionId(); |
| } |
| |
| MojoExecution reportExecution; |
| if ( id.startsWith( MojoExecution.DEFAULT_EXEC_ID_PREFIX ) ) |
| { |
| reportExecution = new MojoExecution( mojoDescriptor ); |
| } |
| else |
| { |
| reportExecution = new MojoExecution( mojoDescriptor, id ); |
| } |
| |
| reports.add( reportExecution ); |
| } |
| } |
| return reports; |
| } |
| |
| private List getReports( final List reportExecutions, final MavenProject project, final MojoExecution mojoExecution, final MavenSession session ) |
| throws LifecycleExecutionException |
| { |
| List reports = new ArrayList(); |
| |
| for ( Iterator it = reportExecutions.iterator(); it.hasNext(); ) |
| { |
| MojoExecution reportExecution = (MojoExecution) it.next(); |
| PluginDescriptor pluginDescriptor = reportExecution.getMojoDescriptor().getPluginDescriptor(); |
| |
| try |
| { |
| MavenReport reportMojo = pluginManager.getReport( project, reportExecution, session ); |
| |
| // Comes back null if it was a plugin, not a report - these are mojos in the reporting plugins that are not reports |
| if ( reportMojo != null ) |
| { |
| reports.add( reportMojo ); |
| mojoExecution.addMojoExecution( reportExecution ); |
| } |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Error getting reports from the plugin '" + pluginDescriptor.getId() + "': " + e.getMessage(), e ); |
| } |
| catch ( PluginConfigurationException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Error getting reports from the plugin '" + pluginDescriptor.getId() + "'", e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| } |
| |
| return reports; |
| } |
| |
| private void forkLifecycle( final MojoDescriptor mojoDescriptor, final Stack ancestorLifecycleForkers, final MavenSession session, |
| final MavenProject project, final String executionId ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor(); |
| getLogger().info( "Preparing " + pluginDescriptor.getGoalPrefix() + ":" + mojoDescriptor.getGoal() ); |
| |
| if ( mojoDescriptor.isAggregator() ) |
| { |
| for ( Iterator i = session.getSortedProjects().iterator(); i.hasNext(); ) |
| { |
| MavenProject reactorProject = (MavenProject) i.next(); |
| |
| line(); |
| |
| getLogger().info( "Building " + reactorProject.getName() ); |
| |
| line(); |
| |
| forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, reactorProject, executionId ); |
| } |
| } |
| else |
| { |
| forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, project, executionId ); |
| } |
| } |
| |
| private void forkProjectLifecycle( final MojoDescriptor mojoDescriptor, final Stack forkEntryPoints, final MavenSession session, |
| MavenProject project, final String executionId ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| project = project.getExecutionProject(); |
| |
| forkEntryPoints.push( mojoDescriptor ); |
| |
| PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor(); |
| |
| String targetPhase = mojoDescriptor.getExecutePhase(); |
| |
| Map lifecycleMappings = null; |
| if ( targetPhase != null ) |
| { |
| Lifecycle lifecycle = getLifecycleForPhase( targetPhase ); |
| |
| // Create new lifecycle |
| lifecycleMappings = constructLifecycleMappings( session, targetPhase, project, lifecycle ); |
| |
| String executeLifecycle = mojoDescriptor.getExecuteLifecycle(); |
| if ( executeLifecycle != null ) |
| { |
| org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay; |
| try |
| { |
| lifecycleOverlay = pluginDescriptor.getLifecycleMapping( executeLifecycle ); |
| } |
| catch ( IOException e ) |
| { |
| throw new LifecycleExecutionException( "Unable to read lifecycle mapping file: " + e.getMessage(), |
| e ); |
| } |
| catch ( XmlPullParserException e ) |
| { |
| throw new LifecycleExecutionException( "Unable to parse lifecycle mapping file: " + e.getMessage(), |
| e ); |
| } |
| |
| if ( lifecycleOverlay == null ) |
| { |
| throw new LifecycleExecutionException( "Lifecycle '" + executeLifecycle + "' not found in plugin" ); |
| } |
| |
| for ( Iterator i = lifecycleOverlay.getPhases().iterator(); i.hasNext(); ) |
| { |
| Phase phase = (Phase) i.next(); |
| for ( Iterator j = phase.getExecutions().iterator(); j.hasNext(); ) |
| { |
| Execution exec = (Execution) j.next(); |
| |
| for ( Iterator k = exec.getGoals().iterator(); k.hasNext(); ) |
| { |
| String goal = (String) k.next(); |
| |
| PluginDescriptor lifecyclePluginDescriptor; |
| String lifecycleGoal; |
| |
| // Here we are looking to see if we have a mojo from an external plugin. |
| // If we do then we need to lookup the plugin descriptor for the externally |
| // referenced plugin so that we can overly the execution into the lifecycle. |
| // An example of this is the corbertura plugin that needs to call the surefire |
| // plugin in forking mode. |
| // |
| //<phase> |
| // <id>test</id> |
| // <executions> |
| // <execution> |
| // <goals> |
| // <goal>org.apache.maven.plugins:maven-surefire-plugin:test</goal> |
| // </goals> |
| // <configuration> |
| // <classesDirectory>${project.build.directory}/generated-classes/cobertura</classesDirectory> |
| // <ignoreFailures>true</ignoreFailures> |
| // <forkMode>once</forkMode> |
| // </configuration> |
| // </execution> |
| // </executions> |
| //</phase> |
| |
| // ---------------------------------------------------------------------- |
| // |
| // ---------------------------------------------------------------------- |
| |
| if ( goal.indexOf( ":" ) > 0 ) |
| { |
| String[] s = StringUtils.split( goal, ":" ); |
| |
| String groupId = s[0]; |
| String artifactId = s[1]; |
| lifecycleGoal = s[2]; |
| |
| Plugin plugin = new Plugin(); |
| plugin.setGroupId( groupId ); |
| plugin.setArtifactId( artifactId ); |
| lifecyclePluginDescriptor = verifyPlugin( plugin, project, session ); |
| if ( lifecyclePluginDescriptor == null ) |
| { |
| throw new LifecycleExecutionException( |
| "Unable to find plugin " + groupId + ":" + artifactId ); |
| } |
| } |
| else |
| { |
| lifecyclePluginDescriptor = pluginDescriptor; |
| lifecycleGoal = goal; |
| } |
| |
| Xpp3Dom configuration = (Xpp3Dom) exec.getConfiguration(); |
| // NOTE: This seems to be duplicated below. Why?? |
| if ( phase.getConfiguration() != null ) |
| { |
| configuration = Xpp3Dom.mergeXpp3Dom( new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ), |
| configuration ); |
| } |
| |
| MojoDescriptor desc = getMojoDescriptor( lifecyclePluginDescriptor, lifecycleGoal ); |
| MojoExecution mojoExecution; |
| if ( executionId.startsWith( MojoExecution.DEFAULT_EXEC_ID_PREFIX ) ) |
| { |
| mojoExecution = new MojoExecution( desc, configuration ); |
| } |
| else |
| { |
| mojoExecution = new MojoExecution( desc, configuration, executionId ); |
| } |
| |
| addToLifecycleMappings( lifecycleMappings, phase.getId(), mojoExecution, |
| session.getSettings() ); |
| } |
| } |
| |
| if ( phase.getConfiguration() != null ) |
| { |
| // Merge in general configuration for a phase. |
| // TODO: this is all kind of backwards from the POMM. Let's align it all under 2.1. |
| // We should create a new lifecycle executor for modelVersion >5.0.0 |
| for ( Iterator j = lifecycleMappings.values().iterator(); j.hasNext(); ) |
| { |
| List tasks = (List) j.next(); |
| |
| for ( Iterator k = tasks.iterator(); k.hasNext(); ) |
| { |
| MojoExecution exec = (MojoExecution) k.next(); |
| |
| Xpp3Dom configuration = Xpp3Dom.mergeXpp3Dom( |
| new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ), exec.getConfiguration() ); |
| |
| exec.setConfiguration( configuration ); |
| } |
| } |
| } |
| |
| } |
| } |
| |
| removeFromLifecycle( forkEntryPoints, lifecycleMappings ); |
| } |
| |
| if ( targetPhase != null ) |
| { |
| Lifecycle lifecycle = getLifecycleForPhase( targetPhase ); |
| |
| executeGoalWithLifecycle( targetPhase, forkEntryPoints, session, lifecycleMappings, project, lifecycle ); |
| } |
| else |
| { |
| String goal = mojoDescriptor.getExecuteGoal(); |
| MojoDescriptor desc = getMojoDescriptor( pluginDescriptor, goal ); |
| executeGoals( Collections.singletonList( new MojoExecution( desc, goal ) ), forkEntryPoints, session, project ); |
| } |
| } |
| |
| private Lifecycle getLifecycleForPhase( final String phase ) |
| throws BuildFailureException, LifecycleExecutionException |
| { |
| Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap().get( phase ); |
| |
| if ( lifecycle == null ) |
| { |
| throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" ); |
| } |
| return lifecycle; |
| } |
| |
| private MojoDescriptor getMojoDescriptor( final PluginDescriptor pluginDescriptor, final String goal ) |
| throws LifecycleExecutionException |
| { |
| MojoDescriptor desc = pluginDescriptor.getMojo( goal ); |
| |
| if ( desc == null ) |
| { |
| String message = |
| "Required goal '" + goal + "' not found in plugin '" + pluginDescriptor.getGoalPrefix() + "'"; |
| int index = goal.indexOf( ':' ); |
| if ( index >= 0 ) |
| { |
| String prefix = goal.substring( index + 1 ); |
| if ( prefix.equals( pluginDescriptor.getGoalPrefix() ) ) |
| { |
| message = message + " (goals should not be prefixed - try '" + prefix + "')"; |
| } |
| } |
| throw new LifecycleExecutionException( message ); |
| } |
| return desc; |
| } |
| |
| private void removeFromLifecycle( final Stack lifecycleForkers, final Map lifecycleMappings ) |
| { |
| for ( Iterator lifecycleIterator = lifecycleMappings.values().iterator(); lifecycleIterator.hasNext(); ) |
| { |
| List tasks = (List) lifecycleIterator.next(); |
| |
| for ( Iterator taskIterator = tasks.iterator(); taskIterator.hasNext(); ) |
| { |
| MojoExecution execution = (MojoExecution) taskIterator.next(); |
| |
| if ( lifecycleForkers.contains( execution.getMojoDescriptor() ) ) |
| { |
| taskIterator.remove(); |
| getLogger().warn( "Removing: " + execution.getMojoDescriptor().getGoal() |
| + " from forked lifecycle, to prevent recursive invocation." ); |
| } |
| } |
| } |
| } |
| |
| private Map constructLifecycleMappings( final MavenSession session, final String selectedPhase, final MavenProject project, |
| final Lifecycle lifecycle ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| // first, bind those associated with the packaging |
| Map lifecycleMappings = bindLifecycleForPackaging( session, selectedPhase, project, lifecycle ); |
| |
| // next, loop over plugins and for any that have a phase, bind it |
| for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); ) |
| { |
| Plugin plugin = (Plugin) i.next(); |
| |
| bindPluginToLifecycle( plugin, session, lifecycleMappings, project ); |
| } |
| |
| return lifecycleMappings; |
| } |
| |
| private Map bindLifecycleForPackaging( final MavenSession session, final String selectedPhase, final MavenProject project, |
| final Lifecycle lifecycle ) |
| throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException |
| { |
| Map mappings = findMappingsForLifecycle( session, project, lifecycle ); |
| |
| List optionalMojos = findOptionalMojosForLifecycle( session, project, lifecycle ); |
| |
| Map lifecycleMappings = new HashMap(); |
| |
| for ( Iterator i = lifecycle.getPhases().iterator(); i.hasNext(); ) |
| { |
| String phase = (String) i.next(); |
| |
| String phaseTasks = (String) mappings.get( phase ); |
| |
| if ( phaseTasks != null ) |
| { |
| for ( StringTokenizer tok = new StringTokenizer( phaseTasks, "," ); tok.hasMoreTokens(); ) |
| { |
| String goal = tok.nextToken().trim(); |
| |
| // Not from the CLI, don't use prefix |
| MojoDescriptor mojoDescriptor = getMojoDescriptor( goal, session, project, selectedPhase, false, |
| optionalMojos.contains( goal ) ); |
| |
| if ( mojoDescriptor == null ) |
| { |
| continue; |
| } |
| |
| if ( mojoDescriptor.isDirectInvocationOnly() ) |
| { |
| throw new LifecycleExecutionException( "Mojo: \'" + goal + |
| "\' requires direct invocation. It cannot be used as part of lifecycle: \'" + |
| project.getPackaging() + "\'." ); |
| } |
| |
| addToLifecycleMappings( lifecycleMappings, phase, new MojoExecution( mojoDescriptor ), |
| session.getSettings() ); |
| } |
| } |
| |
| if ( phase.equals( selectedPhase ) ) |
| { |
| break; |
| } |
| } |
| |
| return lifecycleMappings; |
| } |
| |
| private Map findMappingsForLifecycle( final MavenSession session, final MavenProject project, final Lifecycle lifecycle ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| String packaging = project.getPackaging(); |
| Map mappings = null; |
| |
| LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session ); |
| if ( m != null ) |
| { |
| mappings = m.getPhases( lifecycle.getId() ); |
| } |
| |
| Map defaultMappings = lifecycle.getDefaultPhases(); |
| |
| if ( mappings == null ) |
| { |
| try |
| { |
| m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging ); |
| mappings = m.getPhases( lifecycle.getId() ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| if ( defaultMappings == null ) |
| { |
| throw new LifecycleExecutionException( |
| "Cannot find lifecycle mapping for packaging: \'" + packaging + "\'.", e ); |
| } |
| } |
| } |
| |
| if ( mappings == null ) |
| { |
| if ( defaultMappings == null ) |
| { |
| throw new LifecycleExecutionException( |
| "Cannot find lifecycle mapping for packaging: \'" + packaging + "\', and there is no default" ); |
| } |
| else |
| { |
| mappings = defaultMappings; |
| } |
| } |
| |
| return mappings; |
| } |
| |
| private List findOptionalMojosForLifecycle( final MavenSession session, final MavenProject project, final Lifecycle lifecycle ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| String packaging = project.getPackaging(); |
| List optionalMojos = null; |
| |
| LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session ); |
| |
| if ( m != null ) |
| { |
| optionalMojos = m.getOptionalMojos( lifecycle.getId() ); |
| } |
| |
| if ( optionalMojos == null ) |
| { |
| try |
| { |
| m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging ); |
| optionalMojos = m.getOptionalMojos( lifecycle.getId() ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| getLogger().debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: " + |
| lifecycle.getId() + ". Error: " + e.getMessage(), e ); |
| } |
| } |
| |
| if ( optionalMojos == null ) |
| { |
| optionalMojos = Collections.EMPTY_LIST; |
| } |
| |
| return optionalMojos; |
| } |
| |
| private Object findExtension( final MavenProject project, final String role, final String roleHint, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| Object pluginComponent = null; |
| |
| for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext() && pluginComponent == null; ) |
| { |
| Plugin plugin = (Plugin) i.next(); |
| |
| if ( plugin.isExtensions() ) |
| { |
| loadPluginFully( plugin, project, session ); |
| |
| // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly |
| try |
| { |
| pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| getLogger().debug( "Unable to find the lifecycle component in the extension", e ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Error getting extensions from the plugin '" + plugin.getKey() + "': " + e.getMessage(), e ); |
| } |
| } |
| } |
| return pluginComponent; |
| } |
| |
| /** |
| * @todo Not particularly happy about this. Would like WagonManager and ArtifactTypeHandlerManager to be able to |
| * lookup directly, or have them passed in |
| */ |
| private Map<String, ArtifactHandler> findArtifactTypeHandlersInPlugins( final MavenProject project, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| Map<String, ArtifactHandler> map = new HashMap<String, ArtifactHandler>(); |
| for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); ) |
| { |
| Plugin plugin = (Plugin) i.next(); |
| |
| if ( plugin.isExtensions() ) |
| { |
| loadPluginFully( plugin, project, session ); |
| |
| // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly |
| try |
| { |
| Map components = pluginManager.getPluginComponents( plugin, ArtifactHandler.ROLE ); |
| map.putAll( components ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| getLogger().debug( "Unable to find the lifecycle component in the extension", e ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( "Error looking up available components from plugin '" + |
| plugin.getKey() + "': " + e.getMessage(), e ); |
| } |
| } |
| } |
| return map; |
| } |
| |
| /** |
| * Take each mojo contained with a plugin, look to see whether it contributes to a |
| * phase in the lifecycle and if it does place it at the end of the list of goals |
| * to execute for that given phase. |
| * |
| * @param project |
| * @param session |
| */ |
| private void bindPluginToLifecycle( final Plugin plugin, final MavenSession session, final Map phaseMap, final MavenProject project ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| Settings settings = session.getSettings(); |
| |
| PluginDescriptor pluginDescriptor = |
| verifyPlugin( plugin, project, session ); |
| |
| if ( pluginDescriptor.getMojos() != null && !pluginDescriptor.getMojos().isEmpty() ) |
| { |
| // use the plugin if inherit was true in a base class, or it is in the current POM, otherwise use the default inheritence setting |
| if ( plugin.isInheritanceApplied() || pluginDescriptor.isInheritedByDefault() ) |
| { |
| if ( plugin.getGoals() != null ) |
| { |
| getLogger().error( |
| "Plugin contains a <goals/> section: this is IGNORED - please use <executions/> instead." ); |
| } |
| |
| List executions = plugin.getExecutions(); |
| |
| if ( executions != null ) |
| { |
| for ( Iterator it = executions.iterator(); it.hasNext(); ) |
| { |
| PluginExecution execution = (PluginExecution) it.next(); |
| |
| bindExecutionToLifecycle( pluginDescriptor, phaseMap, execution, settings ); |
| } |
| } |
| } |
| } |
| } |
| |
| private PluginDescriptor verifyPlugin( final Plugin plugin, final MavenProject project, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| PluginDescriptor pluginDescriptor; |
| try |
| { |
| // TODO: MNG-4081...need to flush this plugin once we look at it, to avoid using an external |
| // version of a plugin when a newer version will be created in the current reactor... |
| pluginDescriptor = pluginManager.loadPluginDescriptor( plugin, project, session ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Internal error in the plugin manager getting plugin '" + plugin.getKey() + "': " + e.getMessage(), e ); |
| } |
| catch ( PluginVersionResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidVersionSpecificationException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidPluginException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( PluginVersionNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| return pluginDescriptor; |
| } |
| |
| private PluginDescriptor loadPluginFully( final Plugin plugin, final MavenProject project, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| PluginDescriptor pluginDescriptor; |
| try |
| { |
| // TODO: MNG-4081...need to flush this plugin once we look at it, to avoid using an external |
| // version of a plugin when a newer version will be created in the current reactor... |
| pluginDescriptor = pluginManager.loadPluginFully( plugin, project, session ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Internal error in the plugin manager getting plugin '" + plugin.getKey() + "': " + e.getMessage(), e ); |
| } |
| catch ( PluginVersionResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidVersionSpecificationException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidPluginException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( PluginVersionNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| return pluginDescriptor; |
| } |
| |
| private PluginDescriptor verifyReportPlugin( final ReportPlugin plugin, final MavenProject project, final MavenSession session ) |
| throws LifecycleExecutionException, PluginNotFoundException |
| { |
| PluginDescriptor pluginDescriptor; |
| try |
| { |
| pluginDescriptor = pluginManager.verifyReportPlugin( plugin, project, session ); |
| } |
| catch ( PluginManagerException e ) |
| { |
| throw new LifecycleExecutionException( |
| "Internal error in the plugin manager getting report '" + plugin.getKey() + "': " + e.getMessage(), e ); |
| } |
| catch ( PluginVersionResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidVersionSpecificationException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( InvalidPluginException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( ArtifactResolutionException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| catch ( PluginVersionNotFoundException e ) |
| { |
| throw new LifecycleExecutionException( e.getMessage(), e ); |
| } |
| return pluginDescriptor; |
| } |
| |
| private void bindExecutionToLifecycle( final PluginDescriptor pluginDescriptor, final Map phaseMap, final PluginExecution execution, |
| final Settings settings ) |
| throws LifecycleExecutionException |
| { |
| for ( Iterator i = execution.getGoals().iterator(); i.hasNext(); ) |
| { |
| String goal = (String) i.next(); |
| |
| MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal ); |
| if ( mojoDescriptor == null ) |
| { |
| throw new LifecycleExecutionException( |
| "'" + goal + "' was specified in an execution, but not found in the plugin" ); |
| } |
| |
| // We have to check to see that the inheritance rules have been applied before binding this mojo. |
| if ( execution.isInheritanceApplied() || mojoDescriptor.isInheritedByDefault() ) |
| { |
| MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() ); |
| |
| String phase = execution.getPhase(); |
| |
| if ( phase == null ) |
| { |
| // if the phase was not in the configuration, use the phase in the descriptor |
| phase = mojoDescriptor.getPhase(); |
| } |
| |
| if ( phase != null ) |
| { |
| if ( mojoDescriptor.isDirectInvocationOnly() ) |
| { |
| throw new LifecycleExecutionException( "Mojo: \'" + goal + |
| "\' requires direct invocation. It cannot be used as part of the lifecycle (it was included via the POM)." ); |
| } |
| |
| addToLifecycleMappings( phaseMap, phase, mojoExecution, settings ); |
| } |
| } |
| } |
| } |
| |
| private void addToLifecycleMappings( final Map lifecycleMappings, final String phase, final MojoExecution mojoExecution, |
| final Settings settings ) |
| { |
| List goals = (List) lifecycleMappings.get( phase ); |
| |
| if ( goals == null ) |
| { |
| goals = new ArrayList(); |
| lifecycleMappings.put( phase, goals ); |
| } |
| |
| MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); |
| if ( settings.isOffline() && mojoDescriptor.isOnlineRequired() ) |
| { |
| String goal = mojoDescriptor.getGoal(); |
| getLogger().warn( goal + " requires online mode, but maven is currently offline. Disabling " + goal + "." ); |
| } |
| else |
| { |
| goals.add( mojoExecution ); |
| } |
| } |
| |
| private List processGoalChain( final String task, final Map phaseMap, final Lifecycle lifecycle ) |
| { |
| List goals = new ArrayList(); |
| |
| // only execute up to the given phase |
| int index = lifecycle.getPhases().indexOf( task ); |
| |
| for ( int i = 0; i <= index; i++ ) |
| { |
| String p = (String) lifecycle.getPhases().get( i ); |
| |
| List phaseGoals = (List) phaseMap.get( p ); |
| |
| if ( phaseGoals != null ) |
| { |
| goals.addAll( phaseGoals ); |
| } |
| } |
| return goals; |
| } |
| |
| private MojoDescriptor getMojoDescriptor( final String task, final MavenSession session, final MavenProject project, |
| final String invokedVia, final boolean canUsePrefix, final boolean isOptionalMojo ) |
| throws BuildFailureException, LifecycleExecutionException, PluginNotFoundException |
| { |
| String goal; |
| Plugin plugin = null; |
| |
| PluginDescriptor pluginDescriptor = null; |
| |
| try |
| { |
| StringTokenizer tok = new StringTokenizer( task, ":" ); |
| int numTokens = tok.countTokens(); |
| |
| if ( numTokens == 2 ) |
| { |
| if ( !canUsePrefix ) |
| { |
| String msg = "Mapped-prefix lookup of mojos are only supported from direct invocation. " + |
| "Please use specification of the form groupId:artifactId[:version]:goal instead. " + |
| "(Offending mojo: \'" + task + "\', invoked via: \'" + invokedVia + "\')"; |
| throw new LifecycleExecutionException( msg ); |
| } |
| |
| String prefix = tok.nextToken(); |
| goal = tok.nextToken(); |
| |
| // Steps for retrieving the plugin model instance: |
| // 1. request directly from the plugin collector by prefix |
| pluginDescriptor = pluginManager.getPluginDescriptorForPrefix( prefix ); |
| if ( pluginDescriptor != null ) |
| { |
| plugin = new Plugin(); |
| plugin.setGroupId( pluginDescriptor.getGroupId() ); |
| plugin.setArtifactId( pluginDescriptor.getArtifactId() ); |
| plugin.setVersion( pluginDescriptor.getVersion() ); |
| } |
| |
| // 2. search plugins in the current POM |
| if ( plugin == null ) |
| { |
| for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); ) |
| { |
| Plugin buildPlugin = (Plugin) i.next(); |
| |
| PluginDescriptor desc = |
| verifyPlugin( buildPlugin, project, session ); |
| if ( prefix.equals( desc.getGoalPrefix() ) ) |
| { |
| plugin = buildPlugin; |
| pluginDescriptor = desc; |
| break; |
| } |
| } |
| } |
| |
| // 3. look in the repository via search groups |
| if ( plugin == null ) |
| { |
| plugin = pluginManager.getPluginDefinitionForPrefix( prefix, session, project ); |
| } |
| |
| // 4. default to o.a.m.plugins and maven-<prefix>-plugin |
| if ( plugin == null ) |
| { |
| plugin = new Plugin(); |
| plugin.setGroupId( PluginDescriptor.getDefaultPluginGroupId() ); |
| plugin.setArtifactId( PluginDescriptor.getDefaultPluginArtifactId( prefix ) ); |
| } |
| } |
| else if ( numTokens == 3 || numTokens == 4 ) |
| { |
| plugin = new Plugin(); |
| |
| plugin.setGroupId( tok.nextToken() ); |
| plugin.setArtifactId( tok.nextToken() ); |
| |
| if ( numTokens == 4 ) |
| { |
| plugin.setVersion( tok.nextToken() ); |
| } |
| |
| goal = tok.nextToken(); |
| } |
| else |
| { |
| String message = "Invalid task '" + task + "': you must specify a valid lifecycle phase, or" + |
| " a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal"; |
| throw new BuildFailureException( message ); |
| } |
| |
| if ( plugin.getVersion() == null ) |
| { |
| for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); ) |
| { |
| Plugin buildPlugin = (Plugin) i.next(); |
| |
| if ( buildPlugin.getKey().equals( plugin.getKey() ) ) |
| { |
| plugin = buildPlugin; |
| break; |
| } |
| } |
| |
| project.injectPluginManagementInfo( plugin ); |
| } |
| |
| if ( pluginDescriptor == null ) |
| { |
| pluginDescriptor = verifyPlugin( plugin, project, session ); |
| } |
| |
| // this has been simplified from the old code that injected the plugin management stuff, since |
| // pluginManagement injection is now handled by the project method. |
| project.addPlugin( plugin ); |
| |
| MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal ); |
| if ( mojoDescriptor == null ) |
| { |
| if ( isOptionalMojo ) |
| { |
| getLogger().info( "Skipping missing optional mojo: " + task ); |
| } |
| else |
| { |
| throw new BuildFailureException( "Required goal not found: " + task + " in " |
| + pluginDescriptor.getId() ); |
| } |
| } |
| |
| return mojoDescriptor; |
| } |
| catch ( PluginNotFoundException e ) |
| { |
| if ( isOptionalMojo ) |
| { |
| getLogger().info( "Skipping missing optional mojo: " + task ); |
| getLogger().debug( "Mojo: " + task + " could not be found. Reason: " + e.getMessage(), e ); |
| } |
| else |
| { |
| throw e; |
| } |
| } |
| |
| return null; |
| } |
| |
| protected void line() |
| { |
| getLogger().info( "------------------------------------------------------------------------" ); |
| } |
| |
| public Map getPhaseToLifecycleMap() |
| throws LifecycleExecutionException |
| { |
| if ( phaseToLifecycleMap == null ) |
| { |
| phaseToLifecycleMap = new HashMap(); |
| |
| for ( Iterator i = lifecycles.iterator(); i.hasNext(); ) |
| { |
| Lifecycle lifecycle = (Lifecycle) i.next(); |
| |
| for ( Iterator p = lifecycle.getPhases().iterator(); p.hasNext(); ) |
| { |
| String phase = (String) p.next(); |
| |
| if ( phaseToLifecycleMap.containsKey( phase ) ) |
| { |
| Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase ); |
| throw new LifecycleExecutionException( "Phase '" + phase + |
| "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '" + |
| prevLifecycle.getId() + "'" ); |
| } |
| else |
| { |
| phaseToLifecycleMap.put( phase, lifecycle ); |
| } |
| } |
| } |
| } |
| return phaseToLifecycleMap; |
| } |
| |
| private static class TaskSegment |
| { |
| private boolean aggregate; |
| |
| private final List tasks = new ArrayList(); |
| |
| TaskSegment() |
| { |
| |
| } |
| |
| TaskSegment( final boolean aggregate ) |
| { |
| this.aggregate = aggregate; |
| } |
| |
| public String toString() |
| { |
| StringBuffer message = new StringBuffer(); |
| |
| message.append( " task-segment: [" ); |
| |
| for ( Iterator it = tasks.iterator(); it.hasNext(); ) |
| { |
| String task = (String) it.next(); |
| |
| message.append( task ); |
| |
| if ( it.hasNext() ) |
| { |
| message.append( ", " ); |
| } |
| } |
| |
| message.append( "]" ); |
| |
| if ( aggregate ) |
| { |
| message.append( " (aggregator-style)" ); |
| } |
| |
| return message.toString(); |
| } |
| |
| boolean aggregate() |
| { |
| return aggregate; |
| } |
| |
| void add( final String task ) |
| { |
| tasks.add( task ); |
| } |
| |
| List getTasks() |
| { |
| return tasks; |
| } |
| } |
| |
| public List getLifecycles() |
| { |
| return lifecycles; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // TODO: The methods and fields below are only needed for products like Hudson, |
| // that provide their own LifecycleExecutor and component configuration that extend |
| // default implementation, and which may become out-of-date as component requirements |
| // are updated within Maven itself. |
| public void initialize() |
| throws InitializationException |
| { |
| if ( mavenProjectBuilder == null ) |
| { |
| warnOfIncompleteComponentConfiguration( MavenProjectBuilder.ROLE ); |
| try |
| { |
| mavenProjectBuilder = (MavenProjectBuilder) container.lookup( MavenProjectBuilder.ROLE ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| throw new InitializationException( "Failed to lookup project builder after it was NOT injected via component requirement." ); |
| } |
| } |
| |
| if ( modelInterpolator == null ) |
| { |
| warnOfIncompleteComponentConfiguration( ModelInterpolator.ROLE ); |
| try |
| { |
| modelInterpolator = (ModelInterpolator) container.lookup( ModelInterpolator.ROLE ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| throw new InitializationException( "Failed to lookup model interpolator after it was NOT injected via component requirement." ); |
| } |
| } |
| |
| if ( configInterpolator == null ) |
| { |
| warnOfIncompleteComponentConfiguration( ConfigurationInterpolator.ROLE ); |
| try |
| { |
| configInterpolator = (ConfigurationInterpolator) container.lookup( ConfigurationInterpolator.ROLE ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| throw new InitializationException( "Failed to lookup plugin-configuration interpolator after it was NOT injected via component requirement." ); |
| } |
| } |
| } |
| |
| private void warnOfIncompleteComponentConfiguration( final String role ) |
| { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append( "\n************ WARNING ************" ); |
| buffer.append( "\n\nThis Maven runtime contains a LifecycleExecutor component with an incomplete configuration." ); |
| buffer.append( "\n\nLifecycleExecutor class: " ).append( getClass().getName() ); |
| buffer.append( "\nMissing component requirement: " ).append( role ); |
| buffer.append( "\n" ); |
| buffer.append( "\nNOTE: This seems to be a third-party Maven derivative you are using. If so, please" ); |
| buffer.append( "\nnotify the developers for this derivative project of the problem. The Apache Maven team is not" ); |
| buffer.append( "\nresponsible for maintaining the integrity of third-party component overrides." ); |
| buffer.append( "\n\n" ); |
| |
| getLogger().warn( buffer.toString() ); |
| } |
| |
| private PlexusContainer container; |
| |
| public void contextualize( final Context context ) |
| throws ContextException |
| { |
| container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); |
| } |
| } |