diff --git a/src/it/install-at-end-fail/verify.groovy b/src/it/install-at-end-fail/verify.groovy index f35990b..a2801f5 100644 --- a/src/it/install-at-end-fail/verify.groovy +++ b/src/it/install-at-end-fail/verify.groovy @@ -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" ) diff --git a/src/it/install-at-end-pass/verify.groovy b/src/it/install-at-end-pass/verify.groovy index 3487d52..f1b7e51 100644 --- a/src/it/install-at-end-pass/verify.groovy +++ b/src/it/install-at-end-pass/verify.groovy @@ -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" ) diff --git a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java index b01c114..8ea2f30 100644 --- a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java +++ b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java @@ -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; @@ -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 INSTALLREQUESTS = - Collections.synchronizedList( new ArrayList() ); - - /** - */ @Parameter( defaultValue = "${project}", readonly = true, required = true ) private MavenProject project; @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true ) private List 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. @@ -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 pluginContext = session.getPluginContext( pluginDescriptor, project ); + return State.valueOf( (String) pluginContext.get( INSTALL_PROCESSED_MARKER ) ); + } + + private boolean hasState( MavenProject project ) + { + Map 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 ) { diff --git a/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java b/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java index ed73d2c..1347e4b 100644 --- a/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java @@ -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; @@ -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() ); @@ -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() ); @@ -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() ); @@ -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() ); @@ -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() ); @@ -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 ); @@ -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() ); @@ -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() ); return session; }