From 9815406538b149faaf146699ac001e5309456d2a Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 6 Oct 2021 22:43:18 +0200 Subject: [PATCH] Install At End, Pt1 This PR is inspired by original "installAtEnd" feature, but does not need to be run as extension. In short, it targets 1st project of topologically sorted projects to store state in. --- pom.xml | 41 ++++++++++-- .../maven/plugins/install/InstallMojo.java | 65 ++++++++++--------- .../plugins/install/InstallFileMojoTest.java | 20 ++++-- .../plugins/install/InstallMojoTest.java | 23 +++++-- 4 files changed, 102 insertions(+), 47 deletions(-) diff --git a/pom.xml b/pom.xml index ca7b8764..ba7ae25e 100644 --- a/pom.xml +++ b/pom.xml @@ -63,8 +63,9 @@ - 3.0 - 7 + 3.2.5 + 1.7.32 + 8 2020-04-07T21:04:00Z @@ -73,13 +74,22 @@ org.apache.maven maven-plugin-api ${mavenVersion} + provided org.apache.maven maven-artifact ${mavenVersion} + provided + + + org.apache.maven + maven-core + ${mavenVersion} + provided + org.apache.maven.shared maven-artifact-transfer @@ -96,13 +106,13 @@ junit junit - 4.13.1 + 4.13.2 test org.apache.maven.plugin-testing maven-plugin-testing-harness - 2.1 + 3.3.0 test @@ -120,13 +130,31 @@ org.slf4j slf4j-api - 1.7.30 + ${slf4jVersion} provided org.slf4j slf4j-nop - 1.7.30 + ${slf4jVersion} + test + + + org.eclipse.aether + aether-api + 1.1.0 + test + + + org.eclipse.aether + aether-util + 1.1.0 + test + + + org.eclipse.aether + aether-impl + 1.1.0 test @@ -150,6 +178,7 @@ org.apache.maven.plugins maven-invoker-plugin + 3.2.2 ${project.build.directory}/it true 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 b01c1141..e4f098a5 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,21 @@ */ import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import org.apache.maven.execution.MavenSession; 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 +50,22 @@ public class InstallMojo extends AbstractInstallMojo { + private static final String INSTALL_REQUESTS_KEY = InstallMojo.class.getName() + ".installRequests"; - /** - * 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() ); + private static final MavenProject SENTINEL = new MavenProject(); - /** - */ @Parameter( defaultValue = "${project}", readonly = true, required = true ) private MavenProject project; @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true ) private List reactorProjects; + @Parameter( defaultValue = "${session}", required = true, readonly = true ) + private MavenSession session; + + @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. @@ -91,53 +91,60 @@ public class InstallMojo public void execute() throws MojoExecutionException, MojoFailureException { + + final String projectKey = project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion(); + final ConcurrentMap pluginContext = + (ConcurrentMap) session.getPluginContext( pluginDescriptor, reactorProjects.get( 0 ) ); + final Map installRequests = (Map) pluginContext.computeIfAbsent( + INSTALL_REQUESTS_KEY, + k -> Collections.synchronizedMap( new LinkedHashMap() ) + ); + boolean addedInstallRequest = false; if ( skip ) { + installRequests.put( projectKey, SENTINEL ); getLog().info( "Skipping artifact installation" ); } else { - // CHECKSTYLE_OFF: LineLength - ProjectInstallerRequest projectInstallerRequest = - new ProjectInstallerRequest().setProject( project ); - // CHECKSTYLE_ON: LineLength - if ( !installAtEnd ) { - installProject( session.getProjectBuildingRequest(), projectInstallerRequest ); + installProject( project ); } else { - INSTALLREQUESTS.add( projectInstallerRequest ); + installRequests.put( projectKey, project ); addedInstallRequest = true; } } - boolean projectsReady = READYPROJECTSCOUNTER.incrementAndGet() == reactorProjects.size(); - if ( projectsReady ) + if ( installRequests.size() == reactorProjects.size() ) { - synchronized ( INSTALLREQUESTS ) + for ( Map.Entry projectEntry : installRequests.entrySet() ) { - while ( !INSTALLREQUESTS.isEmpty() ) + if ( projectEntry.getValue() == SENTINEL ) + { + getLog().info( "Project " + projectKey + " skipped install" ); + } + else { - installProject( session.getProjectBuildingRequest(), INSTALLREQUESTS.remove( 0 ) ); + installProject( projectEntry.getValue() ); } } } else if ( addedInstallRequest ) { - getLog().info( "Installing " + project.getGroupId() + ":" + project.getArtifactId() + ":" - + project.getVersion() + " at end" ); + getLog().info( "Installing " + projectKey + " at end" ); } } - 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/InstallFileMojoTest.java b/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java index 8b3b070b..d04b1b14 100644 --- a/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java @@ -21,18 +21,20 @@ import java.io.File; import java.io.Reader; +import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.plugin.testing.AbstractMojoTestCase; -import org.apache.maven.plugins.install.InstallFileMojo; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.utils.ReaderFactory; import org.apache.maven.shared.utils.io.FileUtils; -import org.sonatype.aether.impl.internal.EnhancedLocalRepositoryManager; -import org.sonatype.aether.util.DefaultRepositorySystemSession; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.NoLocalRepositoryManagerException; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -215,7 +217,9 @@ public void testInstallFileWithPomAsPackaging() InstallFileMojo mojo = (InstallFileMojo) lookupMojo( "install-file", testPom ); assertNotNull( mojo ); - + + setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() ); + setVariableValueToObject( mojo, "session", createMavenSession() ); assignValuesForParameter( mojo ); @@ -243,7 +247,9 @@ public void testInstallFile() InstallFileMojo mojo = (InstallFileMojo) lookupMojo( "install-file", testPom ); assertNotNull( mojo ); - + + setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() ); + setVariableValueToObject( mojo, "session", createMavenSession() ); assignValuesForParameter( mojo ); @@ -281,11 +287,11 @@ private String dotToSlashReplacer( String parameter ) return parameter.replace( '.', '/' ); } - private MavenSession createMavenSession() + private MavenSession createMavenSession() throws NoLocalRepositoryManagerException { MavenSession session = mock( MavenSession.class ); DefaultRepositorySystemSession repositorySession = new DefaultRepositorySystemSession(); - repositorySession.setLocalRepositoryManager( new EnhancedLocalRepositoryManager( new File( LOCAL_REPO ) ) ); + repositorySession.setLocalRepositoryManager( new EnhancedLocalRepositoryManagerFactory().newInstance( repositorySession, new LocalRepository( LOCAL_REPO )) ); ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(); buildingRequest.setRepositorySession( repositorySession ); when( session.getProjectBuildingRequest() ).thenReturn( buildingRequest ); 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 63ac6fa9..5d0ed3c7 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; @@ -38,8 +41,10 @@ import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.transfer.repository.RepositoryManager; import org.apache.maven.shared.utils.io.FileUtils; -import org.sonatype.aether.impl.internal.EnhancedLocalRepositoryManager; -import org.sonatype.aether.util.DefaultRepositorySystemSession; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.NoLocalRepositoryManagerException; /** * @author Allan Ramirez @@ -85,7 +90,8 @@ public void testBasicInstall() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); - + + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -118,6 +124,7 @@ public void testBasicInstallWithAttachedArtifacts() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -160,6 +167,7 @@ public void testUpdateReleaseParamSetToTrue() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -186,6 +194,7 @@ public void testInstallIfArtifactFileIsNull() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -222,6 +231,7 @@ public void testInstallIfPackagingIsPom() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -258,6 +268,7 @@ public void testBasicInstallAndCreate() MavenSession mavenSession = createMavenSession(); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", mavenSession ); @@ -314,6 +325,7 @@ public void testSkip() MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); updateMavenProject( project ); + setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); @@ -343,14 +355,15 @@ private String dotToSlashReplacer( String parameter ) return parameter.replace( '.', '/' ); } - private MavenSession createMavenSession() + private MavenSession createMavenSession() throws NoLocalRepositoryManagerException { MavenSession session = mock( MavenSession.class ); DefaultRepositorySystemSession repositorySession = new DefaultRepositorySystemSession(); - repositorySession.setLocalRepositoryManager( new EnhancedLocalRepositoryManager( new File( LOCAL_REPO ) ) ); + repositorySession.setLocalRepositoryManager( new EnhancedLocalRepositoryManagerFactory().newInstance( 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; }