Resolving: MNG-95

o Added --fail-fast --fail-at-end --fail-never CLI options, with appropriate summary and exclusion of dependent projects from the build when --fail-at-end is specified. Also, implemented it0046 and it1011 to test it.



git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@227490 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
John Dennis Casey 2005-08-04 21:14:51 +00:00
parent 7020caf8ee
commit b69490b828
27 changed files with 700 additions and 139 deletions

View File

@ -72,10 +72,20 @@ public class CoreItMojo
* @parameter expression="${artifactToFile}"
*/
private String artifactToFile;
/**
* @parameter expression="${fail}"
*/
private boolean fail = false;
public void execute()
throws MojoExecutionException
{
if ( fail )
{
throw new MojoExecutionException( "Failing per \'fail\' parameter (specified in pom or system properties)" );
}
touch( new File( outputDirectory ), "touch.txt" );
// This parameter should be aligned to the basedir as the parameter type is specified

View File

@ -128,6 +128,9 @@ it0044: Test --settings CLI option
it0045: Test non-reactor behavior when plugin declares "@requiresProject false"
it0046: Test fail-never reactor behavior. Forces an exception to be thrown in
the first module, but checks that the second modules is built.
-------------------------------------------------------------------------------
- generated sources
@ -182,4 +185,7 @@ it1009: Tests packaging from a plugin fails when extensions is not true.
-------------------------------------------------------------------------------
it1010: Tests a type from a plugin fails when extensions is not true.
-------------------------------------------------------------------------------
it1011: Tests the fail-at-end reactor behavior. First module fails, and second
should also run but not fail. End result should be failure of the build.
-------------------------------------------------------------------------------

View File

@ -1,3 +1,4 @@
it0046
it0045
it0044
it0043

View File

@ -1,7 +1,7 @@
<model>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0009</artifactId>
<artifactId>maven-core-it0045</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<pluginRepositories>

View File

@ -0,0 +1 @@
--no-plugin-registry --check-plugin-latest --fail-never

View File

@ -0,0 +1,3 @@
target/touch.txt
!subproject/target/touch.txt
subproject2/target/touch.txt

View File

@ -0,0 +1 @@
core-it:touch

View File

@ -0,0 +1,18 @@
<model>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<pluginRepositories>
<pluginRepository>
<id>snapshots</id>
<name>Maven Central Plugins Development Repository</name>
<url>http://snapshots.maven.codehaus.org/maven2/plugins</url>
</pluginRepository>
</pluginRepositories>
<modules>
<module>subproject</module>
<module>subproject2</module>
</modules>
</model>

View File

@ -0,0 +1 @@
#rm ${artifact:org.apache.maven.plugins:maven-core-it-plugin:1.0-SNAPSHOT:maven-plugin}

View File

@ -0,0 +1,24 @@
<model>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<version>1.0</version>
</parent>
<artifactId>maven-core-it0046-subproject</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-core-it-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<configuration>
<fail>true</fail>
</configuration>
</plugin>
</plugins>
</build>
</model>

View File

@ -0,0 +1,10 @@
<model>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<version>1.0</version>
</parent>
<artifactId>maven-core-it0046-subproject2</artifactId>
<packaging>jar</packaging>
</model>

View File

@ -0,0 +1 @@
--no-plugin-registry --check-plugin-latest --fail-at-end

View File

@ -0,0 +1,3 @@
target/touch.txt
!subproject/target/touch.txt
subproject2/target/touch.txt

View File

@ -0,0 +1 @@
core-it:touch

View File

@ -0,0 +1,18 @@
<model>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<pluginRepositories>
<pluginRepository>
<id>snapshots</id>
<name>Maven Central Plugins Development Repository</name>
<url>http://snapshots.maven.codehaus.org/maven2/plugins</url>
</pluginRepository>
</pluginRepositories>
<modules>
<module>subproject</module>
<module>subproject2</module>
</modules>
</model>

View File

@ -0,0 +1 @@
#rm ${artifact:org.apache.maven.plugins:maven-core-it-plugin:1.0-SNAPSHOT:maven-plugin}

View File

@ -0,0 +1,24 @@
<model>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<version>1.0</version>
</parent>
<artifactId>maven-core-it0046-subproject</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-core-it-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<configuration>
<fail>true</fail>
</configuration>
</plugin>
</plugins>
</build>
</model>

View File

@ -0,0 +1,10 @@
<model>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core-it0046</artifactId>
<version>1.0</version>
</parent>
<artifactId>maven-core-it0046-subproject2</artifactId>
<packaging>jar</packaging>
</model>

View File

@ -23,6 +23,7 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResponse;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.execution.RuntimeInformation;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.LifecycleExecutor;
@ -37,7 +38,6 @@ import org.apache.maven.profiles.ProfilesRoot;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectSorter;
import org.apache.maven.reactor.ReactorException;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Proxy;
@ -130,34 +130,34 @@ public class DefaultMaven
dispatcher.dispatchStart( event, request.getBaseDirectory() );
List projects;
MavenProject topLevelProject;
ReactorManager rm;
try
{
List files = getProjectFiles( request );
projects = collectProjects( files, request.getLocalRepository(), request.isRecursive(),
List projects = collectProjects( files, request.getLocalRepository(), request.isRecursive(),
request.getSettings() );
// the reasoning here is that the list is still unsorted according to dependency, so the first project
// SHOULD BE the top-level, or the one we want to start with if we're doing an aggregated build.
if ( !projects.isEmpty() )
{
// TODO: !![jc; 28-jul-2005] check this; if we're using '-r' and there are aggregator tasks, this will result in weirdness.
topLevelProject = findTopLevelProject( projects, request.getPomFile() );
projects = ProjectSorter.getSortedProjects( projects );
}
else
if ( projects.isEmpty() )
{
List externalProfiles = getActiveExternalProfiles( null, request.getSettings() );
topLevelProject = projectBuilder.buildStandaloneSuperProject( request.getLocalRepository(),
MavenProject superProject = projectBuilder.buildStandaloneSuperProject( request.getLocalRepository(),
externalProfiles );
projects.add( topLevelProject );
projects.add( superProject );
}
rm = new ReactorManager( projects );
String requestFailureBehavior = request.getFailureBehavior();
if ( requestFailureBehavior != null )
{
rm.setFailureBehavior( requestFailureBehavior );
}
}
catch ( IOException e )
@ -166,48 +166,24 @@ public class DefaultMaven
}
catch ( ArtifactResolutionException e )
{
dispatcher.dispatchError( event, request.getBaseDirectory(), e );
MavenExecutionResponse response = new MavenExecutionResponse();
response.setStart( new Date() );
response.setFinish( new Date() );
response.setException( e );
logFailure( response, e, null );
return response;
return dispatchErrorResponse( dispatcher, event, request.getBaseDirectory(), e );
}
catch ( ProjectBuildingException e )
{
dispatcher.dispatchError( event, request.getBaseDirectory(), e );
MavenExecutionResponse response = new MavenExecutionResponse();
response.setStart( new Date() );
response.setFinish( new Date() );
response.setException( e );
logFailure( response, e, null );
return response;
return dispatchErrorResponse( dispatcher, event, request.getBaseDirectory(), e );
}
catch ( CycleDetectedException e )
{
dispatcher.dispatchError( event, request.getBaseDirectory(), e );
MavenExecutionResponse response = new MavenExecutionResponse();
response.setStart( new Date() );
response.setFinish( new Date() );
response.setException( e );
logFailure( response, e, null );
return response;
return dispatchErrorResponse( dispatcher, event, request.getBaseDirectory(), e );
}
try
{
MavenSession session = createSession( request, projects );
MavenSession session = createSession( request, rm );
try
{
MavenExecutionResponse response = lifecycleExecutor.execute( session, topLevelProject, dispatcher );
MavenExecutionResponse response = lifecycleExecutor.execute( session, rm, dispatcher );
// TODO: is this perhaps more appropriate in the CLI?
if ( response.isExecutionFailure() )
@ -217,7 +193,16 @@ public class DefaultMaven
// TODO: yuck! Revisit when cleaning up the exception handling from the top down
Throwable exception = response.getException();
if ( exception instanceof MojoExecutionException )
if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) && ( exception instanceof ReactorException ) )
{
logFailure( response, exception, null );
if ( rm.hasMultipleProjects() )
{
writeReactorSummary( rm );
}
}
else if ( exception instanceof MojoExecutionException )
{
if ( exception.getCause() == null )
{
@ -248,7 +233,7 @@ public class DefaultMaven
}
else
{
logSuccess( response );
logSuccess( response, rm );
}
}
catch ( LifecycleExecutionException e )
@ -269,47 +254,74 @@ public class DefaultMaven
}
}
private MavenProject findTopLevelProject( List projects, String customPomPath ) throws IOException
private void writeReactorSummary( ReactorManager rm )
{
File topPomFile;
// -------------------------
// Reactor Summary:
// -------------------------
// o project-name...........FAILED
// o project2-name..........SKIPPED (dependency build failed or was skipped)
// o project-3-name.........SUCCESS
if ( customPomPath != null )
{
topPomFile = new File( customPomPath ).getCanonicalFile();
}
else
{
topPomFile = new File( userDir, RELEASE_POMv4 );
if ( !topPomFile.exists() )
{
topPomFile = new File( userDir, POMv4 );
if ( !topPomFile.exists() )
{
getLogger().warn( "Cannot find top-level project file in directory: " + userDir + ". Using first project in project-list." );
return (MavenProject) projects.get( 0 );
}
}
}
line();
getLogger().info( "Reactor Summary:" );
line();
MavenProject topProject = null;
for ( Iterator it = projects.iterator(); it.hasNext(); )
for ( Iterator it = rm.getProjectsSortedByDependency().iterator(); it.hasNext(); )
{
MavenProject project = (MavenProject) it.next();
File projectFile = project.getFile().getCanonicalFile();
String id = project.getId();
if ( topPomFile.equals( projectFile ) )
if ( rm.hasBuildFailure( id ) )
{
topProject = project;
break;
logReactorSummaryLine( project.getName(), "FAILED" );
}
else if ( rm.isBlackListed( id ) )
{
logReactorSummaryLine( project.getName(), "SKIPPED (dependency build failed or was skipped)" );
}
else
{
logReactorSummaryLine( project.getName(), "SUCCESS" );
}
}
return topProject;
getLogger().info( "" );
getLogger().info( "" );
}
private void logReactorSummaryLine( String name, String status )
{
StringBuffer messageBuffer = new StringBuffer();
messageBuffer.append( name );
int dotCount = 65;
dotCount -= name.length();
for ( int i = 0; i < dotCount; i++ )
{
messageBuffer.append( '.' );
}
messageBuffer.append( status );
getLogger().info( messageBuffer.toString() );
}
private MavenExecutionResponse dispatchErrorResponse( EventDispatcher dispatcher, String event, String baseDirectory, Exception e )
{
dispatcher.dispatchError( event, baseDirectory, e );
MavenExecutionResponse response = new MavenExecutionResponse();
response.setStart( new Date() );
response.setFinish( new Date() );
response.setException( e );
logFailure( response, e, null );
return response;
}
private List collectProjects( List files, ArtifactRepository localRepository, boolean recursive, Settings settings )
@ -445,10 +457,10 @@ public class DefaultMaven
// the session type would be specific to the request i.e. having a project
// or not.
protected MavenSession createSession( MavenExecutionRequest request, List projects )
protected MavenSession createSession( MavenExecutionRequest request, ReactorManager rpm )
{
return new MavenSession( container, request.getSettings(), request.getLocalRepository(),
request.getEventDispatcher(), projects, request.getGoals(),
request.getEventDispatcher(), rpm, request.getGoals(),
request.getBaseDirectory() );
}
@ -601,8 +613,13 @@ public class DefaultMaven
line();
}
protected void logSuccess( MavenExecutionResponse r )
protected void logSuccess( MavenExecutionResponse r, ReactorManager rm )
{
if ( rm.hasMultipleProjects() )
{
writeReactorSummary( rm );
}
line();
getLogger().info( "BUILD SUCCESSFUL" );
@ -635,7 +652,7 @@ public class DefaultMaven
{
getLogger().info( "----------------------------------------------------------------------------" );
}
protected static String formatTime( long ms )
{
long secs = ms / MS_PER_SEC;

View File

@ -33,6 +33,7 @@ import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResponse;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.monitor.event.DefaultEventDispatcher;
import org.apache.maven.monitor.event.DefaultEventMonitor;
import org.apache.maven.monitor.event.EventDispatcher;
@ -344,6 +345,20 @@ public class MavenCli
{
request.setRecursive( false );
}
if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
{
request.setFailureBehavior( ReactorManager.FAIL_FAST );
}
else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
{
request.setFailureBehavior( ReactorManager.FAIL_AT_END );
}
else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
{
request.setFailureBehavior( ReactorManager.FAIL_NEVER );
}
return request;
}
@ -535,6 +550,12 @@ public class MavenCli
private static final char ALTERNATE_USER_SETTINGS = 's';
private static final String FAIL_FAST = "ff";
private static final String FAIL_AT_END = "fae";
private static final String FAIL_NEVER = "fn";
public CLIManager()
{
options = new Options();
@ -594,6 +615,12 @@ public class MavenCli
options.addOption( OptionBuilder.withLongOpt( "settings" )
.withDescription( "Alternate path for the user settings file" ).hasArg()
.create( ALTERNATE_USER_SETTINGS ) );
options.addOption( OptionBuilder.withLongOpt( "fail-fast" ).withDescription( "Stop at first failure in reactorized builds" ).create( FAIL_FAST ) );
options.addOption( OptionBuilder.withLongOpt( "fail-at-end" ).withDescription( "Only fail the build afterwards; allow all non-impacted builds to continue" ).create( FAIL_AT_END ) );
options.addOption( OptionBuilder.withLongOpt( "fail-never" ).withDescription( "NEVER fail the build, regardless of project result" ).create( FAIL_NEVER ) );
}
public CommandLine parse( String[] args )

View File

@ -51,6 +51,8 @@ public class DefaultMavenExecutionRequest
private String pomFilename;
private String failureBehavior;
public DefaultMavenExecutionRequest( ArtifactRepository localRepository, Settings settings,
EventDispatcher eventDispatcher, List goals, String baseDirectory )
{
@ -138,4 +140,14 @@ public class DefaultMavenExecutionRequest
{
return pomFilename;
}
public void setFailureBehavior( String failureBehavior )
{
this.failureBehavior = failureBehavior;
}
public String getFailureBehavior()
{
return failureBehavior;
}
}

View File

@ -56,4 +56,8 @@ public interface MavenExecutionRequest
void setPomFile( String pomFile );
String getPomFile();
void setFailureBehavior( String failureBehavior );
String getFailureBehavior();
}

