package org.apache.maven.lifecycle.internal; /* * 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.InternalErrorException; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.BuildFailure; import org.apache.maven.execution.ExecutionEvent; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenSession; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.LifecycleNotFoundException; import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException; import org.apache.maven.lifecycle.MavenExecutionPlan; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.InvalidPluginDescriptorException; import org.apache.maven.plugin.MojoNotFoundException; import org.apache.maven.plugin.PluginDescriptorParsingException; import org.apache.maven.plugin.PluginNotFoundException; import org.apache.maven.plugin.PluginResolutionException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException; import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; import java.util.Set; /** * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder * * @since 3.0 * @author Kristian Rosenvold * Builds one or more lifecycles for a full module * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. */ @Component( role = BuilderCommon.class ) public class BuilderCommon { @Requirement private LifecycleDebugLogger lifecycleDebugLogger; @Requirement private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator; @Requirement private ExecutionEventCatapult eventCatapult; @Requirement private Logger logger; public BuilderCommon() { } public BuilderCommon( LifecycleDebugLogger lifecycleDebugLogger, LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator, Logger logger ) { this.lifecycleDebugLogger = lifecycleDebugLogger; this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator; this.logger = logger; } public MavenExecutionPlan resolveBuildPlan( MavenSession session, MavenProject project, TaskSegment taskSegment, Set<Artifact> projectArtifacts ) throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException, LifecycleExecutionException { MavenExecutionPlan executionPlan = lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, project, taskSegment.getTasks() ); lifecycleDebugLogger.debugProjectPlan( project, executionPlan ); if ( session.getRequest().isThreadConfigurationPresent() ) { final Set<Plugin> unsafePlugins = executionPlan.getNonThreadSafePlugins(); if ( !unsafePlugins.isEmpty() ) { logger.warn( "*****************************************************************" ); logger.warn( "* Your build is requesting parallel execution, but project *" ); logger.warn( "* contains the following plugin(s) that have goals not marked *" ); logger.warn( "* as @threadSafe to support parallel building. *" ); logger.warn( "* While this /may/ work fine, please look for plugin updates *" ); logger.warn( "* and/or request plugins be made thread-safe. *" ); logger.warn( "* If reporting an issue, report it against the plugin in *" ); logger.warn( "* question, not against maven-core *" ); logger.warn( "*****************************************************************" ); if ( logger.isDebugEnabled() ) { final Set<MojoDescriptor> unsafeGoals = executionPlan.getNonThreadSafeMojos(); logger.warn( "The following goals are not marked @threadSafe in " + project.getName() + ":" ); for ( MojoDescriptor unsafeGoal : unsafeGoals ) { logger.warn( unsafeGoal.getId() ); } } else { logger.warn( "The following plugins are not marked @threadSafe in " + project.getName() + ":" ); for ( Plugin unsafePlugin : unsafePlugins ) { logger.warn( unsafePlugin.getId() ); } logger.warn( "Enable debug to see more precisely which goals are not marked @threadSafe." ); } logger.warn( "*****************************************************************" ); } } return executionPlan; } public void handleBuildError( final ReactorContext buildContext, final MavenSession rootSession, final MavenProject mavenProject, Exception e, final long buildStartTime ) { if ( e instanceof RuntimeException ) { e = new InternalErrorException( "Internal error: " + e, e ); } buildContext.getResult().addException( e ); long buildEndTime = System.currentTimeMillis(); buildContext.getResult().addBuildSummary( new BuildFailure( mavenProject, buildEndTime - buildStartTime, e ) ); eventCatapult.fire( ExecutionEvent.Type.ProjectFailed, rootSession, null, e ); if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( rootSession.getReactorFailureBehavior() ) ) { // continue the build } else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( rootSession.getReactorFailureBehavior() ) ) { // continue the build but ban all projects that depend on the failed one buildContext.getReactorBuildStatus().blackList( mavenProject ); } else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( rootSession.getReactorFailureBehavior() ) ) { buildContext.getReactorBuildStatus().halt(); } else { throw new IllegalArgumentException( "invalid reactor failure behavior " + rootSession.getReactorFailureBehavior() ); } } public static void attachToThread( MavenProject currentProject ) { ClassRealm projectRealm = currentProject.getClassRealm(); if ( projectRealm != null ) { Thread.currentThread().setContextClassLoader( projectRealm ); } } // Todo: I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some reason // it isn't ? This localization is kind-of a code smell. public static String getKey( MavenProject project ) { return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion(); } }