You are viewing a plain text version of this content. The canonical link for it is here.
Posted to m2-dev@maven.apache.org by jd...@apache.org on 2004/09/22 01:11:17 UTC
cvs commit: maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/session MavenSession.java
jdcasey 2004/09/21 16:11:16
Modified: maven-core/src/main/resources/META-INF/plexus components.xml
maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase
GoalResolutionPhase.java
maven-core/src/main/java/org/apache/maven/plugin
DefaultPluginManager.java PluginManager.java
maven-core/src/test/java/org/apache/maven/lifecycle
MavenLifecycleManagerTest.java
maven-core/src/main/java/org/apache/maven/lifecycle/session
MavenSession.java
Added: maven-core/src/test/java/org/apache/maven/lifecycle/goal/phase
GoalAssemblySubProcessTest.java
maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase
PluginResolutionPhase.java GoalMappingPhase.java
maven-core/src/main/java/org/apache/maven/util
AbstractGoalVisitor.java
GraphTraversalException.java GoalVisitor.java
GoalWalker.java
maven-core/src/site/apt goal-resolution.apt
Removed: maven-core/src/test/java/org/apache/maven/lifecycle/goal/phase
GoalResolutionPhaseTest.java
Log:
o Refactored the goal/plugin resolution part of the lifecycle.
Revision Changes Path
1.4 +11 -0 maven-components/maven-core/src/main/resources/META-INF/plexus/components.xml
Index: components.xml
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/main/resources/META-INF/plexus/components.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- components.xml 26 Aug 2004 04:39:51 -0000 1.3
+++ components.xml 21 Sep 2004 23:11:16 -0000 1.4
@@ -39,6 +39,8 @@
<implementation>org.apache.maven.lifecycle.goal.DefaultMavenGoalPhaseManager</implementation>
<configuration>
<lifecycle-phases>
+ <lifecycle-phase implementation="org.apache.maven.lifecycle.goal.phase.PluginResolutionPhase"/>
+ <lifecycle-phase implementation="org.apache.maven.lifecycle.goal.phase.GoalMappingPhase"/>
<lifecycle-phase implementation="org.apache.maven.lifecycle.goal.phase.GoalResolutionPhase"/>
<lifecycle-phase implementation="org.apache.maven.lifecycle.goal.phase.DependencyResolutionPhase"/>
<lifecycle-phase implementation="org.apache.maven.lifecycle.goal.phase.DependencyDownloadPhase"/>
@@ -64,6 +66,15 @@
</requirement>
<requirement>
<role>org.apache.maven.artifact.resolver.ArtifactResolver</role>
+ </requirement>
+ </requirements>
+ </component>
+ <component>
+ <role>org.apache.maven.util.GoalWalker</role>
+ <implementation>org.apache.maven.util.GoalWalker</implementation>
+ <requirements>
+ <requirement>
+ <role>org.apache.maven.plugin.PluginManager</role>
</requirement>
</requirements>
</component>
1.1 maven-components/maven-core/src/test/java/org/apache/maven/lifecycle/goal/phase/GoalAssemblySubProcessTest.java
Index: GoalAssemblySubProcessTest.java
===================================================================
/* Created on Jul 14, 2004 */
package org.apache.maven.lifecycle.goal.phase;
import org.apache.maven.MavenTestCase;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.model.Model;
import org.apache.maven.model.PostGoal;
import org.apache.maven.model.PreGoal;
import org.apache.maven.project.MavenProject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/** The point of this test class is to check out the functioning of the
* plugin resolution, goal mapping, and goal resolution phases. These are
* intertwined here to make testing easier, but should be separated into their
* own unit tests.
*
* @author jdcasey
*/
public class GoalAssemblySubProcessTest
extends MavenTestCase
{
/*
* <!-- Test main with preGoal and postGoal --> <mojo>
* <id>resolveTest:t1-preGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t1-main </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t1-postGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <!-- End of test -->
*/
public void testT1_ShouldFind_PreGoal_MainGoal_PostGoal() throws Exception
{
String mainGoal = "resolveTest:t1-main";
String preGoal = "resolveTest:t1-preGoal";
String postGoal = "resolveTest:t1-postGoal";
PreGoal pg = new PreGoal();
pg.setAttain( preGoal );
pg.setName( mainGoal );
List preGoals = new LinkedList();
preGoals.add( pg );
PostGoal pog = new PostGoal();
pog.setAttain( postGoal );
pog.setName( mainGoal );
List postGoals = new LinkedList();
postGoals.add( pog );
Map messages = new TreeMap();
messages.put( mainGoal, "Main goal is missing." );
messages.put( preGoal, "preGoal is missing" );
messages.put( postGoal, "postGoal is missing" );
List order = new ArrayList();
order.add( preGoal );
order.add( mainGoal );
order.add( postGoal );
runTest( mainGoal, preGoals, postGoals, order, messages );
}
/*
* <!-- Test main with prereq --> <mojo> <id>resolveTest:t2-prereq </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t2-main </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> <prereqs> <prereq>resolveTest:t2-prereq
* </prereq> </prereqs> </mojo> <!-- End of test -->
*/
public void testT2_ShouldFind_Prereq_MainGoal() throws Exception
{
String mainGoal = "resolveTest:t2-main";
String prereq = "resolveTest:t2-prereq";
Map messages = new TreeMap();
messages.put( mainGoal, "Main goal is missing." );
messages.put( prereq, "prereq is missing" );
List order = new ArrayList();
order.add( prereq );
order.add( mainGoal );
runTest( mainGoal, Collections.EMPTY_LIST, Collections.EMPTY_LIST, order, messages );
}
/*
* <!-- Test main with prereq, preGoal and postGoal --> <mojo>
* <id>resolveTest:t3-preGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t3-prereq </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t3-main </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> <prereqs> <prereq>resolveTest:t3-prereq
* </prereq> </prereqs> </mojo> <mojo> <id>resolveTest:t3-postGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <!-- End of test -->
*/
public void testT3_ShouldFind_PreGoal_Prereq_MainGoal_PostGoal() throws Exception
{
String mainGoal = "resolveTest:t3-main";
String prereq = "resolveTest:t3-prereq";
String preGoal = "resolveTest:t3-preGoal";
String postGoal = "resolveTest:t3-postGoal";
PreGoal pg = new PreGoal();
pg.setAttain( preGoal );
pg.setName( mainGoal );
List preGoals = new LinkedList();
preGoals.add( pg );
PostGoal pog = new PostGoal();
pog.setAttain( postGoal );
pog.setName( mainGoal );
List postGoals = new LinkedList();
postGoals.add( pog );
Map messages = new TreeMap();
messages.put( mainGoal, "Main goal is missing." );
messages.put( prereq, "prereq is missing" );
messages.put( preGoal, "preGoal is missing" );
messages.put( postGoal, "postGoal is missing" );
List order = new ArrayList();
order.add( preGoal );
order.add( prereq );
order.add( mainGoal );
order.add( postGoal );
runTest( mainGoal, preGoals, postGoals, order, messages );
}
/*
* <!-- Test main with prereq which has preGoal and postGoal --> <mojo>
* <id>resolveTest:t4-prereq-preGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t4-prereq </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t4-main </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> <prereqs> <prereq>resolveTest:t4-prereq
* </prereq> </prereqs> </mojo> <mojo> <id>resolveTest:t4-prereq-postGoal
* </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <!-- End of test -->
*/
public void testT4_ShouldFind_PreGoal_Prereq_PostGoal_MainGoal() throws Exception
{
String mainGoal = "resolveTest:t4-main";
String prereq = "resolveTest:t4-prereq";
String preGoal = "resolveTest:t4-prereq-preGoal";
String postGoal = "resolveTest:t4-prereq-postGoal";
PreGoal pg = new PreGoal();
pg.setAttain( preGoal );
pg.setName( prereq );
List preGoals = new LinkedList();
preGoals.add( pg );
PostGoal pog = new PostGoal();
pog.setAttain( postGoal );
pog.setName( prereq );
List postGoals = new LinkedList();
postGoals.add( pog );
Map messages = new TreeMap();
messages.put( mainGoal, "Main goal is missing." );
messages.put( prereq, "prereq is missing" );
messages.put( preGoal, "preGoal is missing" );
messages.put( postGoal, "postGoal is missing" );
List order = new ArrayList();
order.add( preGoal );
order.add( prereq );
order.add( postGoal );
order.add( mainGoal );
runTest( mainGoal, preGoals, postGoals, order, messages );
}
/*
* <!-- Test main with prereq and preGoal which has the same prereq -->
* <mojo> <id>resolveTest:t5-prereq </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> </mojo> <mojo> <id>resolveTest:t5-preGoal </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> <prereqs> <prereq>resolveTest:t5-prereq
* </prereq> </prereqs> </mojo> <mojo> <id>resolveTest:t5-main </id>
* <implementation>org.apache.maven.plugin.GoalDecorationAndResolutionTestPlugin
* </implementation> <instantiationStrategy>singleton
* </instantiationStrategy> <prereqs> <prereq>resolveTest:t5-prereq
* </prereq> </prereqs> </mojo> <!-- End of test -->
*/
public void testT5_ShouldFind_Prereq_PreGoal_MainGoal() throws Exception
{
String mainGoal = "resolveTest:t5-main";
String prereq = "resolveTest:t5-prereq";
String preGoal = "resolveTest:t5-preGoal";
PreGoal pg = new PreGoal();
pg.setAttain( preGoal );
pg.setName( mainGoal );
List preGoals = new LinkedList();
preGoals.add( pg );
Map messages = new TreeMap();
messages.put( mainGoal, "Main goal is missing." );
messages.put( prereq, "prereq is missing" );
messages.put( preGoal, "preGoal is missing" );
List order = new ArrayList();
order.add( prereq );
order.add( preGoal );
order.add( mainGoal );
runTest( mainGoal, preGoals, Collections.EMPTY_LIST, order, messages );
}
private void runTest( String mainGoal, List preGoals, List postGoals, List expectedOrder, Map messages )
throws Exception
{
ArtifactRepository localRepository = new ArtifactRepository( "local", getTestRepoURL() );
Model model = new Model();
model.setPreGoals( preGoals );
model.setPostGoals( postGoals );
MavenProject project = new MavenProject( model );
MavenGoalExecutionContext context = createGoalExecutionContext( project, localRepository, mainGoal );
context.setGoalName( mainGoal );
PluginResolutionPhase pluginPhase = new PluginResolutionPhase();
GoalMappingPhase mappingPhase = new GoalMappingPhase();
GoalResolutionPhase goalPhase = new GoalResolutionPhase();
pluginPhase.execute( context );
mappingPhase.execute( context );
goalPhase.execute( context );
List goals = context.getResolvedGoals();
//System.out.println("Expected chain: " + expectedOrder);
//System.out.println("Actual chain: " + goals);
assertNotNull( goals );
assertEquals( expectedOrder.size(), goals.size() );
int index = 0;
for ( Iterator it = expectedOrder.iterator(); it.hasNext(); )
{
String goal = (String) it.next();
String failureMessage = (String) messages.get( goal );
String resolvedGoal = (String) goals.get( index++ );
assertEquals( failureMessage, goal, resolvedGoal );
}
}
}
1.5 +55 -85 maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/GoalResolutionPhase.java
Index: GoalResolutionPhase.java
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/GoalResolutionPhase.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- GoalResolutionPhase.java 15 Sep 2004 12:34:16 -0000 1.4
+++ GoalResolutionPhase.java 21 Sep 2004 23:11:16 -0000 1.5
@@ -19,17 +19,25 @@
import org.apache.maven.lifecycle.goal.AbstractMavenGoalPhase;
import org.apache.maven.lifecycle.goal.GoalExecutionException;
import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
+import org.apache.maven.lifecycle.goal.phase.PluginResolutionPhase.PluginResolutionVisitor;
+import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.model.GoalDecorator;
import org.apache.maven.model.PreGoal;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.util.AbstractGoalVisitor;
+import org.apache.maven.util.GoalWalker;
+import org.apache.maven.util.GraphTraversalException;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
/**
* @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
@@ -38,114 +46,76 @@
public class GoalResolutionPhase
extends AbstractMavenGoalPhase
{
+
public void execute( MavenGoalExecutionContext context ) throws GoalExecutionException
{
- PluginManager pluginManager = context.getSession().getPluginManager();
+ GoalResolutionVisitor visitor = new GoalResolutionVisitor( context.getSession().getPluginManager() );
try
{
- // First, start by retrieving the currently-requested goal.
- String goal = context.getGoalName();
-
- List resolvedGoals = resolveTopLevel( goal, new HashSet(), new LinkedList(), context, pluginManager );
-
- context.setResolvedGoals( resolvedGoals );
-
- if ( goal.indexOf( ":" ) < 0 )
- {
- goal = context.getProject().getType() + ":" + goal;
- }
-
- MojoDescriptor md = pluginManager.getMojoDescriptor( goal );
-
- context.setMojoDescriptor( md );
- }
- catch ( Exception e )
- {
- throw new GoalExecutionException( "Error resolving goals: ", e );
+ GoalWalker.walk( context.getGoalName(), context.getSession(), visitor );
}
- finally
+ catch ( GraphTraversalException e )
{
- context.release( pluginManager );
+ throw new GoalExecutionException("Cannot calculate goal execution chain", e);
}
+
+ context.setResolvedGoals(visitor.getExecutionChain());
}
- private List resolveTopLevel( String goal, Set includedGoals, List results, MavenGoalExecutionContext context,
- PluginManager pluginManager ) throws Exception
+ public static final class GoalResolutionVisitor
+ extends AbstractGoalVisitor
{
+ private PluginManager pluginManager;
- // Ensure that the plugin for this goal is installed.
- pluginManager.verifyPluginForGoal( goal );
-
- // Retrieve the prereqs-driven execution path for this goal, using the
- // DAG.
- List work = pluginManager.getGoals( goal );
-
- // Reverse the original goals list to preserve encapsulation while
- // decorating.
- Collections.reverse( work );
+ private List executionChain = new LinkedList();
+
+ private Map prereqChains = new TreeMap();
- return resolveWithPrereqs( work, includedGoals, results, context, pluginManager );
- }
-
- private List resolveWithPrereqs( List work, Set includedGoals, List results, MavenGoalExecutionContext context,
- PluginManager pluginManager ) throws Exception
- {
- if ( !work.isEmpty() )
+ GoalResolutionVisitor( PluginManager pluginManager )
{
- String goal = (String) work.remove( 0 );
-
- MojoDescriptor descriptor = context.getMojoDescriptor( goal );
-
- if ( descriptor.alwaysExecute() || !includedGoals.contains( goal ) )
- {
- List preGoals = new LinkedList();
- List allPreGoals = context.getProject().getModel().getPreGoals();
- for ( Iterator it = allPreGoals.iterator(); it.hasNext(); )
- {
- PreGoal preGoal = (PreGoal) it.next();
- if ( goal.equals( preGoal.getName() ) )
- {
- preGoals.add( preGoal.getAttain() );
- }
- }
-
- results = resolveGoalDecorators( goal, true, includedGoals, results, context, pluginManager );
-
- results = resolveWithPrereqs( work, includedGoals, results, context, pluginManager );
- includedGoals.add( goal );
- results.add( goal );
+ this.pluginManager = pluginManager;
+ }
- results = resolveGoalDecorators( goal, false, includedGoals, results, context, pluginManager );
- }
+ public boolean shouldVisit( String goal, MavenSession session )
+ {
+ boolean result = !executionChain.contains( goal );
+
+ return result;
}
- return results;
- }
- private List resolveGoalDecorators( String baseGoal, boolean usePreGoals, Set includedGoals, List results,
- MavenGoalExecutionContext context, PluginManager pluginManager ) throws Exception
- {
- List decorators = null;
- if ( usePreGoals )
+ public void visitGoal( String goal, MavenSession session )
{
- decorators = context.getProject().getModel().getPreGoals();
+ executionChain.add( goal );
}
- else
+
+ public void visitPostGoal( String goal, String postGoal, MavenSession session )
+ throws GraphTraversalException
{
- decorators = context.getProject().getModel().getPostGoals();
+ List chain = session.getExecutionChain( postGoal );
+
+ executionChain.addAll( chain );
}
-
- for ( Iterator it = decorators.iterator(); it.hasNext(); )
+
+ public void visitPreGoal( String goal, String preGoal, MavenSession session )
+ throws GraphTraversalException
+ {
+ List chain = session.getExecutionChain( preGoal );
+
+ executionChain.addAll( chain );
+ }
+
+ public void visitPrereq( String goal, String prereq, MavenSession session)
+ throws GraphTraversalException
+ {
+ GoalWalker.walk( prereq, session, this );
+ }
+
+ public List getExecutionChain()
{
- GoalDecorator decorator = (GoalDecorator) it.next();
- if ( baseGoal.equals( decorator.getName() ) )
- {
- String goal = decorator.getAttain();
- resolveTopLevel( goal, includedGoals, results, context, pluginManager );
- }
+ return executionChain;
}
- return results;
}
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/PluginResolutionPhase.java
Index: PluginResolutionPhase.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.lifecycle.goal.phase;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.maven.lifecycle.goal.AbstractMavenGoalPhase;
import org.apache.maven.lifecycle.goal.GoalExecutionException;
import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.util.AbstractGoalVisitor;
import org.apache.maven.util.GoalWalker;
import org.apache.maven.util.GraphTraversalException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.dag.CycleDetectedException;
/**
* @author jdcasey
*/
public class PluginResolutionPhase
extends AbstractMavenGoalPhase
{
public void execute( MavenGoalExecutionContext context ) throws GoalExecutionException
{
PluginResolutionVisitor visitor = new PluginResolutionVisitor( context.getSession().getPluginManager() );
try
{
GoalWalker.walk( context.getGoalName(), context.getSession(), visitor );
}
catch ( GraphTraversalException e )
{
throw new GoalExecutionException( "Cannot resolve plugins required for goal execution chain", e );
}
}
public static final class PluginResolutionVisitor
extends AbstractGoalVisitor
{
private PluginManager pluginManager;
private Set resolved = new HashSet();
PluginResolutionVisitor( PluginManager pluginManager )
{
this.pluginManager = pluginManager;
}
public void preVisit( String goal, MavenSession session ) throws GraphTraversalException
{
try
{
pluginManager.verifyPluginForGoal( goal );
}
catch ( Exception e )
{
throw new GraphTraversalException( "Cannot resolve plugin for goal", e );
}
finally
{
resolved.add( goal );
}
}
public boolean shouldVisit( String goal, MavenSession session ) throws GraphTraversalException
{
boolean result = !resolved.contains( goal );
return result;
}
public void visitPostGoal( String goal, String postGoal, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( postGoal, session, this );
}
public void visitPreGoal( String goal, String preGoal, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( preGoal, session, this );
}
public void visitPrereq( String goal, String prereq, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( prereq, session, this );
}
}
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/goal/phase/GoalMappingPhase.java
Index: GoalMappingPhase.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.lifecycle.goal.phase;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.maven.lifecycle.goal.AbstractMavenGoalPhase;
import org.apache.maven.lifecycle.goal.GoalExecutionException;
import org.apache.maven.lifecycle.goal.MavenGoalExecutionContext;
import org.apache.maven.lifecycle.goal.phase.PluginResolutionPhase.PluginResolutionVisitor;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.util.AbstractGoalVisitor;
import org.apache.maven.util.GoalWalker;
import org.apache.maven.util.GraphTraversalException;
import org.codehaus.plexus.util.dag.CycleDetectedException;
/**
* @author jdcasey
*/
public class GoalMappingPhase
extends AbstractMavenGoalPhase
{
public void execute( MavenGoalExecutionContext context ) throws GoalExecutionException
{
GoalMappingVisitor visitor = new GoalMappingVisitor( context.getSession().getPluginManager() );
try
{
GoalWalker.walk( context.getGoalName(), context.getSession(), visitor );
}
catch ( GraphTraversalException e )
{
throw new GoalExecutionException( "Cannot resolve plugins required for goal execution chain", e );
}
}
public static final class GoalMappingVisitor
extends AbstractGoalVisitor
{
private PluginManager pluginManager;
private Set visited = new HashSet();
GoalMappingVisitor( PluginManager pluginManager )
{
this.pluginManager = pluginManager;
}
public void visitPrereq( String goal, String prereq, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( prereq, session, this );
try
{
session.addImpliedExecution( goal, prereq );
}
catch ( CycleDetectedException e )
{
throw new GraphTraversalException( "Goal prereq causes goal-graph cycle", e );
}
}
public void visitPostGoal( String goal, String postGoal, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( postGoal, session, this );
}
public void visitPreGoal( String goal, String preGoal, MavenSession session ) throws GraphTraversalException
{
GoalWalker.walk( preGoal, session, this );
}
public void visitGoal( String goal, MavenSession session ) throws GraphTraversalException
{
session.addSingleExecution( goal );
}
public boolean shouldVisit( String goal, MavenSession session ) throws GraphTraversalException
{
boolean result = !visited.contains( goal );
return result;
}
}
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/util/AbstractGoalVisitor.java
Index: AbstractGoalVisitor.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.util;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
/**
* @author jdcasey
*/
public abstract class AbstractGoalVisitor
implements GoalVisitor
{
protected AbstractGoalVisitor()
{
}
public boolean shouldVisit( String goal, MavenSession session )
throws GraphTraversalException
{
// visit all by default
return true;
}
public void visitGoal( String goal, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
public void visitPostGoal( String goal, String postGoal, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
public void visitPreGoal( String goal, String preGoal, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
public void visitPrereq( String goal, String prereq, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
public void preVisit( String goal, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
public void postVisit( String goal, MavenSession session )
throws GraphTraversalException
{
// do nothing by default
}
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/util/GraphTraversalException.java
Index: GraphTraversalException.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.util;
/**
* @author jdcasey
*/
public class GraphTraversalException
extends Exception
{
public GraphTraversalException( Throwable cause )
{
super( cause );
}
public GraphTraversalException( String message, Throwable cause )
{
super( message, cause );
}
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/util/GoalVisitor.java
Index: GoalVisitor.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.util;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
/**
* @author jdcasey
*/
public interface GoalVisitor
{
boolean shouldVisit( String goal, MavenSession session ) throws GraphTraversalException;
void preVisit( String goal, MavenSession session ) throws GraphTraversalException;
void visitGoal( String goal, MavenSession session ) throws GraphTraversalException;
void visitPreGoal( String goal, String preGoal, MavenSession session ) throws GraphTraversalException;
void visitPrereq( String goal, String prereq, MavenSession session ) throws GraphTraversalException;
void visitPostGoal( String goal, String postGoal, MavenSession session ) throws GraphTraversalException;
void postVisit( String goal, MavenSession session ) throws GraphTraversalException;
}
1.1 maven-components/maven-core/src/main/java/org/apache/maven/util/GoalWalker.java
Index: GoalWalker.java
===================================================================
/* Created on Sep 21, 2004 */
package org.apache.maven.util;
import java.util.Iterator;
import java.util.List;
import org.apache.maven.lifecycle.session.MavenSession;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
/**
* @author jdcasey
*/
public final class GoalWalker
{
public static void walk( String goal, MavenSession session, GoalVisitor visitor ) throws GraphTraversalException
{
if ( visitor.shouldVisit( goal, session ) )
{
visitor.preVisit( goal, session );
List preGoals = session.getPreGoals( goal );
if ( preGoals != null )
{
for ( Iterator it = preGoals.iterator(); it.hasNext(); )
{
String preGoal = (String) it.next();
visitor.visitPreGoal( goal, preGoal, session );
}
}
PluginManager pluginManager = session.getPluginManager();
MojoDescriptor mojoDescriptor = pluginManager.getMojoDescriptor( goal );
if ( mojoDescriptor != null )
{
List prereqs = mojoDescriptor.getPrereqs();
if ( prereqs != null )
{
for ( Iterator it = prereqs.iterator(); it.hasNext(); )
{
String prereq = (String) it.next();
visitor.visitPrereq( goal, prereq, session );
}
}
}
visitor.visitGoal( goal, session );
List postGoals = session.getPostGoals( goal );
if ( postGoals != null )
{
for ( Iterator it = postGoals.iterator(); it.hasNext(); )
{
String postGoal = (String) it.next();
visitor.visitPostGoal( goal, postGoal, session );
}
}
visitor.postVisit( goal, session );
}
}
}
1.1 maven-components/maven-core/src/site/apt/goal-resolution.apt
Index: goal-resolution.apt
===================================================================
---
Goal Resolution Discussion
---
The Maven Team
---
21-Sept-2004
---
This document is intended to be a working memory of sorts for the goal
resolution algorithm used in Maven-2. It is not intended to supplant the
living bible of Maven, the lifecycle.apt document. Instead it is meant to
add depth to the goal resolution step of the lifecycle and provide a place
for discussing the dirty details of its implementation.
*Conceptual Resolution
Conceptually, goal resolution must take place in a particular order in order
to preserve the encapsulation of the goal and it's implied requirements as a
single operation. Obviously, since implied requirements are themselves goals,
this is a recursive definition. This model is further complicated by the fact
that such implied requirements can be derived from two sources: a mojo's
declared pre-requisites (non-optional, these are required for correct
operation of the mojo itself), and any goal decorations which may have been
declared in a project-specific manner via the project POM.
In general, the following should be the combined outcome of all implied
requirements.
+-----+
[ main-preGoal* ] [ prereq ]* main-goal [ main-postGoal* ]
+-----+
Note that each of the elements in this formula is a goal in its own right,
and will therefore be subject to resolution (taking the place of <<<main-goal>>>
above) and substitution into the parent (replace <<<main-preGoal>>> with the
list of goals implied by <<<main-preGoal>>> <in correct order>).
*Functional Resolution
The fact we must merge two sources of implied-goal information in order to
construct a complete execution chain complicates goal resolution beyond simple
use of a directed acyclical graph (DAG). This is especially true because of the
differing lifecycle and scope of the two sources. One is the plugin
descriptor, which has a lifecycle arguably longer than the JVM lifecycle
itself, and system-wide scope (provided plugin versioning is tracked). The
other is the project's POM, which has an extremely short lifecycle (probably
roughly equivalent to the maven-session lifecycle, which is <not> the same as
the JVM lifecycle in some embedded use cases), and only project scope (don't
want one POM's decorations polluting the builds of other POMs). While the
plugin descriptor information may be cached - even to disk - the POM goal
information must be rebuilt for each maven-session.
On the other hand, one very important distinction between information derived
from plugin descriptors and information from POMs is that POMs lack the
ability to declare new goals. This means that in theory we should be able to
clone a DAG that describes all of the conventional requirements for all of the
plugins referenced, and simply add inter-goal relationships to account for any
extra decoration from the POM. When the session is over, we can then discard
the modified DAG, retaining the plugin-derived DAG for future use in memory or
on disk.
<NOTE:> There are other reasons to be very careful when caching the DAG to
disk, notably the handling and updating of -SNAPSHOT plugins.
*Algorithm
Here is the current algorithm implemented by the GoalResolutionPhase:
<NOTE:> The separation of the plugin resolution step from the process of
actually building the execution chain is new, and has not yet been implemented.
However, this appears to be a required separation since the DAG cannot
function properly until all plugins - and consequently the prereqs implied by
them - are resolved. So, we'll take a second pass later to actually build the
execution list; for now, we'll just resolve plugins.
<<Resolve Plugins:>>
<NOTE:> Can we re-separate this as a plugin-resolution phase, and provide
some sort of reusable tree-visit logic (akin to the topo sorter) where we
could pass in some sort of visitation command to execute per visited goal?
[[1]] Initialize recursion
[[a]] Instantiate Set for caching resolved goals. <resolved>
[[b]] Set current goal to be resolved. <goal>
[]
[[2]] If <goal> is contained in <resolved>, Return.
[[3]] Verify plugin for <goal>.
[[4]] Add <goal> to resolved.
[[5]] Foreach <preGoal> of <goal>,
[[a]] Set <goal> = <preGoal>
[[b]] Call [2]
[]
[[6]] Foreach <prereq> of <goal>,
[[a]] Set <goal> = <prereq>
[[b]] Call [2]
[]
[[7]] Foreach <postGoal> of <goal>,
[[a]] Set <goal> = <postGoal>
[[b]] Call [2]
[]
[[8]] Return.
[]
<<Build Execution Chain:>>
<NOTE:> Visitation logic is eerily similar to the above recursive process.
Can we create a graph visitation utility and pass in some sort of command
to be executed per visited node?
[[1]] Initialize recursion
[[a]] Instantiate LinkedList to hold execution chain. <chain>
[[b]] Instantiate Set for caching visited goals. <visited>
[[c]] Set current goal to be executed. <goal>
[]
[[2]] If <visited> contains <goal>, Return.
[[3]] Process preGoals of <goal>
[[a]] Retrieve List of preGoals bound to <goal>
[[b]] Foreach <preGoal> in <preGoals>
[[i]] Set <goal> = <preGoal>
[[ii]] Call [1]
[]
[]
[[4]] Process prereqs of <goal>
[[a]] Retrieve List of prereqs bound to <goal>
[[b]] Foreach <prereq> in <prereqs>
[[i]] Set <goal> = <prereq>
[[ii]] Call [1]
[]
[]
[[5]] Add <goal> to <chain>
[[6]] Add <goal> to <visited>
[[7]] Process postGoals of <goal>
[[a]] Retrieve List of postGoals bound to <goal>
[[b]] Foreach <postGoal> in <postGoals>
[[i]] Set <goal> = <postGoal>
[[ii]] Call [1]
[]
[]
[[8]] Return.
[]
<NOTE:> Since the user's intent most likely aligned with separate, serial
execution of all goals listed on the command line <in order>, the above
algorithm must be repeated for each <goal> in <user-goals>, with the execution
chains of each being appended to a single list in order to resolve a complete,
end-to-end picture of the current build session.
1.10 +1 -61 maven-components/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java
Index: DefaultPluginManager.java
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- DefaultPluginManager.java 18 Sep 2004 01:52:38 -0000 1.9
+++ DefaultPluginManager.java 21 Sep 2004 23:11:16 -0000 1.10
@@ -47,8 +47,6 @@
{
static String MAVEN_PLUGIN = "maven-plugin";
- protected DAG dag;
-
protected Map mojoDescriptors;
protected Map pluginDescriptors;
@@ -67,8 +65,6 @@
public DefaultPluginManager()
{
- dag = new DAG();
-
mojoDescriptors = new HashMap();
pluginDescriptors = new HashMap();
@@ -77,15 +73,6 @@
}
// ----------------------------------------------------------------------
- //
- // ----------------------------------------------------------------------
-
- public List getGoals( String goal )
- {
- return TopologicalSorter.sort( dag.getVertex( goal ) );
- }
-
- // ----------------------------------------------------------------------
// Goal descriptors
// ----------------------------------------------------------------------
@@ -121,58 +108,11 @@
MavenMojoDescriptor mavenMojoDescriptor = (MavenMojoDescriptor) it.next();
MojoDescriptor mojoDescriptor = mavenMojoDescriptor.getMojoDescriptor();
-
- if ( mojoDescriptor.getPrereqs() != null )
- {
- for ( Iterator k = mojoDescriptor.getPrereqs().iterator(); k.hasNext(); )
- {
- String prereq = (String) k.next();
-
- if ( !processEdge( mojoDescriptor.getId(), prereq ) )
- {
- continue;
- }
- }
- }
- else
- {
- dag.addVertex( mojoDescriptor.getId() );
- }
-
+
mojoDescriptors.put( mojoDescriptor.getId(), mojoDescriptor );
pluginDescriptors.put( pluginDescriptor.getId(), pluginDescriptor );
}
- }
-
- private boolean processEdge( String mojoId, String prereq ) throws CycleDetectedException
- {
- dag.addEdge( mojoId, prereq );
-
- // We don't want to verify a plugin that we are already in the process
- // of verifying.
- String prereqPlugin = getPluginId( prereq );
-
- String goalPlugin = getPluginId( mojoId );
-
- if ( isPluginInstalled( prereqPlugin ) )
- {
- return false;
- }
-
- if ( !goalPlugin.equals( prereqPlugin ) )
- {
- try
- {
- verifyPluginForGoal( prereq );
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- }
- }
-
- return true;
}
// ----------------------------------------------------------------------
1.3 +1 -3 maven-components/maven-core/src/main/java/org/apache/maven/plugin/PluginManager.java
Index: PluginManager.java
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/plugin/PluginManager.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- PluginManager.java 15 Sep 2004 12:30:04 -0000 1.2
+++ PluginManager.java 21 Sep 2004 23:11:16 -0000 1.3
@@ -49,8 +49,6 @@
//
// ----------------------------------------------------------------------
- List getGoals( String goal );
-
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
1.4 +1 -1 maven-components/maven-core/src/test/java/org/apache/maven/lifecycle/MavenLifecycleManagerTest.java
Index: MavenLifecycleManagerTest.java
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/test/java/org/apache/maven/lifecycle/MavenLifecycleManagerTest.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MavenLifecycleManagerTest.java 26 Aug 2004 04:39:54 -0000 1.3
+++ MavenLifecycleManagerTest.java 21 Sep 2004 23:11:16 -0000 1.4
@@ -19,6 +19,6 @@
List lifecyclePhases = mlm.getLifecyclePhases();
- assertEquals( 4, lifecyclePhases.size() );
+ assertEquals( 6, lifecyclePhases.size() );
}
}
1.4 +100 -12 maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/session/MavenSession.java
Index: MavenSession.java
===================================================================
RCS file: /home/cvs/maven-components/maven-core/src/main/java/org/apache/maven/lifecycle/session/MavenSession.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MavenSession.java 15 Sep 2004 12:30:04 -0000 1.3
+++ MavenSession.java 21 Sep 2004 23:11:16 -0000 1.4
@@ -1,14 +1,24 @@
package org.apache.maven.lifecycle.session;
import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.PostGoal;
+import org.apache.maven.model.PreGoal;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositoryUtils;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.codehaus.plexus.util.dag.DAG;
+import org.codehaus.plexus.util.dag.TopologicalSorter;
+import org.codehaus.plexus.util.dag.Vertex;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
/*
* Copyright 2001-2004 The Apache Software Foundation.
@@ -27,7 +37,7 @@
*/
/**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
* @version $Id$
*/
public class MavenSession
@@ -42,13 +52,16 @@
private Set remoteRepositories;
+ private DAG dag;
+
private List goals;
- public MavenSession( PlexusContainer container,
- PluginManager pluginManager,
- MavenProject project,
- ArtifactRepository localRepository,
- List goals )
+ private Map preGoalMappings;
+
+ private Map postGoalMappings;
+
+ public MavenSession( PlexusContainer container, PluginManager pluginManager, MavenProject project,
+ ArtifactRepository localRepository, List goals )
{
this.container = container;
@@ -58,7 +71,15 @@
this.localRepository = localRepository;
+ this.dag = new DAG();
+
this.goals = goals;
+
+ this.preGoalMappings = new TreeMap();
+
+ this.postGoalMappings = new TreeMap();
+
+ initGoalDecoratorMappings();
}
public PlexusContainer getContainer()
@@ -100,14 +121,12 @@
//
// ----------------------------------------------------------------------
- public Object lookup( String role )
- throws ComponentLookupException
+ public Object lookup( String role ) throws ComponentLookupException
{
return container.lookup( role );
}
- public Object lookup( String role, String roleHint )
- throws ComponentLookupException
+ public Object lookup( String role, String roleHint ) throws ComponentLookupException
{
return container.lookup( role, roleHint );
}
@@ -126,4 +145,73 @@
}
}
}
-}
+
+ public List getPreGoals( String goal )
+ {
+ List result = (List) preGoalMappings.get( goal );
+ return result;
+ }
+
+ public List getPostGoals( String goal )
+ {
+ List result = (List) postGoalMappings.get( goal );
+ return result;
+ }
+
+ private void initGoalDecoratorMappings()
+ {
+ List allPreGoals = project.getModel().getPreGoals();
+ for ( Iterator it = allPreGoals.iterator(); it.hasNext(); )
+ {
+ PreGoal preGoal = (PreGoal) it.next();
+
+ List preGoalList = (List) preGoalMappings.get( preGoal.getName() );
+ if ( preGoalList == null )
+ {
+ preGoalList = new LinkedList();
+ preGoalMappings.put( preGoal.getName(), preGoalList );
+ }
+
+ preGoalList.add( preGoal.getAttain() );
+ }
+
+ List allPostGoals = project.getModel().getPostGoals();
+ for ( Iterator it = allPostGoals.iterator(); it.hasNext(); )
+ {
+ PostGoal postGoal = (PostGoal) it.next();
+
+ List postGoalList = (List) postGoalMappings.get( postGoal.getName() );
+ if ( postGoalList == null )
+ {
+ postGoalList = new LinkedList();
+ postGoalMappings.put( postGoal.getName(), postGoalList );
+ }
+
+ postGoalList.add( postGoal.getAttain() );
+ }
+ }
+
+ public void addImpliedExecution( String goal, String implied ) throws CycleDetectedException
+ {
+ dag.addEdge( goal, implied );
+ }
+
+ public void addSingleExecution( String goal )
+ {
+ dag.addVertex( goal );
+ }
+
+ public List getExecutionChain( String goal )
+ {
+ Vertex vertex = dag.getVertex( goal );
+
+ List sorted = TopologicalSorter.sort( vertex );
+
+ int goalIndex = sorted.indexOf( goal );
+
+ List chainToHere = sorted.subList( 0, goalIndex + 1 );
+
+ return chainToHere;
+ }
+
+}
\ No newline at end of file