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.prefix.NoPluginFoundForPrefixException;
039 import org.apache.maven.plugin.version.PluginVersionResolutionException;
040 import org.apache.maven.project.MavenProject;
041 import org.codehaus.plexus.classworlds.realm.ClassRealm;
042 import org.codehaus.plexus.component.annotations.Component;
043 import org.codehaus.plexus.component.annotations.Requirement;
044 import org.codehaus.plexus.logging.Logger;
045
046 import java.util.Set;
047
048 /**
049 * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder
050 *
051 * @since 3.0
052 * @author Kristian Rosenvold
053 * Builds one or more lifecycles for a full module
054 * NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
055 */
056 @Component( role = BuilderCommon.class )
057 public class BuilderCommon
058 {
059 @Requirement
060 private LifecycleDebugLogger lifecycleDebugLogger;
061
062 @Requirement
063 private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
064
065 @Requirement
066 private ExecutionEventCatapult eventCatapult;
067
068 @Requirement
069 private Logger logger;
070
071
072 @SuppressWarnings( { "UnusedDeclaration" } )
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 are not marked as *" );
105 logger.warn( "* @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 logger.warn( "The following plugins are not marked @threadSafe in " + project.getName() + ":" );
112 for ( Plugin unsafePlugin : unsafePlugins )
113 {
114 logger.warn( unsafePlugin.getId() );
115 }
116 logger.warn( "*****************************************************************" );
117 }
118 }
119
120 return executionPlan;
121 }
122
123 public void handleBuildError( final ReactorContext buildContext, final MavenSession rootSession,
124 final MavenProject mavenProject, Exception e, final long buildStartTime )
125 {
126 if ( e instanceof RuntimeException )
127 {
128 e = new InternalErrorException( "Internal error: " + e, e );
129 }
130
131 buildContext.getResult().addException( e );
132
133 long buildEndTime = System.currentTimeMillis();
134
135 buildContext.getResult().addBuildSummary( new BuildFailure( mavenProject, buildEndTime - buildStartTime, e ) );
136
137 eventCatapult.fire( ExecutionEvent.Type.ProjectFailed, rootSession, null, e );
138
139 if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( rootSession.getReactorFailureBehavior() ) )
140 {
141 // continue the build
142 }
143 else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( rootSession.getReactorFailureBehavior() ) )
144 {
145 // continue the build but ban all projects that depend on the failed one
146 buildContext.getReactorBuildStatus().blackList( mavenProject );
147 }
148 else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( rootSession.getReactorFailureBehavior() ) )
149 {
150 buildContext.getReactorBuildStatus().halt();
151 }
152 else
153 {
154 throw new IllegalArgumentException(
155 "invalid reactor failure behavior " + rootSession.getReactorFailureBehavior() );
156 }
157 }
158
159 public static void attachToThread( MavenProject currentProject )
160 {
161 ClassRealm projectRealm = currentProject.getClassRealm();
162 if ( projectRealm != null )
163 {
164 Thread.currentThread().setContextClassLoader( projectRealm );
165 }
166 }
167
168 // Todo: I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some reason
169 // it isn't ? This localization is kind-of a code smell.
170
171 public static String getKey( MavenProject project )
172 {
173 return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
174 }
175
176
177 }