View File

@ -45,12 +45,12 @@ public class MavenSession
// TODO: make this the central one, get rid of build settings...
private final Settings settings;
private List sortedProjects;
private ReactorManager rpm;
private final String executionRootDir;
public MavenSession( PlexusContainer container, Settings settings, ArtifactRepository localRepository,
EventDispatcher eventDispatcher, List sortedProjects, List goals, String executionRootDir )
EventDispatcher eventDispatcher, ReactorManager rpm, List goals, String executionRootDir )
{
this.container = container;
@ -60,7 +60,7 @@ public class MavenSession
this.eventDispatcher = eventDispatcher;
this.sortedProjects = sortedProjects;
this.rpm = rpm;
this.goals = goals;
@ -132,7 +132,7 @@ public class MavenSession
public List getSortedProjects()
{
return sortedProjects;
return rpm.getProjectsSortedByDependency();
}
public String getExecutionRootDirectory()

View File

@ -0,0 +1,275 @@
package org.apache.maven.execution;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Extension;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.dag.CycleDetectedException;
import org.codehaus.plexus.util.dag.DAG;
import org.codehaus.plexus.util.dag.TopologicalSorter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class ReactorManager
{
public static final String FAIL_FAST = "fail-fast";
public static final String FAIL_AT_END = "fail-at-end";
public static final String FAIL_NEVER = "fail-never";
private DAG reactorDag;
private Map projectMap;
private List projectsByDependency;
private List blackList = new ArrayList();
private MavenProject topLevelProject;
private Map buildFailuresByProject = new HashMap();
private String failureBehavior = FAIL_FAST;
public ReactorManager( List projects )
throws CycleDetectedException
{
reactorDag = new DAG();
projectMap = new HashMap();
for ( Iterator i = projects.iterator(); i.hasNext(); )
{
MavenProject project = (MavenProject) i.next();
String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
reactorDag.addVertex( id );
projectMap.put( id, project );
}
for ( Iterator i = projects.iterator(); i.hasNext(); )
{
MavenProject project = (MavenProject) i.next();
String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
for ( Iterator j = project.getDependencies().iterator(); j.hasNext(); )
{
Dependency dependency = (Dependency) j.next();
String dependencyId = ArtifactUtils.versionlessKey( dependency.getGroupId(), dependency.getArtifactId() );
if ( reactorDag.getVertex( dependencyId ) != null )
{
project.addProjectReference( (MavenProject) projectMap.get( dependencyId ) );
reactorDag.addEdge( id, dependencyId );
}
}
MavenProject parent = project.getParent();
if ( parent != null )
{
String parentId = ArtifactUtils.versionlessKey( parent.getGroupId(), parent.getArtifactId() );
if ( reactorDag.getVertex( parentId ) != null )
{
reactorDag.addEdge( id, parentId );
}
}
List buildPlugins = project.getBuildPlugins();
if ( buildPlugins != null )
{
for ( Iterator j = buildPlugins.iterator(); j.hasNext(); )
{
Plugin plugin = (Plugin) j.next();
String pluginId = ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() );
if ( reactorDag.getVertex( pluginId ) != null )
{
reactorDag.addEdge( id, pluginId );
}
}
}
List reportPlugins = project.getReportPlugins();
if ( reportPlugins != null )
{
for ( Iterator j = reportPlugins.iterator(); j.hasNext(); )
{
ReportPlugin plugin = (ReportPlugin) j.next();
String pluginId = ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() );
if ( reactorDag.getVertex( pluginId ) != null )
{
reactorDag.addEdge( id, pluginId );
}
}
}
for ( Iterator j = project.getBuildExtensions().iterator(); j.hasNext(); )
{
Extension extension = (Extension) j.next();
String extensionId = ArtifactUtils.versionlessKey( extension.getGroupId(), extension.getArtifactId() );
if ( reactorDag.getVertex( extensionId ) != null )
{
reactorDag.addEdge( id, extensionId );
}
}
}
projectsByDependency = new ArrayList();
for ( Iterator i = TopologicalSorter.sort( reactorDag ).iterator(); i.hasNext(); )
{
String id = (String) i.next();
projectsByDependency.add( projectMap.get( id ) );
}
projectsByDependency = Collections.unmodifiableList( projectsByDependency );
}
public void setFailureBehavior( String failureBehavior )
{
if ( FAIL_FAST.equals( failureBehavior ) || FAIL_AT_END.equals( failureBehavior ) || FAIL_NEVER.equals( failureBehavior ) )
{
this.failureBehavior = failureBehavior;
}
else
{
throw new IllegalArgumentException( "Invalid failure behavior (must be one of: \'" + FAIL_FAST + "\', \'"
+ FAIL_AT_END + "\', \'" + FAIL_NEVER + "\')." );
}
}
public String getFailureBehavior()
{
return failureBehavior;
}
public List getProjectsSortedByDependency()
{
return projectsByDependency;
}
// TODO: !![jc; 28-jul-2005] check this; if we're using '-r' and there are aggregator tasks, this will result in weirdness.
public MavenProject getTopLevelProject()
{
if ( topLevelProject == null )
{
List projectsByFile = new ArrayList( projectsByDependency );
Collections.sort(projectsByFile, new ByProjectFileComparator() );
topLevelProject = (MavenProject) projectsByFile.get( 0 );
}
return topLevelProject;
}
public void blackList( String id )
{
if ( !blackList.contains( id ) )
{
blackList.add( id );
List dependents = reactorDag.getParentLabels( id );
if ( dependents != null && !dependents.isEmpty() )
{
for ( Iterator it = dependents.iterator(); it.hasNext(); )
{
String dependentId = (String) it.next();
blackList( dependentId );
}
}
}
}
public boolean isBlackListed( String id )
{
return blackList.contains( id );
}
public void registerBuildFailure( MavenProject project, Exception error, String task )
{
buildFailuresByProject.put( project.getId(), new BuildFailure( error, task ) );
}
public boolean hasBuildFailures()
{
return !buildFailuresByProject.isEmpty();
}
public boolean hasBuildFailure( String id )
{
return buildFailuresByProject.containsKey( id );
}
public boolean hasMultipleProjects()
{
return projectsByDependency.size() > 1;
}
private static class ByProjectFileComparator implements Comparator
{
public int compare( Object first, Object second )
{
MavenProject p1 = (MavenProject) first;
MavenProject p2 = (MavenProject) second;
String p1Path = p1.getFile().getAbsolutePath();
String p2Path = p2.getFile().getAbsolutePath();
int comparison = p1Path.length() - p2Path.length();
if ( comparison > 0 )
{
return 1;
}
else if ( comparison < 0 )
{
return -1;
}
else
{
return 0;
}
}
}
private static class BuildFailure
{
private Exception cause;
private String task;
BuildFailure( Exception cause, String task )
{
this.cause = cause;
this.task = task;
}
String getTask()
{
return task;
}
Exception getCause()
{
return cause;
}
}
}

