mirror of https://github.com/apache/maven.git
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:
parent
7020caf8ee
commit
b69490b828
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
it0046
|
||||
it0045
|
||||
it0044
|
||||
it0043
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
--no-plugin-registry --check-plugin-latest --fail-never
|
|
@ -0,0 +1,3 @@
|
|||
target/touch.txt
|
||||
!subproject/target/touch.txt
|
||||
subproject2/target/touch.txt
|
|
@ -0,0 +1 @@
|
|||
core-it:touch
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
#rm ${artifact:org.apache.maven.plugins:maven-core-it-plugin:1.0-SNAPSHOT:maven-plugin}
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
--no-plugin-registry --check-plugin-latest --fail-at-end
|
|
@ -0,0 +1,3 @@
|
|||
target/touch.txt
|
||||
!subproject/target/touch.txt
|
||||
subproject2/target/touch.txt
|
|
@ -0,0 +1 @@
|
|||
core-it:touch
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
#rm ${artifact:org.apache.maven.plugins:maven-core-it-plugin:1.0-SNAPSHOT:maven-plugin}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,4 +56,8 @@ public interface MavenExecutionRequest
|
|||
void setPomFile( String pomFile );
|
||||
|
||||
String getPomFile();
|
||||
|
||||
void setFailureBehavior( String failureBehavior );
|
||||
|
||||
String getFailureBehavior();
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue