[MNG-2576] Make Like Reactor Mode

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@794043 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-07-14 20:03:15 +00:00
parent 433d4bf3b8
commit df47b11957
9 changed files with 386 additions and 21 deletions

View File

@ -22,6 +22,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -36,6 +37,7 @@
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.execution.ProjectSorter;
import org.apache.maven.lifecycle.LifecycleExecutor;
import org.apache.maven.project.MavenProject;
@ -140,14 +142,14 @@ public MavenExecutionResult execute( MavenExecutionRequest request )
}
try
{
{
ProjectSorter projectSorter = new ProjectSorter( session.getProjects() );
projects = projectSorter.getSortedProjects();
ProjectDependencyGraph projectDependencyGraph = createDependencyGraph( projectSorter, request );
session.setProjects( projects );
session.setProjects( projectDependencyGraph.getSortedProjects() );
session.setProjectDependencyGraph( new DefaultProjectDependencyGraph( projectSorter ) );
session.setProjectDependencyGraph( projectDependencyGraph );
}
catch ( CycleDetectedException e )
{
@ -161,6 +163,10 @@ public MavenExecutionResult execute( MavenExecutionRequest request )
{
return processResult( result, e );
}
catch ( MavenExecutionException e )
{
return processResult( result, e );
}
// Desired order of precedence for local artifact repositories
//
@ -293,6 +299,8 @@ private void collectProjects( List<MavenProject> projects, List<File> files, Mav
for ( File file : files )
{
MavenProject project = projectBuilder.build( file, request.getProjectBuildingRequest() );
projects.add( project );
if ( ( project.getModules() != null ) && !project.getModules().isEmpty() && request.isRecursive() )
{
@ -340,8 +348,6 @@ else if ( moduleFile.isDirectory() )
collectProjects( projects, moduleFiles, request );
}
projects.add( project );
}
}
@ -368,4 +374,90 @@ protected Logger getLogger()
return logger;
}
private ProjectDependencyGraph createDependencyGraph( ProjectSorter sorter, MavenExecutionRequest request )
throws MavenExecutionException
{
ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( sorter );
if ( !request.getSelectedProjects().isEmpty() )
{
File reactorDirectory = request.getPom().getParentFile().getAbsoluteFile();
Map<File, MavenProject> projectsByFile = new HashMap<File, MavenProject>();
for ( MavenProject project : sorter.getSortedProjects() )
{
projectsByFile.put( project.getFile(), project );
}
List<MavenProject> selectedProjects = new ArrayList<MavenProject>( request.getSelectedProjects().size() );
for ( String selectedProject : request.getSelectedProjects() )
{
File pomFile = new File( reactorDirectory, selectedProject );
if ( pomFile.isDirectory() )
{
pomFile = new File( pomFile, Maven.POMv4 );
}
MavenProject project = projectsByFile.get( pomFile );
if ( project != null )
{
selectedProjects.add( project );
}
else
{
throw new MavenExecutionException( "Could not find project in reactor: " + selectedProject,
request.getPom() );
}
}
boolean makeUpstream = false;
boolean makeDownstream = false;
if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
{
makeUpstream = true;
}
else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
{
makeDownstream = true;
}
else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
{
makeUpstream = true;
makeDownstream = true;
}
else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
{
throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
request.getPom() );
}
Collection<MavenProject> makeProjects = new LinkedHashSet<MavenProject>( selectedProjects );
if ( makeUpstream || makeDownstream )
{
for ( MavenProject selectedProject : selectedProjects )
{
if ( makeUpstream )
{
makeProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
}
if ( makeDownstream )
{
makeProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
}
}
}
// TODO: process resume from
graph = new FilteredProjectDependencyGraph( graph, makeProjects );
}
return graph;
}
}

View File

