MNG-4634 Allow custom lifecycles

Build extensions plugins can now define new lifecycles. Implementation guarantees 
that standard lifecycles, i.e. default, clean and site, are considered before custom
lifecycles. It assumes that phase names are globally unique and ignores any
duplicate phase names (with a warning).

git-svn-id: https://svn.apache.org/repos/asf/maven/maven-3/trunk@933848 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Igor Fedorenko 2010-04-14 03:09:21 +00:00
parent 87ff4bf414
commit 2115920094
3 changed files with 167 additions and 123 deletions

View File

@ -14,82 +14,65 @@
*/ */
package org.apache.maven.lifecycle; package org.apache.maven.lifecycle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.lifecycle.internal.BuilderCommon; import org.apache.maven.lifecycle.internal.BuilderCommon;
import org.apache.maven.lifecycle.internal.ExecutionPlanItem; import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
import org.apache.maven.plugin.*; import org.apache.maven.plugin.InvalidPluginDescriptorException;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoNotFoundException;
import org.apache.maven.plugin.PluginDescriptorParsingException;
import org.apache.maven.plugin.PluginNotFoundException;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException; import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable; import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.StringUtils;
import java.util.*;
/** /**
* @author Jason van Zyl * @author Jason van Zyl
* @author Kristian Rosenvold * @author Kristian Rosenvold
*/ */
//TODO: The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the wiring and reference and external source for the lifecycle configuration. // TODO: The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the
// wiring and reference and external source for the lifecycle configuration.
public class DefaultLifecycles public class DefaultLifecycles
implements Initializable
{ {
public static final String[] STANDARD_LIFECYCLES = { "default", "clean", "site" };
// @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml") // @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml")
private List<Lifecycle> lifecycles; // @Requirement(role=Lifecycle.class)
private Map<String, Lifecycle> lifecycles;
// @Requirement
private Logger logger;
private List<Scheduling> schedules; private List<Scheduling> schedules;
/** @SuppressWarnings( { "UnusedDeclaration" } )
* We use this to display all the lifecycles available and their phases to users. Currently this is primarily
* used in the IDE integrations where a UI is presented to the user and they can select the lifecycle phase
* they would like to execute.
*/
private Map<String, Lifecycle> lifecycleMap;
/**
* We use this to map all phases to the lifecycle that contains it. This is used so that a user can specify the
* phase they want to execute and we can easily determine what lifecycle we need to run.
*/
private Map<String, Lifecycle> phaseToLifecycleMap;
@SuppressWarnings({"UnusedDeclaration"})
public DefaultLifecycles() public DefaultLifecycles()
{ {
} }
public DefaultLifecycles( List<Lifecycle> lifecycles, List<Scheduling> schedules ) public DefaultLifecycles( List<Lifecycle> lifecycles, List<Scheduling> schedules )
{ {
this.lifecycles = lifecycles; this.lifecycles = new LinkedHashMap<String, Lifecycle>();
this.schedules = schedules; this.schedules = schedules;
}
public void initialize()
throws InitializationException
{
lifecycleMap = new HashMap<String, Lifecycle>();
// If people are going to make their own lifecycles then we need to tell people how to namespace them correctly so
// that they don't interfere with internally defined lifecycles.
phaseToLifecycleMap = new HashMap<String, Lifecycle>();
for ( Lifecycle lifecycle : lifecycles ) for ( Lifecycle lifecycle : lifecycles )
{ {
for ( String phase : lifecycle.getPhases() ) this.lifecycles.put( lifecycle.getId(), lifecycle );
{
// The first definition wins.
if ( !phaseToLifecycleMap.containsKey( phase ) )
{
phaseToLifecycleMap.put( phase, lifecycle );
} }
} }
lifecycleMap.put( lifecycle.getId(), lifecycle );
}
}
public List<ExecutionPlanItem> createExecutionPlanItem( MavenProject mavenProject, List<MojoExecution> executions ) public List<ExecutionPlanItem> createExecutionPlanItem( MavenProject mavenProject, List<MojoExecution> executions )
throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
@ -140,17 +123,62 @@ public class DefaultLifecycles
public Lifecycle get( String key ) public Lifecycle get( String key )
{ {
return phaseToLifecycleMap.get( key ); return getPhaseToLifecycleMap().get( key );
} }
/**
* We use this to map all phases to the lifecycle that contains it. This is used so that a user can specify the
* phase they want to execute and we can easily determine what lifecycle we need to run.
*/
public Map<String, Lifecycle> getPhaseToLifecycleMap() public Map<String, Lifecycle> getPhaseToLifecycleMap()
{ {
// If people are going to make their own lifecycles then we need to tell people how to namespace them correctly
// so
// that they don't interfere with internally defined lifecycles.
HashMap<String, Lifecycle> phaseToLifecycleMap = new HashMap<String, Lifecycle>();
for ( Lifecycle lifecycle : getLifeCycles() )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Custom lifecycle " + lifecycle.toString() );
}
for ( String phase : lifecycle.getPhases() )
{
// The first definition wins.
if ( !phaseToLifecycleMap.containsKey( phase ) )
{
phaseToLifecycleMap.put( phase, lifecycle );
}
else
{
Lifecycle original = phaseToLifecycleMap.get( phase );
logger.warn( "Duplicated lifecycle phase " + phase + ". Defined in " + original.getId()
+ " but also in " + lifecycle.getId() );
}
}
}
return phaseToLifecycleMap; return phaseToLifecycleMap;
} }
public List<Lifecycle> getLifeCycles() public List<Lifecycle> getLifeCycles()
{ {
return lifecycles; // ensure canonical order of standard lifecycles
Map<String, Lifecycle> lifecycles = new LinkedHashMap<String, Lifecycle>( this.lifecycles );
LinkedHashSet<String> lifecycleNames = new LinkedHashSet<String>( Arrays.asList( STANDARD_LIFECYCLES ) );
lifecycleNames.addAll( lifecycles.keySet() );
ArrayList<Lifecycle> result = new ArrayList<Lifecycle>();
for ( String name : lifecycleNames )
{
result.add( lifecycles.get( name ) );
}
return result;
} }
public List<Scheduling> getSchedules() public List<Scheduling> getSchedules()
@ -162,7 +190,7 @@ public class DefaultLifecycles
{ {
Set<String> phases = new LinkedHashSet<String>(); Set<String> phases = new LinkedHashSet<String>();
for ( Lifecycle lifecycle : lifecycles ) for ( Lifecycle lifecycle : lifecycles.values() )
{ {
phases.addAll( lifecycle.getPhases() ); phases.addAll( lifecycle.getPhases() );
} }

View File

@ -57,9 +57,46 @@
<role>org.apache.maven.lifecycle.DefaultLifecycles</role> <role>org.apache.maven.lifecycle.DefaultLifecycles</role>
<implementation>org.apache.maven.lifecycle.DefaultLifecycles</implementation> <implementation>org.apache.maven.lifecycle.DefaultLifecycles</implementation>
<requirements>
<requirement>
<role>org.codehaus.plexus.logging.Logger</role>
<field-name>logger</field-name>
</requirement>
<requirement>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<field-name>lifecycles</field-name>
</requirement>
</requirements>
<configuration>
<schedules>
<scheduling>
<lifecycle>default</lifecycle>
<schedules>
<schedule>
<phase>test</phase>
<mojoSynchronized>false</mojoSynchronized>
<parallel>true</parallel>
</schedule>
<schedule>
<mojoClass>org.apache.maven.plugins:maven-assembly-plugin</mojoClass>
<mojoSynchronized>true</mojoSynchronized>
</schedule>
<!--schedule>
<mojoClass>org.codehaus.modello:modello-maven-plugin</mojoClass>
<mojoSynchronized>true</mojoSynchronized>
</schedule -->
</schedules>
</scheduling>
</schedules>
</configuration>
</component>
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>default</role-hint>
<configuration> <configuration>
<lifecycles>
<lifecycle>
<id>default</id> <id>default</id>
<!-- START SNIPPET: lifecycle --> <!-- START SNIPPET: lifecycle -->
<phases> <phases>
@ -88,8 +125,13 @@
<phase>deploy</phase> <phase>deploy</phase>
</phases> </phases>
<!-- END SNIPPET: lifecycle --> <!-- END SNIPPET: lifecycle -->
</lifecycle> </configuration>
<lifecycle> </component>
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>clean</role-hint>
<configuration>
<id>clean</id> <id>clean</id>
<phases> <phases>
<phase>pre-clean</phase> <phase>pre-clean</phase>
@ -101,8 +143,13 @@
org.apache.maven.plugins:maven-clean-plugin:2.4:clean org.apache.maven.plugins:maven-clean-plugin:2.4:clean
</clean> </clean>
</default-phases> </default-phases>
</lifecycle> </configuration>
<lifecycle> </component>
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>site</role-hint>
<configuration>
<id>site</id> <id>site</id>
<phases> <phases>
<phase>pre-site</phase> <phase>pre-site</phase>
@ -118,28 +165,6 @@
org.apache.maven.plugins:maven-site-plugin:2.0.1:deploy org.apache.maven.plugins:maven-site-plugin:2.0.1:deploy
</site-deploy> </site-deploy>
</default-phases> </default-phases>
</lifecycle>
</lifecycles>
<schedules>
<scheduling>
<lifecycle>default</lifecycle>
<schedules>
<schedule>
<phase>test</phase>
<mojoSynchronized>false</mojoSynchronized>
<parallel>true</parallel>
</schedule>
<schedule>
<mojoClass>org.apache.maven.plugins:maven-assembly-plugin</mojoClass>
<mojoSynchronized>true</mojoSynchronized>
</schedule>
<!--schedule>
<mojoClass>org.codehaus.modello:modello-maven-plugin</mojoClass>
<mojoSynchronized>true</mojoSynchronized>
</schedule -->
</schedules>
</scheduling>
</schedules>
</configuration> </configuration>
</component> </component>
<component> <component>

View File

@ -15,14 +15,13 @@
package org.apache.maven.lifecycle.internal.stub; package org.apache.maven.lifecycle.internal.stub;
import java.util.Arrays;
import java.util.List;
import org.apache.maven.lifecycle.DefaultLifecycles; import org.apache.maven.lifecycle.DefaultLifecycles;
import org.apache.maven.lifecycle.Lifecycle; import org.apache.maven.lifecycle.Lifecycle;
import org.apache.maven.lifecycle.Schedule; import org.apache.maven.lifecycle.Schedule;
import org.apache.maven.lifecycle.Scheduling; import org.apache.maven.lifecycle.Scheduling;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import java.util.Arrays;
import java.util.List;
/** /**
* @author Kristian Rosenvold * @author Kristian Rosenvold
@ -37,14 +36,6 @@ public class DefaultLifecyclesStub
final List<Lifecycle> lifeCycles = Arrays.asList( lifecycle1, lifecycle2 ); final List<Lifecycle> lifeCycles = Arrays.asList( lifecycle1, lifecycle2 );
final List<Scheduling> schedulingList = getSchedulingList(); final List<Scheduling> schedulingList = getSchedulingList();
final DefaultLifecycles defaultLifecycles = new DefaultLifecycles( lifeCycles, schedulingList ); final DefaultLifecycles defaultLifecycles = new DefaultLifecycles( lifeCycles, schedulingList );
try
{
defaultLifecycles.initialize();
}
catch ( InitializationException e )
{
throw new RuntimeException( e );
}
return defaultLifecycles; return defaultLifecycles;
} }