diff --git a/pom.xml b/pom.xml index 45d3ed1..4b7c7b9 100644 --- a/pom.xml +++ b/pom.xml @@ -25,12 +25,12 @@ under the License. org.apache.maven.plugins maven-plugins - 35 + 36 maven-clean-plugin - 3.2.1-SNAPSHOT + 4.0.0-SNAPSHOT maven-plugin Apache Maven Clean Plugin @@ -65,44 +65,31 @@ under the License. - 3.2.5 + 4.0.0-alpha-1-SNAPSHOT 8 - 2.22.2 - 3.6.4 + 4.0.0-SNAPSHOT + 4.0.0-SNAPSHOT 2022-04-01T21:20:42Z org.apache.maven - maven-plugin-api + maven-api-core ${mavenVersion} provided - org.apache.maven.shared - maven-shared-utils - 3.3.4 - - - - - org.apache.maven.plugin-tools - maven-plugin-annotations - provided + org.codehaus.plexus + plexus-utils + ${mavenVersion} org.apache.maven.plugin-testing maven-plugin-testing-harness - 3.3.0 - test - - - org.apache.maven - maven-compat - ${mavenVersion} + ${mavenPluginTestingVersion} test @@ -112,13 +99,28 @@ under the License. provided - junit - junit - 4.13.2 + org.junit.jupiter + junit-jupiter + 5.8.0 test + + + + org.apache.maven.plugins + maven-plugin-plugin + 4.0.0-SNAPSHOT + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M7 + + + + run-its diff --git a/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java b/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java index 4b5ba86..fadf5db 100644 --- a/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java +++ b/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java @@ -19,11 +19,12 @@ * under the License. */ -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.api.Session; +import org.apache.maven.api.plugin.MojoException; +import org.apache.maven.api.plugin.annotations.Mojo; +import org.apache.maven.api.plugin.annotations.Parameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -44,9 +45,9 @@ * @see org.apache.maven.plugins.clean.Fileset * @since 2.0 */ -@Mojo( name = "clean", threadSafe = true ) +@Mojo( name = "clean" ) public class CleanMojo - extends AbstractMojo + implements org.apache.maven.api.plugin.Mojo { public static final String FAST_MODE_BACKGROUND = "background"; @@ -55,6 +56,8 @@ public class CleanMojo public static final String FAST_MODE_DEFER = "defer"; + private static final Logger LOGGER = LoggerFactory.getLogger( CleanMojo.class ); + /** * This is where build results go. */ @@ -209,21 +212,20 @@ public class CleanMojo private String fastMode; @Parameter( defaultValue = "${session}", readonly = true ) - private MavenSession session; + private Session session; /** * Deletes file-sets in the following project build directory order: (source) directory, output directory, test * directory, report directory, and then the additional file-sets. * - * @throws MojoExecutionException When a directory failed to get deleted. - * @see org.apache.maven.plugin.Mojo#execute() + * @throws MojoException When a directory failed to get deleted. + * @see org.apache.maven.api.plugin.Mojo#execute() */ public void execute() - throws MojoExecutionException { if ( skip ) { - getLog().info( "Clean is skipped." ); + LOGGER.info( "Clean is skipped." ); return; } @@ -243,7 +245,7 @@ else if ( fast && multiModuleProjectDirectory != null ) fastDir = null; if ( fast ) { - getLog().warn( "Fast clean requires maven 3.3.1 or newer, " + LOGGER.warn( "Fast clean requires maven 3.3.1 or newer, " + "or an explicit directory to be specified with the 'fastDir' configuration of " + "this plugin, or the 'maven.clean.fastDir' user property to be set." ); } @@ -256,7 +258,7 @@ else if ( fast && multiModuleProjectDirectory != null ) + FAST_MODE_BACKGROUND + "', '" + FAST_MODE_AT_END + "' and '" + FAST_MODE_DEFER + "'." ); } - Cleaner cleaner = new Cleaner( session, getLog(), isVerbose(), fastDir, fastMode ); + Cleaner cleaner = new Cleaner( session, LOGGER, isVerbose(), fastDir, fastMode ); try { @@ -274,7 +276,7 @@ else if ( fast && multiModuleProjectDirectory != null ) { if ( fileset.getDirectory() == null ) { - throw new MojoExecutionException( "Missing base directory for " + fileset ); + throw new MojoException( "Missing base directory for " + fileset ); } GlobSelector selector = new GlobSelector( fileset.getIncludes(), fileset.getExcludes(), fileset.isUseDefaultExcludes() ); @@ -285,7 +287,7 @@ else if ( fast && multiModuleProjectDirectory != null ) } catch ( IOException e ) { - throw new MojoExecutionException( "Failed to clean project: " + e.getMessage(), e ); + throw new MojoException( "Failed to clean project: " + e.getMessage(), e ); } } @@ -296,7 +298,7 @@ else if ( fast && multiModuleProjectDirectory != null ) */ private boolean isVerbose() { - return ( verbose != null ) ? verbose : getLog().isDebugEnabled(); + return ( verbose != null ) ? verbose : LOGGER.isDebugEnabled(); } /** diff --git a/src/main/java/org/apache/maven/plugins/clean/Cleaner.java b/src/main/java/org/apache/maven/plugins/clean/Cleaner.java index 4e6e9d2..0765a96 100644 --- a/src/main/java/org/apache/maven/plugins/clean/Cleaner.java +++ b/src/main/java/org/apache/maven/plugins/clean/Cleaner.java @@ -21,20 +21,18 @@ import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayDeque; import java.util.Deque; -import org.apache.maven.execution.ExecutionListener; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.shared.utils.Os; -import org.eclipse.aether.SessionData; +import org.apache.maven.api.Event; +import org.apache.maven.api.EventType; +import org.apache.maven.api.Listener; +import org.apache.maven.api.Session; +import org.apache.maven.api.SessionData; +import org.codehaus.plexus.util.Os; import static org.apache.maven.plugins.clean.CleanMojo.FAST_MODE_BACKGROUND; import static org.apache.maven.plugins.clean.CleanMojo.FAST_MODE_DEFER; @@ -54,7 +52,7 @@ class Cleaner /** * The maven session. This is typically non-null in a real run, but it can be during unit tests. */ - private final MavenSession session; + private final Session session; private final Logger logDebug; @@ -74,7 +72,7 @@ class Cleaner * @param verbose Whether to perform verbose logging. * @param fastMode The fast deletion mode */ - Cleaner( MavenSession session, final Log log, boolean verbose, File fastDir, String fastMode ) + Cleaner( Session session, final org.slf4j.Logger log, boolean verbose, File fastDir, String fastMode ) { logDebug = ( log == null || !log.isDebugEnabled() ) ? null : log::debug; @@ -153,7 +151,7 @@ private boolean fastDelete( File baseDirFile ) Files.move( baseDir, tmpDir, StandardCopyOption.REPLACE_EXISTING ); if ( session != null ) { - session.getRepositorySession().getData().set( LAST_DIRECTORY_TO_DELETE, baseDir.toFile() ); + session.getData().set( LAST_DIRECTORY_TO_DELETE, baseDir.toFile() ); } baseDir = tmpDir; } @@ -379,7 +377,7 @@ public void update( Result result ) private interface Logger { - void log( CharSequence message ); + void log( String message ); } @@ -473,7 +471,7 @@ synchronized File pollNext() { if ( cleaner.session != null ) { - SessionData data = cleaner.session.getRepositorySession().getData(); + SessionData data = cleaner.session.getData(); File lastDir = ( File ) data.get( LAST_DIRECTORY_TO_DELETE ); if ( lastDir != null ) { @@ -513,16 +511,12 @@ synchronized boolean doDelete( File dir ) */ private void wrapExecutionListener() { - ExecutionListener executionListener = cleaner.session.getRequest().getExecutionListener(); - if ( executionListener == null - || !Proxy.isProxyClass( executionListener.getClass() ) - || !( Proxy.getInvocationHandler( executionListener ) instanceof SpyInvocationHandler ) ) + synchronized ( CleanerListener.class ) { - ExecutionListener listener = ( ExecutionListener ) Proxy.newProxyInstance( - ExecutionListener.class.getClassLoader(), - new Class[] { ExecutionListener.class }, - new SpyInvocationHandler( executionListener ) ); - cleaner.session.getRequest().setExecutionListener( listener ); + if ( cleaner.session.getListeners().stream().noneMatch( l -> l instanceof CleanerListener ) ) + { + cleaner.session.registerListener( new CleanerListener() ); + } } } @@ -554,29 +548,16 @@ synchronized void doSessionEnd() } - static class SpyInvocationHandler implements InvocationHandler + static class CleanerListener implements Listener { - private final ExecutionListener delegate; - - SpyInvocationHandler( ExecutionListener delegate ) - { - this.delegate = delegate; - } - @Override - public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable + public void onEvent( Event event ) { - if ( "sessionEnded".equals( method.getName() ) ) + if ( event.getType() == EventType.SessionEnded ) { BackgroundCleaner.sessionEnd(); } - if ( delegate != null ) - { - return method.invoke( delegate, args ); - } - return null; } - } } diff --git a/src/main/java/org/apache/maven/plugins/clean/GlobSelector.java b/src/main/java/org/apache/maven/plugins/clean/GlobSelector.java index ab791eb..3f4f5fd 100644 --- a/src/main/java/org/apache/maven/plugins/clean/GlobSelector.java +++ b/src/main/java/org/apache/maven/plugins/clean/GlobSelector.java @@ -19,12 +19,12 @@ * under the License. */ -import org.apache.maven.shared.utils.io.DirectoryScanner; -import org.apache.maven.shared.utils.io.SelectorUtils; - import java.io.File; import java.util.Arrays; +import org.codehaus.plexus.util.DirectoryScanner; +import org.codehaus.plexus.util.SelectorUtils; + /** * Selects paths based on Ant-like glob patterns. diff --git a/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java b/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java index 84b638f..6c443b9 100644 --- a/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java @@ -19,49 +19,60 @@ * under the License. */ -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.testing.AbstractMojoTestCase; - import java.io.File; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; +import java.util.Properties; + +import com.google.inject.Provides; +import com.google.inject.Singleton; +import org.apache.maven.api.Session; +import org.apache.maven.api.plugin.MojoException; +import org.apache.maven.api.plugin.testing.InjectMojo; +import org.apache.maven.api.plugin.testing.MojoTest; +import org.apache.maven.api.plugin.testing.stubs.SessionStub; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import static org.apache.maven.api.plugin.testing.MojoExtension.getBasedir; +import static org.apache.maven.api.plugin.testing.MojoExtension.setVariableValueToObject; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.doReturn; -import static org.apache.commons.io.FileUtils.copyDirectory; /** * Test the clean mojo. - * - * @author Vincent Siveton */ +@MojoTest public class CleanMojoTest - extends AbstractMojoTestCase { + private static final String LOCAL_REPO = "target/local-repo/"; + /** * Tests the simple removal of directories * * @throws Exception in case of an error. */ - public void testBasicClean() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/basic-clean-test/plugin-pom.xml" ) + public void testBasicClean( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/basic-clean-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/basic-clean-test" ), - new File( getBasedir(), "target/test-classes/unit/basic-clean-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); mojo.execute(); - assertFalse( "Directory exists", checkExists( getBasedir() + "/target/test-classes/unit/" - + "basic-clean-test/buildDirectory" ) ); - assertFalse( "Directory exists", checkExists( getBasedir() + "/target/test-classes/unit/basic-clean-test/" - + "buildOutputDirectory" ) ); - assertFalse( "Directory exists", checkExists( getBasedir() + "/target/test-classes/unit/basic-clean-test/" - + "buildTestDirectory" ) ); + assertFalse( checkExists( getBasedir() + "/target/test-classes/unit/" + + "basic-clean-test/buildDirectory" ), "Directory exists" ); + assertFalse( checkExists( getBasedir() + "/target/test-classes/unit/basic-clean-test/" + + "buildOutputDirectory" ), "Directory exists" ); + assertFalse( checkExists( getBasedir() + "/target/test-classes/unit/basic-clean-test/" + + "buildTestDirectory" ), "Directory exists" ); } /** @@ -69,16 +80,10 @@ public void testBasicClean() * * @throws Exception in case of an error. */ - public void testCleanNestedStructure() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/nested-clean-test/plugin-pom.xml" ) + public void testCleanNestedStructure( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/nested-clean-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/nested-clean-test" ), - new File( getBasedir(), "target/test-classes/unit/nested-clean-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); mojo.execute(); @@ -94,16 +99,10 @@ public void testCleanNestedStructure() * * @throws Exception in case of an error. */ - public void testCleanEmptyDirectories() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/empty-clean-test/plugin-pom.xml" ) + public void testCleanEmptyDirectories( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/empty-clean-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/empty-clean-test" ), - new File( getBasedir(), "target/test-classes/unit/empty-clean-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupEmptyMojo( "clean", pluginPom ); assertNotNull( mojo ); mojo.execute(); @@ -122,16 +121,10 @@ public void testCleanEmptyDirectories() * * @throws Exception in case of an error. */ - public void testFilesetsClean() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/fileset-clean-test/plugin-pom.xml" ) + public void testFilesetsClean( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/fileset-clean-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/fileset-clean-test" ), - new File( getBasedir(), "target/test-classes/unit/fileset-clean-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); mojo.execute(); @@ -158,28 +151,14 @@ public void testFilesetsClean() * * @throws Exception in case of an error. */ - public void testCleanInvalidDirectory() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/invalid-directory-test/plugin-pom.xml" ) + public void testCleanInvalidDirectory( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/invalid-directory-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/invalid-directory-test" ), - new File( getBasedir(), "target/test-classes/unit/invalid-directory-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); - try - { - mojo.execute(); - - fail( "Should fail to delete a file treated as a directory" ); - } - catch ( MojoExecutionException expected ) - { - assertTrue( true ); - } + assertThrows( MojoException.class, mojo::execute, + "Should fail to delete a file treated as a directory" ); } /** @@ -187,16 +166,10 @@ public void testCleanInvalidDirectory() * * @throws Exception in case of an error. */ - public void testMissingDirectory() - throws Exception + @Test + @InjectMojo( goal = "clean", pom = "classpath:/unit/missing-directory-test/plugin-pom.xml" ) + public void testMissingDirectory( CleanMojo mojo ) { - String pluginPom = getBasedir() + "/src/test/resources/unit/missing-directory-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/missing-directory-test" ), - new File( getBasedir(), "target/test-classes/unit/missing-directory-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); mojo.execute(); @@ -212,22 +185,12 @@ public void testMissingDirectory() * * @throws Exception in case of an error. */ - public void testCleanLockedFile() - throws Exception + @Test + @EnabledOnOs( OS.WINDOWS ) + @InjectMojo( goal = "clean", pom = "classpath:/unit/locked-file-test/plugin-pom.xml" ) + public void testCleanLockedFile( CleanMojo mojo ) + throws Exception { - if (!System.getProperty("os.name").toLowerCase().contains("windows")) - { - assertTrue( "Ignored this test on none Windows based systems", true ); - return; - } - - String pluginPom = getBasedir() + "/src/test/resources/unit/locked-file-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/locked-file-test" ), - new File( getBasedir(), "target/test-classes/unit/locked-file-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); assertNotNull( mojo ); File f = new File( getBasedir(), "target/test-classes/unit/locked-file-test/buildDirectory/file.txt" ); @@ -237,7 +200,7 @@ public void testCleanLockedFile() mojo.execute(); fail( "Should fail to delete a file that is locked" ); } - catch ( MojoExecutionException expected ) + catch ( MojoException expected ) { assertTrue( true ); } @@ -251,22 +214,12 @@ public void testCleanLockedFile() * * @throws Exception in case of an error. */ - public void testCleanLockedFileWithNoError() - throws Exception + @Test + @EnabledOnOs( OS.WINDOWS ) + @InjectMojo( goal = "clean", pom = "classpath:/unit/locked-file-test/plugin-pom.xml" ) + public void testCleanLockedFileWithNoError( CleanMojo mojo ) + throws Exception { - if (!System.getProperty("os.name").toLowerCase().contains("windows")) - { - assertTrue( "Ignored this test on none Windows based systems", true ); - return; - } - - String pluginPom = getBasedir() + "/src/test/resources/unit/locked-file-test/plugin-pom.xml"; - - // safety - copyDirectory( new File( getBasedir(), "src/test/resources/unit/locked-file-test" ), - new File( getBasedir(), "target/test-classes/unit/locked-file-test" ) ); - - CleanMojo mojo = (CleanMojo) lookupMojo( "clean", pluginPom ); setVariableValueToObject( mojo, "failOnError", Boolean.FALSE ); assertNotNull( mojo ); @@ -277,12 +230,23 @@ public void testCleanLockedFileWithNoError() mojo.execute(); assertTrue( true ); } - catch ( MojoExecutionException expected ) + catch ( MojoException expected ) { fail( "Should display a warning when deleting a file that is locked" ); } } + @Provides + @Singleton + @SuppressWarnings( "unused" ) + private Session createSession() + { + Session session = SessionStub.getMockSession( LOCAL_REPO ); + Properties props = new Properties(); + doReturn( props ).when( session ).getSystemProperties(); + return session; + } + /** * @param dir a dir or a file * @return true if a file/dir exists, false otherwise