@ -70,17 +70,7 @@ public List<MavenProject> getDownstreamProjects( MavenProject project, boolean t
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;
return getProjects( projectIds );
}
private void getDownstreamProjects( String projectId, Collection<String> projectIds, boolean transitive )
@ -96,6 +86,48 @@ private void getDownstreamProjects( String projectId, Collection<String> project
}
}
public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
{
if ( project == null )
{
throw new IllegalArgumentException( "project missing" );
}
Collection<String> projectIds = new HashSet<String>();
getUpstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
return getProjects( projectIds );
}
private void getUpstreamProjects( String projectId, Collection<String> projectIds, boolean transitive )
{
for ( String id : sorter.getDependencies( projectId ) )
{
projectIds.add( id );
if ( transitive )
{
getUpstreamProjects( id, projectIds, transitive );
}
}
}
private List<MavenProject> getProjects( Collection<String> projectIds )
{
List<MavenProject> projects = new ArrayList<MavenProject>();
for ( MavenProject p : sorter.getSortedProjects() )
{
if ( projectIds.contains( ProjectSorter.getId( p ) ) )
{
projects.add( p );
}
}
return projects;
}
@Override
public String toString()
{

View File

@ -0,0 +1,111 @@
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.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.project.MavenProject;
/**
* Provides a sub view of another dependency graph.
*
* @author Benjamin Bentmann
*/
class FilteredProjectDependencyGraph
implements ProjectDependencyGraph
{
private ProjectDependencyGraph projectDependencyGraph;
private Map<MavenProject, ?> whiteList;
private List<MavenProject> sortedProjects;
/**
* Creates a new project dependency graph from the specified graph.
*
* @param projectDependencyGraph The project dependency graph to create a sub view from, must not be {@code null}.
* @param whiteList The projects on which the dependency view should focus, must not be {@code null}.
*/
public FilteredProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph,
Collection<? extends MavenProject> whiteList )
{
if ( projectDependencyGraph == null )
{
throw new IllegalArgumentException( "project dependency graph missing" );
}
this.projectDependencyGraph = projectDependencyGraph;
this.whiteList = new IdentityHashMap<MavenProject, Object>();
for ( MavenProject project : whiteList )
{
this.whiteList.put( project, null );
}
}
public List<MavenProject> getSortedProjects()
{
if ( sortedProjects == null )
{
sortedProjects = applyFilter( projectDependencyGraph.getSortedProjects() );
}
return new ArrayList<MavenProject>( sortedProjects );
}
public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
{
return applyFilter( projectDependencyGraph.getDownstreamProjects( project, transitive ) );
}
public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
{
return applyFilter( projectDependencyGraph.getUpstreamProjects( project, transitive ) );
}
private List<MavenProject> applyFilter( Collection<? extends MavenProject> projects )
{
List<MavenProject> filtered = new ArrayList<MavenProject>( projects.size() );
for ( MavenProject project : projects )
{
if ( whiteList.containsKey( project ) )
{
filtered.add( project );
}
}
return filtered;
}
@Override
public String toString()
{
return getSortedProjects().toString();
}
}

View File

@ -85,6 +85,12 @@ public class DefaultMavenExecutionRequest
private String reactorFailureBehavior = REACTOR_FAIL_FAST;
private List<String> selectedProjects;
private String resumeFrom;
private String makeBehavior;
private Properties properties;
private Date startTime;
@ -200,6 +206,26 @@ public String getReactorFailureBehavior()
return reactorFailureBehavior;
}
public List<String> getSelectedProjects()
{
if ( selectedProjects == null )
{
selectedProjects = new ArrayList<String>();
}
return selectedProjects;
}
public String getResumeFrom()
{
return resumeFrom;
}
public String getMakeBehavior()
{
return makeBehavior;
}
public Date getStartTime()
{
return startTime;
@ -414,6 +440,34 @@ public MavenExecutionRequest setReactorFailureBehavior( String failureBehavior )
return this;
}
public MavenExecutionRequest setSelectedProjects( List<String> selectedProjects )
{
if ( selectedProjects != null )
{
this.selectedProjects = new ArrayList<String>( selectedProjects );
}
else
{
this.selectedProjects = null;
}
return this;
}
public MavenExecutionRequest setResumeFrom( String project )
{
this.resumeFrom = project;
return this;
}
public MavenExecutionRequest setMakeBehavior( String makeBehavior )
{
this.makeBehavior = makeBehavior;
return this;
}
public MavenExecutionRequest addActiveProfile( String profile )
{
if ( !getActiveProfiles().contains( profile ) )

View File

@ -64,6 +64,16 @@ public interface MavenExecutionRequest
static final String REACTOR_FAIL_NEVER = "FAIL_NEVER";
// ----------------------------------------------------------------------
// Reactor Make Mode
// ----------------------------------------------------------------------
static final String REACTOR_MAKE_UPSTREAM = "make-upstream";
static final String REACTOR_MAKE_DOWNSTREAM = "make-downstream";
static final String REACTOR_MAKE_BOTH = "make-both";
// ----------------------------------------------------------------------
// Artifactr repository policies
// ----------------------------------------------------------------------
@ -97,6 +107,15 @@ public interface MavenExecutionRequest
MavenExecutionRequest setReactorFailureBehavior( String failureBehavior );
String getReactorFailureBehavior();
MavenExecutionRequest setSelectedProjects( List<String> projects );
List<String> getSelectedProjects();
MavenExecutionRequest setResumeFrom( String project );
String getResumeFrom();
MavenExecutionRequest setMakeBehavior( String makeBehavior );
String getMakeBehavior();
// Recursive (really to just process the top-level POM)
MavenExecutionRequest setRecursive( boolean recursive );
boolean isRecursive();

View File

@ -40,7 +40,7 @@ public interface ProjectDependencyGraph
List<MavenProject> getSortedProjects();
/**
* Gets the downstream projects of the specified projects. A downstream project is a project that directly or
* Gets the downstream projects of the specified project. 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}.
@ -50,4 +50,15 @@ public interface ProjectDependencyGraph
*/
List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive );
/**
* Gets the upstream projects of the specified project. An upstream project is a project that directly or indirectly
* is a prerequisite of the given project.
*
* @param project The project whose upstream projects should be retrieved, must not be {@code null}.
* @param transitive A flag whether to retrieve all direct and indirect upstream projects or just the immediate
* upstream projects.
* @return The upstream projects in the build order, never {@code null}.
*/
List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive );
}

