Skip to content

Commit

Permalink
[MINSTALL-115] Install At End feature (no extension) (#15)
Browse files Browse the repository at this point in the history
This PR makes installAtEnd work as expected even
if maven-install-plugin is not used as extension.

How it works: it uses mojo Contexts to store "state markers":
* presence of marker means project was "processed"
* value of state marker tells what should be done

UTs adjusted to provide plugin context (was null before).
Plugin updated (as required by maven-plugin-testing-harness) and 
cleaned up.
  • Loading branch information
cstamas committed Jul 3, 2022
1 parent d13f571 commit 9fa9fd5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/it/install-at-end-fail/verify.groovy
Expand Up @@ -22,5 +22,5 @@ assert !( new File( basedir, "../../local-repo/org/apache/maven/its/install/dae/

File buildLog = new File( basedir, 'build.log' )
assert buildLog.exists()
assert buildLog.text.contains( "[INFO] Installing org.apache.maven.its.install.dae.fail:dae:1.0 at end" )
assert buildLog.text.contains( "[INFO] Deferring install for org.apache.maven.its.install.dae.fail:dae:1.0 at end" )

2 changes: 1 addition & 1 deletion src/it/install-at-end-pass/verify.groovy
Expand Up @@ -22,5 +22,5 @@ assert new File( basedir, "../../local-repo/org/apache/maven/its/install/dae/pas

File buildLog = new File( basedir, 'build.log' )
assert buildLog.exists()
assert buildLog.text.contains( "[INFO] Installing org.apache.maven.its.install.dae.pass:dae:1.0 at end" )
assert buildLog.text.contains( "[INFO] Deferring install for org.apache.maven.its.install.dae.pass:dae:1.0 at end" )

91 changes: 56 additions & 35 deletions src/main/java/org/apache/maven/plugins/install/InstallMojo.java
Expand Up @@ -20,19 +20,17 @@
*/

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Map;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.shared.transfer.artifact.install.ArtifactInstallerException;
import org.apache.maven.shared.transfer.project.NoFileAssignedException;
import org.apache.maven.shared.transfer.project.install.ProjectInstaller;
Expand All @@ -48,24 +46,15 @@
public class InstallMojo
extends AbstractInstallMojo
{

/**
* When building with multiple threads, reaching the last project doesn't have to mean that all projects are ready
* to be installed
*/
private static final AtomicInteger READYPROJECTSCOUNTER = new AtomicInteger();

private static final List<ProjectInstallerRequest> INSTALLREQUESTS =
Collections.synchronizedList( new ArrayList<ProjectInstallerRequest>() );

/**
*/
@Parameter( defaultValue = "${project}", readonly = true, required = true )
private MavenProject project;

@Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
private List<MavenProject> reactorProjects;

@Parameter( defaultValue = "${plugin}", required = true, readonly = true )
private PluginDescriptor pluginDescriptor;

/**
* Whether every project should be installed during its own install-phase or at the end of the multimodule build. If
* set to {@code true} and the build fails, none of the reactor projects is installed.
Expand All @@ -88,56 +77,88 @@ public class InstallMojo
@Component
private ProjectInstaller installer;

private enum State
{
SKIPPED, INSTALLED, TO_BE_INSTALLED
}

private static final String INSTALL_PROCESSED_MARKER = InstallMojo.class.getName() + ".processed";

private void putState( State state )
{
getPluginContext().put( INSTALL_PROCESSED_MARKER, state.name() );
}

private State getState( MavenProject project )
{
Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
return State.valueOf( (String) pluginContext.get( INSTALL_PROCESSED_MARKER ) );
}

private boolean hasState( MavenProject project )
{
Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
return pluginContext.containsKey( INSTALL_PROCESSED_MARKER );
}

public void execute()
throws MojoExecutionException, MojoFailureException
{
boolean addedInstallRequest = false;
if ( skip )
{
getLog().info( "Skipping artifact installation" );
putState( State.SKIPPED );
}
else
{
// CHECKSTYLE_OFF: LineLength
ProjectInstallerRequest projectInstallerRequest =
new ProjectInstallerRequest().setProject( project );
// CHECKSTYLE_ON: LineLength

if ( !installAtEnd )
{
installProject( session.getProjectBuildingRequest(), projectInstallerRequest );
installProject( project );
putState( State.INSTALLED );
}
else
{
INSTALLREQUESTS.add( projectInstallerRequest );
addedInstallRequest = true;
getLog().info( "Deferring install for " + getProjectReferenceId( project ) + " at end" );
putState( State.TO_BE_INSTALLED );
}
}

boolean projectsReady = READYPROJECTSCOUNTER.incrementAndGet() == reactorProjects.size();
if ( projectsReady )
if ( allProjectsMarked() )
{
synchronized ( INSTALLREQUESTS )
for ( MavenProject reactorProject : reactorProjects )
{
while ( !INSTALLREQUESTS.isEmpty() )
State state = getState( reactorProject );
if ( state == State.TO_BE_INSTALLED )
{
installProject( session.getProjectBuildingRequest(), INSTALLREQUESTS.remove( 0 ) );
installProject( reactorProject );
}
}
}
else if ( addedInstallRequest )
}

private String getProjectReferenceId( MavenProject mavenProject )
{
return mavenProject.getGroupId() + ":" + mavenProject.getArtifactId() + ":" + mavenProject.getVersion();
}

private boolean allProjectsMarked()
{
for ( MavenProject reactorProject : reactorProjects )
{
getLog().info( "Installing " + project.getGroupId() + ":" + project.getArtifactId() + ":"
+ project.getVersion() + " at end" );
if ( !hasState( reactorProject ) )
{
return false;
}
}
return true;
}

private void installProject( ProjectBuildingRequest pbr, ProjectInstallerRequest pir )
private void installProject( MavenProject pir )
throws MojoFailureException, MojoExecutionException
{
try
{
installer.install( session.getProjectBuildingRequest(), pir );
installer.install( session.getProjectBuildingRequest(), new ProjectInstallerRequest().setProject( pir ) );
}
catch ( IOException e )
{
Expand Down
Expand Up @@ -19,17 +19,20 @@
* under the License.
*/

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.apache.maven.plugins.install.stubs.AttachedArtifactStub0;
import org.apache.maven.plugins.install.stubs.InstallArtifactStub;
Expand Down Expand Up @@ -88,6 +91,8 @@ public void testBasicInstall()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand Down Expand Up @@ -120,6 +125,8 @@ public void testBasicInstallWithAttachedArtifacts()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand Down Expand Up @@ -162,6 +169,8 @@ public void testUpdateReleaseParamSetToTrue()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand All @@ -188,6 +197,8 @@ public void testInstallIfArtifactFileIsNull()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand Down Expand Up @@ -224,6 +235,8 @@ public void testInstallIfPackagingIsPom()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand Down Expand Up @@ -260,6 +273,8 @@ public void testBasicInstallAndCreate()
MavenSession mavenSession = createMavenSession();
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", mavenSession );

Expand Down Expand Up @@ -316,6 +331,8 @@ public void testSkip()
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
updateMavenProject( project );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", createMavenSession() );

Expand Down Expand Up @@ -357,6 +374,8 @@ repositorySession, new LocalRepository( LOCAL_REPO )
ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest();
buildingRequest.setRepositorySession( repositorySession );
when( session.getProjectBuildingRequest() ).thenReturn( buildingRequest );
when( session.getPluginContext(any(PluginDescriptor.class), any(MavenProject.class)))
.thenReturn( new ConcurrentHashMap<String, Object>() );
return session;
}

Expand Down

0 comments on commit 9fa9fd5

Please sign in to comment.