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.InternalErrorException;
023 import org.apache.maven.artifact.Artifact;
024 import org.apache.maven.execution.BuildFailure;
025 import org.apache.maven.execution.ExecutionEvent;
026 import org.apache.maven.execution.MavenExecutionRequest;
027 import org.apache.maven.execution.MavenSession;
028 import org.apache.maven.lifecycle.LifecycleExecutionException;
029 import org.apache.maven.lifecycle.LifecycleNotFoundException;
030 import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
031 import org.apache.maven.lifecycle.MavenExecutionPlan;
032 import org.apache.maven.model.Plugin;
033 import org.apache.maven.plugin.InvalidPluginDescriptorException;
034 import org.apache.maven.plugin.MojoNotFoundException;
035 import org.apache.maven.plugin.PluginDescriptorParsingException;
036 import org.apache.maven.plugin.PluginNotFoundException;
037 import org.apache.maven.plugin.PluginResolutionException;
038 import org.apache.maven.plugin.descriptor.MojoDescriptor;
039 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
040 import org.apache.maven.plugin.version.PluginVersionResolutionException;
041 import org.apache.maven.project.MavenProject;
042 import org.codehaus.plexus.classworlds.realm.ClassRealm;
043 import org.codehaus.plexus.component.annotations.Component;
044 import org.codehaus.plexus.component.annotations.Requirement;
045 import org.codehaus.plexus.logging.Logger;
046
047 import java.util.Set;
048
049 /**
050 * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder
051 *
052 * @since 3.0
053 * @author Kristian Rosenvold
054 * Builds one or more lifecycles for a full module
055 * NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
056 */
057 @Component( role = BuilderCommon.class )
058 public class BuilderCommon
059 {
060 @Requirement
061 private LifecycleDebugLogger lifecycleDebugLogger;
062
063 @Requirement
064 private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
065
066 @Requirement
067 private ExecutionEventCatapult eventCatapult;
068
069 @Requirement
070 private Logger logger;
071
072
073 public BuilderCommon()
074 {
075 }
076
077 public BuilderCommon( LifecycleDebugLogger lifecycleDebugLogger,
078 LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator, Logger logger )
079 {
080 this.lifecycleDebugLogger = lifecycleDebugLogger;
081 this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
082 this.logger = logger;
083 }
084
085 public MavenExecutionPlan resolveBuildPlan( MavenSession session, MavenProject project, TaskSegment taskSegment,
086 Set<Artifact> projectArtifacts )
087 throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
088 PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
089 NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException,
090 LifecycleExecutionException
091 {
092 MavenExecutionPlan executionPlan =
093 lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, project, taskSegment.getTasks() );
094
095 lifecycleDebugLogger.debugProjectPlan( project, executionPlan );
096
097 if ( session.getRequest().isThreadConfigurationPresent() )
098 {
099 final Set<Plugin> unsafePlugins = executionPlan.getNonThreadSafePlugins();
100 if ( !unsafePlugins.isEmpty() )
101 {
102 logger.warn( "*****************************************************************" );
103 logger.warn( "* Your build is requesting parallel execution, but project *" );
104 logger.warn( "* contains the following plugin(s) that have goals not marked *" );
105 logger.warn( "* as @threadSafe to support parallel building. *" );
106 logger.warn( "* While this /may/ work fine, please look for plugin updates *" );
107 logger.warn( "* and/or request plugins be made thread-safe. *" );
108 logger.warn( "* If reporting an issue, report it against the plugin in *" );
109 logger.warn( "* question, not against maven-core *" );
110 logger.warn( "*****************************************************************" );
111 if ( logger.isDebugEnabled() )
112 {
113 final Set<MojoDescriptor> unsafeGoals = executionPlan.getNonThreadSafeMojos();
114 logger.warn( "The following goals are not marked @threadSafe in " + project.getName() + ":" );
115 for ( MojoDescriptor unsafeGoal : unsafeGoals )
116 {
117 logger.warn( unsafeGoal.getId() );
118 }
119 }
120 else
121 {
122 logger.warn( "The following plugins are not marked @threadSafe in " + project.getName() + ":" );
123 for ( Plugin unsafePlugin : unsafePlugins )
124 {
125 logger.warn( unsafePlugin.getId() );
126 }
127 logger.warn( "Enable debug to see more precisely which goals are not marked @threadSafe." );
128 }
129 logger.warn( "*****************************************************************" );
130 }
131 }
132
133 return executionPlan;
134 }
135
136 public void handleBuildError( final ReactorContext buildContext, final MavenSession rootSession,
137 final MavenSession currentSession, final MavenProject mavenProject, Exception e,
138 final long buildStartTime )
139 {
140 if ( e instanceof RuntimeException )
141 {
142 e = new InternalErrorException( "Internal error: " + e, e );
143 }
144
145 buildContext.getResult().addException( e );
146
147 long buildEndTime = System.currentTimeMillis();
148
149 buildContext.getResult().addBuildSummary( new BuildFailure( mavenProject, buildEndTime - buildStartTime, e ) );
150
151 eventCatapult.fire( ExecutionEvent.Type.ProjectFailed, currentSession, null, e );
152
153 if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( rootSession.getReactorFailureBehavior() ) )
154 {
155 // continue the build
156 }
157 else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( rootSession.getReactorFailureBehavior() ) )
158 {
159 // continue the build but ban all projects that depend on the failed one
160 buildContext.getReactorBuildStatus().blackList( mavenProject );
161 }
162 else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( rootSession.getReactorFailureBehavior() ) )
163 {
164 buildContext.getReactorBuildStatus().halt();
165 }
166 else
167 {
168 throw new IllegalArgumentException(
169 "invalid reactor failure behavior " + rootSession.getReactorFailureBehavior() );
170 }
171 }
172
173 public static void attachToThread( MavenProject currentProject )
174 {
175 ClassRealm projectRealm = currentProject.getClassRealm();
176 if ( projectRealm != null )
177 {
178 Thread.currentThread().setContextClassLoader( projectRealm );
179 }
180 }
181
182 // Todo: I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some reason
183 // it isn't ? This localization is kind-of a code smell.
184
185 public static String getKey( MavenProject project )
186 {
187 return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
188 }
189
190 }