View File

@ -193,6 +193,11 @@ public List<String> getDependents( String id )
return dag.getParentLabels( id );
}
public List<String> getDependencies( String id )
{
return dag.getChildLabels( id );
}
public static String getId( MavenProject project )
{
return ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );

View File

@ -84,6 +84,14 @@ public class CLIManager
public static final String FAIL_NEVER = "fn";
public static final String RESUME_FROM = "rf";
public static final String PROJECT_LIST = "pl";
public static final String ALSO_MAKE = "am";
public static final String ALSO_MAKE_DEPENDENTS = "amd";
public static final String LOG_FILE = "l";
private Options options;
@ -117,6 +125,10 @@ public CLIManager()
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 ) );
options.addOption( OptionBuilder.withLongOpt( "resume-from" ).hasArg().withDescription( "Resume reactor from specified project" ).create( RESUME_FROM ) );
options.addOption( OptionBuilder.withLongOpt( "projects" ).withDescription( "Build specified reactor projects instead of all projects" ).hasArg().create( PROJECT_LIST ) );
options.addOption( OptionBuilder.withLongOpt( "also-make" ).withDescription( "If project list is specified, also build projects required by the list" ).create( ALSO_MAKE ) );
options.addOption( OptionBuilder.withLongOpt( "also-make-dependents" ).withDescription( "If project list is specified, also build projects that depend on projects on the list" ).create( ALSO_MAKE_DEPENDENTS ) );
options.addOption( OptionBuilder.withLongOpt( "log-file" ).hasArg().withDescription( "Log file to where all build output will go." ).create( LOG_FILE ) );
options.addOption( OptionBuilder.withLongOpt( "show-version" ).withDescription( "Display version information WITHOUT stopping build" ).create( SHOW_VERSION ) );
@ -138,7 +150,7 @@ public CommandLine parse( String[] args )
private String[] cleanArgs( String[] args )
{
List cleaned = new ArrayList();
List<String> cleaned = new ArrayList<String>();
StringBuffer currentArg = null;
@ -226,7 +238,7 @@ private String[] cleanArgs( String[] args )
}
else
{
cleanArgs = (String[]) cleaned.toArray( new String[cleanedSz] );
cleanArgs = cleaned.toArray( new String[cleanedSz] );
}
return cleanArgs;

View File

@ -22,6 +22,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
@ -33,6 +34,7 @@
import org.apache.maven.embedder.MavenEmbedder;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequest;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineUtils;
public final class CLIRequestUtils
@ -267,7 +269,34 @@ else if ( quiet )
{
request.setPom( pom );
}
if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
{
request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
}
if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
{
String projectList = commandLine.getOptionValue( CLIManager.PROJECT_LIST );
String[] projects = StringUtils.split( projectList, "," );
request.setSelectedProjects( Arrays.asList( projects ) );
}
if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM );
}
else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE )
&& commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM );
}
else if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
&& commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH );
}
return request;
}