o Restored reactor failure behaviors

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@792111 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-07-08 12:23:46 +00:00
parent 88062f08dd
commit 52519425f7
7 changed files with 265 additions and 49 deletions

View File

@ -146,6 +146,8 @@ public class DefaultMaven
projects = projectSorter.getSortedProjects();
session.setProjects( projects );
session.setProjectDependencyGraph( new DefaultProjectDependencyGraph( projectSorter ) );
}
catch ( CycleDetectedException e )
{

View File

@ -0,0 +1,105 @@
package org.apache.maven;
/*
* 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 java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.execution.ProjectSorter;
import org.apache.maven.project.MavenProject;
/**
* Describes the inter-dependencies between projects in the reactor.
*
* @author Benjamin Bentmann
*/
class DefaultProjectDependencyGraph
implements ProjectDependencyGraph
{
private ProjectSorter sorter;
/**
* Creates a new project dependency graph based on the specified project sorting.
*
* @param sorter The project sorter backing the graph, must not be {@code null}.
*/
public DefaultProjectDependencyGraph( ProjectSorter sorter )
{
if ( sorter == null )
{
throw new IllegalArgumentException( "project sorter missing" );
}
this.sorter = sorter;
}
public List<MavenProject> getSortedProjects()
{
return new ArrayList<MavenProject>( sorter.getSortedProjects() );
}
public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
{
if ( project == null )
{
throw new IllegalArgumentException( "project missing" );
}
Collection<String> projectIds = new HashSet<String>();
getDownstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
List<MavenProject> projects = new ArrayList<MavenProject>();
for ( MavenProject p : sorter.getSortedProjects() )
{
if ( projectIds.contains( ProjectSorter.getId( p ) ) )
{
projects.add( p );
}
}
return projects;
}
private void getDownstreamProjects( String projectId, Collection<String> projectIds, boolean transitive )
{
for ( String id : sorter.getDependents( projectId ) )
{
projectIds.add( id );
if ( transitive )
{
getDownstreamProjects( id, projectIds, transitive );
}
}
}
@Override
public String toString()
{
return sorter.getSortedProjects().toString();
}
}

View File

@ -20,7 +20,9 @@ package org.apache.maven.execution;
*/
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -53,7 +55,11 @@ public class MavenSession
private List<MavenProject> projects;
private MavenProject topLevelProject;
private ProjectDependencyGraph projectDependencyGraph;
private Collection<String> blackListedProjects;
@Deprecated
public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, MavenProject project )
{
@ -198,4 +204,40 @@ public class MavenSession
return pluginContext;
}
public void setProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph )
{
this.projectDependencyGraph = projectDependencyGraph;
}
public String getReactorFailureBehavior()
{
return request.getReactorFailureBehavior();
}
public boolean isBlackListed( MavenProject project )
{
return blackListedProjects != null && blackListedProjects.contains( getId( project ) );
}
public void blackList( MavenProject project )
{
if ( blackListedProjects == null )
{
blackListedProjects = new HashSet<String>();
}
if ( blackListedProjects.add( getId( project ) ) && projectDependencyGraph != null )
{
for ( MavenProject downstreamProject : projectDependencyGraph.getDownstreamProjects( project, true ) )
{
blackListedProjects.add( getId( downstreamProject ) );
}
}
}
private String getId( MavenProject project )
{
return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
}
}

View File

@ -0,0 +1,53 @@
package org.apache.maven.execution;
/*
* 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 java.util.List;
import org.apache.maven.project.MavenProject;
/**
* Describes the inter-dependencies between projects in the reactor.
*
* @author Benjamin Bentmann
*/
public interface ProjectDependencyGraph
{
/**
* Gets all projects in their intended build order, i.e. after topologically sorting the projects according to their
* inter-dependencies.
*
* @return The projects in the build order, never {@code null}.
*/
List<MavenProject> getSortedProjects();
/**
* Gets the downstream projects of the specified projects. A downstream project is a project that directly or
* indirectly depends on the given project.
*
* @param project The project whose downstream projects should be retrieved, must not be {@code null}.
* @param transitive A flag whether to retrieve all direct and indirect downstream projects or just the immediate
* downstream projects.
* @return The downstream projects in the build order, never {@code null}.
*/
List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive );
}

View File