View File

@ -23,6 +23,7 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.execution.MavenExecutionResponse;
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;
@ -45,6 +46,7 @@ import org.apache.maven.plugin.lifecycle.Phase;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.injection.ModelDefaultsInjector;
import org.apache.maven.reactor.ReactorException;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusContainerException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
@ -100,9 +102,11 @@ public class DefaultLifecycleExecutor
* @param project
* @param dispatcher
*/
public MavenExecutionResponse execute( MavenSession session, MavenProject project, EventDispatcher dispatcher )
public MavenExecutionResponse execute( MavenSession session, ReactorManager rm, EventDispatcher dispatcher )
throws LifecycleExecutionException
{
MavenProject project = rm.getTopLevelProject();
List taskSegments = segmentTaskListByAggregationNeeds( session.getGoals(), session, project );
MavenExecutionResponse response = new MavenExecutionResponse();
@ -120,7 +124,12 @@ public class DefaultLifecycleExecutor
Map handlers = findArtifactTypeHandlers( project, session.getSettings(), session.getLocalRepository() );
artifactHandlerManager.addHandlers( handlers );
executeTaskSegments( taskSegments, session, project, dispatcher );
executeTaskSegments( taskSegments, rm, session, project, dispatcher );
if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) && rm.hasBuildFailures() )
{
response.setException( new ReactorException( "One or more projects failed to build." ) );
}
}
catch ( MojoExecutionException e )
{
@ -154,8 +163,8 @@ public class DefaultLifecycleExecutor
return response;
}
private void executeTaskSegments( List taskSegments, MavenSession session, MavenProject project,
EventDispatcher dispatcher )
private void executeTaskSegments( List taskSegments, ReactorManager rm, MavenSession session, MavenProject project,
EventDispatcher dispatcher )
throws PluginNotFoundException, MojoExecutionException, ArtifactResolutionException, LifecycleExecutionException
{
for ( Iterator it = taskSegments.iterator(); it.hasNext(); )
@ -164,37 +173,63 @@ public class DefaultLifecycleExecutor
if ( segment.aggregate() )
{
line();
getLogger().info( "Building " + project.getName() );
getLogger().info( " " + segment );
line();
// !! This is ripe for refactoring to an aspect.
// Event monitoring.
String event = MavenEvents.PROJECT_EXECUTION;
dispatcher.dispatchStart( event, project.getId() + " ( " + segment + " )" );
try
if ( !rm.isBlackListed( project.getId() ) )
{
// only call once, with the top-level project (assumed to be provided as a parameter)...
for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
line();
getLogger().info( "Building " + project.getName() );
getLogger().info( " " + segment );
line();
// !! This is ripe for refactoring to an aspect.
// Event monitoring.
String event = MavenEvents.PROJECT_EXECUTION;
dispatcher.dispatchStart( event, project.getId() + " ( " + segment + " )" );
try
{
String task = (String) goalIterator.next();
// 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();
executeGoal( task, session, project );
try
{
executeGoal( task, session, project );
}
catch ( MojoExecutionException e )
{
handleExecutionFailure( rm, project, e, task );
}
catch ( ArtifactResolutionException e )
{
handleExecutionFailure( rm, project, e, task );
}
}
dispatcher.dispatchEnd( event, project.getId() + " ( " + segment + " )" );
}
catch ( LifecycleExecutionException e )
{
dispatcher.dispatchError( event, project.getId() + " ( " + segment + " )", e );
dispatcher.dispatchEnd( event, project.getId() + " ( " + segment + " )" );
throw e;
}
}
catch ( LifecycleExecutionException e )
else
{
dispatcher.dispatchError( event, project.getId() + " ( " + segment + " )", e );
line();
throw e;
getLogger().info( "SKIPPING " + project.getName() );
getLogger().info( " " + segment );
getLogger().info( "This project has been banned from further executions due to previous failures." );
line();
}
}
else
@ -206,42 +241,98 @@ public class DefaultLifecycleExecutor
{
MavenProject currentProject = (MavenProject) projectIterator.next();
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;
dispatcher.dispatchStart( event, currentProject.getId() + " ( " + segment + " )" );
try
if ( !rm.isBlackListed( currentProject.getId() ) )
{
for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
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;
dispatcher.dispatchStart( event, currentProject.getId() + " ( " + segment + " )" );
try
{
String task = (String) goalIterator.next();
for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
{
String task = (String) goalIterator.next();
executeGoal( task, session, currentProject );
try
{
executeGoal( task, session, currentProject );
}
catch ( MojoExecutionException e )
{
handleExecutionFailure( rm, project, e, task );
}
catch ( ArtifactResolutionException e )
{
handleExecutionFailure( rm, project, e, task );
}
}
dispatcher.dispatchEnd( event, currentProject.getId() + " ( " + segment + " )" );
}
catch ( LifecycleExecutionException e )
{
dispatcher.dispatchError( event, currentProject.getId() + " ( " + segment + " )", e );
dispatcher.dispatchEnd( event, currentProject.getId() + " ( " + segment + " )" );
throw e;
}
}
catch ( LifecycleExecutionException e )
else
{
dispatcher.dispatchError( event, currentProject.getId() + " ( " + segment + " )", e );
line();
throw e;
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 handleExecutionFailure( ReactorManager rm, MavenProject project, Exception e, String task )
throws MojoExecutionException, ArtifactResolutionException
{
if ( ReactorManager.FAIL_FAST.equals( rm.getFailureBehavior() ) )
{
rm.registerBuildFailure( project, e, task );
if ( e instanceof MojoExecutionException )
{
throw (MojoExecutionException) e;
}
else if ( e instanceof ArtifactResolutionException )
{
throw (ArtifactResolutionException) e;
}
else
{
getLogger().error( "Attempt to register inappropriate build-failure Exception.", e );
throw new IllegalArgumentException( "Inappropriate build-failure Exception: " + e );
}
}
else if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) )
{
rm.registerBuildFailure( project, e, task );
rm.blackList( project.getId() );
}
}
private List segmentTaskListByAggregationNeeds( List tasks, MavenSession session, MavenProject project )
{
List segments = new ArrayList();

View File

@ -18,8 +18,8 @@ package org.apache.maven.lifecycle;
import org.apache.maven.execution.MavenExecutionResponse;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.monitor.event.EventDispatcher;
import org.apache.maven.project.MavenProject;
/**
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
@ -29,7 +29,7 @@ public interface LifecycleExecutor
{
String ROLE = LifecycleExecutor.class.getName();
MavenExecutionResponse execute( MavenSession session, MavenProject project, EventDispatcher dispatcher )
MavenExecutionResponse execute( MavenSession session, ReactorManager rpm, EventDispatcher dispatcher )
throws LifecycleExecutionException;
}

View File

@ -22,6 +22,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.model.Build;
import org.apache.maven.model.Model;
import org.apache.maven.monitor.event.DefaultEventDispatcher;
@ -31,6 +32,7 @@ import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.util.dag.CycleDetectedException;
import java.io.File;
import java.util.Collections;
@ -67,10 +69,10 @@ public class PluginParameterExpressionEvaluatorTest
}
private static MavenSession createSession( PlexusContainer container,
ArtifactRepository repo )
ArtifactRepository repo ) throws CycleDetectedException
{
return new MavenSession( container, new Settings(), repo, new DefaultEventDispatcher(),
Collections.EMPTY_LIST, Collections.EMPTY_LIST, "." );
new ReactorManager( Collections.EMPTY_LIST ), Collections.EMPTY_LIST, "." );
}
public void testLocalRepositoryExtraction()