[MNG-4224] maven lifecycle participant

Submitted by: Igor Fedorenko

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@789993 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-06-30 22:36:30 +00:00
parent e0d29fe6a3
commit accb45543f
9 changed files with 306 additions and 22 deletions

View File

@ -0,0 +1,54 @@
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 org.apache.maven.execution.MavenSession;
/**
* Allows core extensions to participate in build lifecycle.
*
* All callback methods (will) follow beforeXXX/afterXXX naming pattern to
* indicate at what lifecycle point it is being called.
*
*/
public abstract class AbstractMavenLifecycleParticipant
{
/**
* Invoked after all MavenProject instances have been created.
*
* This callback is intended to allow extensions to manipulate MavenProjects
* before they are sorted and actual build execution starts.
*/
public void afterProjectsRead( MavenSession session ) throws MavenExecutionException
{
// do nothing
}
/**
* Invoked after MavenSession instance has been created.
*
* This callback is intended to allow extensions to inject execution properties,
* activate profiles and perform similar tasks that affect MavenProject
* instance construction.
*/
public void afterSessionStart( MavenSession session ) throws MavenExecutionException
{
// do nothing
}
}

View File

@ -22,7 +22,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@ -46,6 +45,7 @@ import org.apache.maven.repository.DelegatingLocalArtifactRepository;
import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.Os; import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.StringUtils;
@ -87,12 +87,23 @@ public class DefaultMaven
request.setLocalRepository( delegatingLocalArtifactRepository ); request.setLocalRepository( delegatingLocalArtifactRepository );
MavenSession session; MavenSession session = new MavenSession( container, request, result);
Map<String,MavenProject> projects; try
{
for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants() )
{
listener.afterSessionStart( session );
}
}
catch ( MavenExecutionException e )
{
return processResult( result, e );
}
//TODO: optimize for the single project or no project //TODO: optimize for the single project or no project
List<MavenProject> projects;
try try
{ {
projects = getProjectsForMavenReactor( request ); projects = getProjectsForMavenReactor( request );
@ -101,7 +112,7 @@ public class DefaultMaven
if ( projects.isEmpty() ) if ( projects.isEmpty() )
{ {
MavenProject project = projectBuilder.buildStandaloneSuperProject( request.getProjectBuildingRequest() ); MavenProject project = projectBuilder.buildStandaloneSuperProject( request.getProjectBuildingRequest() );
projects.put( ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() ), project ); projects.add( project );
request.setProjectPresent( false ); request.setProjectPresent( false );
} }
} }
@ -114,11 +125,27 @@ public class DefaultMaven
return processResult( result, e ); return processResult( result, e );
} }
session.setProjects( projects );
try try
{ {
ProjectSorter projectSorter = new ProjectSorter( projects.values() ); for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants() )
{
listener.afterProjectsRead( session );
}
}
catch ( MavenExecutionException e )
{
return processResult( result, e );
}
session = new MavenSession( container, request, result, projectSorter.getSortedProjects() ); try
{
ProjectSorter projectSorter = new ProjectSorter( session.getProjects() );
projects = projectSorter.getSortedProjects();
session.setProjects( projects );
} }
catch ( CycleDetectedException e ) catch ( CycleDetectedException e )
{ {
@ -138,8 +165,14 @@ public class DefaultMaven
// Reactor // Reactor
// Workspace // Workspace
// User Local Repository // User Local Repository
try
delegatingLocalArtifactRepository.setBuildReactor( new ReactorArtifactRepository( projects ) ); {
delegatingLocalArtifactRepository.setBuildReactor( new ReactorArtifactRepository( getProjectMap( session.getProjects() ) ) );
}
catch ( MavenExecutionException e )
{
return processResult( result, e );
}
if ( result.hasExceptions() ) if ( result.hasExceptions() )
{ {
@ -162,6 +195,22 @@ public class DefaultMaven
return result; return result;
} }
private List<AbstractMavenLifecycleParticipant> getLifecycleParticipants()
{
// TODO injection of component lists does not work
List<AbstractMavenLifecycleParticipant> lifecycleListeners;
try
{
lifecycleListeners = container.lookupList( AbstractMavenLifecycleParticipant.class );
}
catch ( ComponentLookupException e1 )
{
// this is just silly, lookupList should return an empty list!
lifecycleListeners = new ArrayList<AbstractMavenLifecycleParticipant>();
}
return lifecycleListeners;
}
private MavenExecutionResult processResult( MavenExecutionResult result, Exception e ) private MavenExecutionResult processResult( MavenExecutionResult result, Exception e )
{ {
ExceptionHandler handler = new DefaultExceptionHandler(); ExceptionHandler handler = new DefaultExceptionHandler();
@ -175,14 +224,14 @@ public class DefaultMaven
return result; return result;
} }
protected Map<String,MavenProject> getProjectsForMavenReactor( MavenExecutionRequest request ) private List<MavenProject> getProjectsForMavenReactor( MavenExecutionRequest request )
throws MavenExecutionException, ProjectBuildingException throws MavenExecutionException, ProjectBuildingException
{ {
// We have no POM file. // We have no POM file.
// //
if ( request.getPom() == null || !request.getPom().exists() ) if ( request.getPom() == null || !request.getPom().exists() )
{ {
return new HashMap<String,MavenProject>(); return new ArrayList<MavenProject>();
} }
List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() ); List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() );
@ -191,6 +240,12 @@ public class DefaultMaven
collectProjects( projects, files, request ); collectProjects( projects, files, request );
return projects;
}
private Map<String, MavenProject> getProjectMap( List<MavenProject> projects )
throws org.apache.maven.DuplicateProjectException
{
Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>(); Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>(); Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();

View File

@ -31,7 +31,6 @@ import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.settings.Settings; import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.util.dag.CycleDetectedException;
/** /**
* @author Jason van Zyl * @author Jason van Zyl
@ -55,18 +54,30 @@ public class MavenSession
private MavenProject topLevelProject; private MavenProject topLevelProject;
@Deprecated
public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, MavenProject project ) public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, MavenProject project )
throws CycleDetectedException, DuplicateProjectException
{ {
this( container, request, result, Arrays.asList( new MavenProject[]{ project } ) ); this( container, request, result, Arrays.asList( new MavenProject[]{ project } ) );
} }
@Deprecated
public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, List<MavenProject> projects ) public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, List<MavenProject> projects )
throws CycleDetectedException, DuplicateProjectException
{ {
this.container = container; this.container = container;
this.request = request; this.request = request;
this.result = result; this.result = result;
setProjects( projects );
}
public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result )
{
this.container = container;
this.request = request;
this.result = result;
}
public void setProjects( List<MavenProject> projects )
{
//TODO: Current for testing classes creating the session //TODO: Current for testing classes creating the session
if ( projects.size() > 0 ) if ( projects.size() > 0 )
{ {

View File

@ -806,9 +806,12 @@ public class DefaultLifecycleExecutor
{ {
String phase = goalsForLifecyclePhase.getKey(); String phase = goalsForLifecyclePhase.getKey();
String goals = goalsForLifecyclePhase.getValue(); String goals = goalsForLifecyclePhase.getValue();
if ( goals != null )
{
parseLifecyclePhaseDefinitions( plugins, phase, goals ); parseLifecyclePhaseDefinitions( plugins, phase, goals );
} }
} }
}
else if ( lifecycle.getDefaultPhases() != null ) else if ( lifecycle.getDefaultPhases() != null )
{ {
for ( String goals : lifecycle.getDefaultPhases() ) for ( String goals : lifecycle.getDefaultPhases() )

View File

@ -222,7 +222,7 @@ public class DefaultPluginManager
} }
} }
private PluginDescriptor parsebuildPluginDescriptor( InputStream is ) public PluginDescriptor parsebuildPluginDescriptor( InputStream is )
throws IOException, PlexusConfigurationException throws IOException, PlexusConfigurationException
{ {
PluginDescriptor pluginDescriptor; PluginDescriptor pluginDescriptor;

View File

@ -165,6 +165,8 @@ public class MavenProject
private File parentFile; private File parentFile;
private Map<String, Object> context;
// //
public MavenProject() public MavenProject()
@ -1966,4 +1968,41 @@ public class MavenProject
{ {
return groupId + ":" + artifactId + ":" + version; return groupId + ":" + artifactId + ":" + version;
} }
/**
* Sets the value of the context value of this project identified
* by the given key. If the supplied value is <code>null</code>,
* the context value is removed from this project.
*
* Context values are intended to allow core extensions to associate
* derived state with project instances.
*/
public void setContextValue( String key, Object value )
{
if ( context == null )
{
context = new HashMap<String, Object>();
}
if ( value != null )
{
context.put( key, value );
}
else
{
context.remove( key );
}
}
/**
* Returns context value of this project associated with the given key
* or null if this project has no such value.
*/
public Object getContextValue( String key )
{
if ( context == null )
{
return null;
}
return context.get( key );
}
} }

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.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
public class MavenLifecycleParticipantTest
extends AbstractCoreMavenComponentTestCase
{
private static final String INJECTED_ARTIFACT_ID = "injected";
public static class InjectDependencyLifecycleListener
extends AbstractMavenLifecycleParticipant
{
@Override
public void afterProjectsRead( MavenSession session )
{
MavenProject project = session.getProjects().get( 0 );
Dependency dependency = new Dependency();
dependency.setArtifactId( INJECTED_ARTIFACT_ID );
dependency.setGroupId( "foo" );
dependency.setVersion( "1.2.3" );
dependency.setScope( "system" );
try
{
dependency.setSystemPath( new File(
"src/test/projects/lifecycle-executor/project-with-additional-lifecycle-elements/pom.xml" ).getCanonicalPath() );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
project.getModel().addDependency( dependency );
}
@Override
public void afterSessionStart( MavenSession session )
{
session.getExecutionProperties().setProperty( "injected", "bar" );
}
}
@Override
protected void setupContainer()
{
super.setupContainer();
}
@Override
protected String getProjectsDirectory()
{
return "src/test/projects/lifecycle-listener";
}
public void testDependencyInjection()
throws Exception
{
PlexusContainer container = getContainer();
ComponentDescriptor cd =
new ComponentDescriptor( InjectDependencyLifecycleListener.class, container.getContainerRealm() );
cd.setRoleClass( AbstractMavenLifecycleParticipant.class );
container.addComponentDescriptor( cd );
Maven maven = container.lookup( Maven.class );
File pom = getProject( "lifecycle-listener-dependency-injection" );
MavenExecutionRequest request = createMavenExecutionRequest( pom );
MavenExecutionResult result = maven.execute( request );
assertFalse( result.hasExceptions() );
MavenProject project = result.getProject();
assertEquals( "bar", project.getProperties().getProperty( "foo" ) );
ArrayList<Artifact> artifacts = new ArrayList<Artifact>( project.getArtifacts() );
assertEquals( 1, artifacts.size() );
assertEquals( INJECTED_ARTIFACT_ID, artifacts.get( 0 ).getArtifactId() );
}
}

View File

@ -6,7 +6,6 @@ import org.apache.maven.exception.ExceptionHandler;
import org.apache.maven.exception.ExceptionSummary; import org.apache.maven.exception.ExceptionSummary;
import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.component.annotations.Requirement;
public class MavenTest public class MavenTest

View File

@ -0,0 +1,12 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven.lifecycle-listener.test</groupId>
<artifactId>simple</artifactId>
<version>1.0</version>
<properties>
<foo>${injected}</foo>
</properties>
</project>