@ -58,11 +58,11 @@ public class ProjectSorter
for ( MavenProject project : projects )
{
String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
String id = getId( project );
if ( dag.getVertex( id ) != null )
{
MavenProject conflictingProject = (MavenProject) projectMap.get( id );
MavenProject conflictingProject = projectMap.get( id );
throw new DuplicateProjectException( id, conflictingProject.getFile(), project.getFile(), "Project '" + id + "' is duplicated in the reactor" );
}
@ -74,7 +74,7 @@ public class ProjectSorter
for ( MavenProject project : projects )
{
String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
String id = getId( project );
for( Dependency dependency : project.getDependencies() )
{
@ -82,7 +82,7 @@ public class ProjectSorter
if ( dag.getVertex( dependencyId ) != null )
{
project.addProjectReference( (MavenProject) projectMap.get( dependencyId ) );
project.addProjectReference( projectMap.get( dependencyId ) );
dag.addEdge( id, dependencyId );
}
@ -139,7 +139,7 @@ public class ProjectSorter
private void addEdgeWithParentCheck( Map<String,MavenProject> projectMap, String projectRefId, MavenProject project, String id )
throws CycleDetectedException
{
MavenProject extProject = (MavenProject) projectMap.get( projectRefId );
MavenProject extProject = projectMap.get( projectRefId );
if ( extProject == null )
{
@ -165,9 +165,9 @@ public class ProjectSorter
{
if ( topLevelProject == null )
{
for ( Iterator i = sortedProjects.iterator(); i.hasNext() && ( topLevelProject == null ); )
for ( Iterator<MavenProject> i = sortedProjects.iterator(); i.hasNext() && ( topLevelProject == null ); )
{
MavenProject project = (MavenProject) i.next();
MavenProject project = i.next();
if ( project.isExecutionRoot() )
{
topLevelProject = project;
@ -188,8 +188,14 @@ public class ProjectSorter
return sortedProjects.size() > 1;
}
List<String> getDependents( String id )
public List<String> getDependents( String id )
{
return dag.getParentLabels( id );
}
}
public static String getId( MavenProject project )
{
return ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
}
}

View File

@ -35,8 +35,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.metadata.Metadata;
import org.apache.maven.artifact.repository.metadata.RepositoryMetadataReadException;
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.mapping.LifecycleMapping;
import org.apache.maven.model.Dependency;
@ -144,43 +143,27 @@ public class DefaultLifecycleExecutor
for ( MavenProject currentProject : session.getProjects() )
{
if ( session.isBlackListed( currentProject ) )
{
logger.info( "Skipping " + currentProject.getName() );
logger.info( "This project has been banned from the build due to previous failures." );
continue;
}
logger.info( "Building " + currentProject.getName() );
try
{
session.setCurrentProject( currentProject );
MavenExecutionPlan executionPlan;
try
{
executionPlan = calculateExecutionPlan( session, goals.toArray( new String[] {} ) );
}
catch ( Exception e )
{
session.getResult().addException( e );
return;
}
MavenExecutionPlan executionPlan = calculateExecutionPlan( session, goals.toArray( new String[] {} ) );
//TODO: once we have calculated the build plan then we should accurately be able to download
// the project dependencies. Having it happen in the plugin manager is a tangled mess. We can optimize this
// later by looking at the build plan. Would be better to just batch download everything required by the reactor.
// mojoDescriptor.isDependencyResolutionRequired() is actually the scope of the dependency resolution required, not a boolean ... yah.
try
{
projectDependenciesResolver.resolve( currentProject, executionPlan.getRequiredResolutionScopes(), session.getLocalRepository(), currentProject.getRemoteArtifactRepositories() );
}
catch ( ArtifactNotFoundException e )
{
session.getResult().addException( e );
return;
}
catch ( ArtifactResolutionException e )
{
session.getResult().addException( e );
return;
}
projectDependenciesResolver.resolve( currentProject, executionPlan.getRequiredResolutionScopes(), session.getLocalRepository(), currentProject.getRemoteArtifactRepositories() );
if ( logger.isDebugEnabled() )
{
@ -200,19 +183,35 @@ public class DefaultLifecycleExecutor
for ( MojoExecution mojoExecution : executionPlan.getExecutions() )
{
try
{
logger.info( executionDescription( mojoExecution, currentProject ) );
pluginManager.executeMojo( session, mojoExecution );
}
catch ( Exception e )
{
session.getResult().addException( e );
return;
}
logger.info( executionDescription( mojoExecution, currentProject ) );
pluginManager.executeMojo( session, mojoExecution );
}
}
catch ( Exception e )
{
session.getResult().addException( e );
if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( session.getReactorFailureBehavior() ) )
{
// continue the build
}
else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( session.getReactorFailureBehavior() ) )
{
// continue the build but ban all projects that depend on the failed one
session.blackList( currentProject );
}
else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( session.getReactorFailureBehavior() ) )
{
// abort the build
return;
}
else
{
throw new IllegalArgumentException( "invalid reactor failure behavior "
+ session.getReactorFailureBehavior() );
}
}
finally
{
session.setCurrentProject( null );

View File

@ -192,7 +192,16 @@ public class MavenCli
es.getException().printStackTrace();
}
return 1;
if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( request.getReactorFailureBehavior() ) )
{
System.out.println( "+ Build failures were ignored." );
return 0;
}
else
{
return 1;
}
}
else
{