diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml
index ce4b500..56062b5 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -26,4 +26,6 @@ jobs:
name: Verify
uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v4
with:
- maven4-enabled: true
+ ff-maven: "4.0.0-beta-3" # Maven version for fail-fast-build
+ maven-matrix: '[ "4.0.0-beta-3" ]'
+ jdk-matrix: '[ "17", "21" ]'
diff --git a/pom.xml b/pom.xml
index 73c3c72..a7ef0bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@ under the License.
maven-clean-plugin
- 3.4.1-SNAPSHOT
+ 4.0.0-SNAPSHOT
maven-plugin
Apache Maven Clean Plugin
@@ -61,46 +61,44 @@ under the License.
- 3.6.3
+ 4.0.0-beta-3
+ 17
+ 3.7.0
+ 4.0.0-alpha-3-SNAPSHOT
+ 4.0.0-SNAPSHOT
2024-06-16T10:25:11Z
org.apache.maven
- maven-plugin-api
+ maven-api-core
${mavenVersion}
provided
org.apache.maven
- maven-core
+ maven-api-di
${mavenVersion}
provided
- org.apache.maven.resolver
- maven-resolver-api
- 1.1.1
+ org.apache.maven
+ maven-api-meta
+ ${mavenVersion}
provided
+
org.codehaus.plexus
plexus-utils
-
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- provided
-
-
org.apache.maven.plugin-testing
maven-plugin-testing-harness
- 4.0.0-alpha-2
+ ${version.maven-plugin-testing}
test
@@ -109,18 +107,42 @@ under the License.
test
- org.codehaus.plexus
- plexus-testing
- 1.3.0
+ org.apache.maven
+ maven-core
+ ${mavenVersion}
test
- org.codehaus.plexus
- plexus-xml
+ com.google.inject
+ guice
+ 6.0.0
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ 2.0.13
test
+
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+ ${version.maven-plugin-tools}
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
run-its
diff --git a/src/it/settings.xml b/src/it/settings.xml
index c8f77f0..5617e4e 100644
--- a/src/it/settings.xml
+++ b/src/it/settings.xml
@@ -32,9 +32,11 @@ under the License.
@localRepositoryUrl@
true
+ ignore
true
+ ignore
@@ -44,9 +46,11 @@ under the License.
@localRepositoryUrl@
true
+ ignore
true
+ ignore
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 4f77c00..44ceb48 100644
--- a/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java
+++ b/src/main/java/org/apache/maven/plugins/clean/CleanMojo.java
@@ -18,14 +18,16 @@
*/
package org.apache.maven.plugins.clean;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
-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.di.Inject;
+import org.apache.maven.api.plugin.Log;
+import org.apache.maven.api.plugin.MojoException;
+import org.apache.maven.api.plugin.annotations.Mojo;
+import org.apache.maven.api.plugin.annotations.Parameter;
/**
* Goal which cleans the build.
@@ -43,8 +45,8 @@
* @see org.apache.maven.plugins.clean.Fileset
* @since 2.0
*/
-@Mojo(name = "clean", threadSafe = true)
-public class CleanMojo extends AbstractMojo {
+@Mojo(name = "clean")
+public class CleanMojo implements org.apache.maven.api.plugin.Mojo {
public static final String FAST_MODE_BACKGROUND = "background";
@@ -52,23 +54,26 @@ public class CleanMojo extends AbstractMojo {
public static final String FAST_MODE_DEFER = "defer";
+ @Inject
+ private Log logger;
+
/**
* This is where build results go.
*/
@Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
- private File directory;
+ private Path directory;
/**
* This is where compiled classes go.
*/
@Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true, required = true)
- private File outputDirectory;
+ private Path outputDirectory;
/**
* This is where compiled test classes go.
*/
@Parameter(defaultValue = "${project.build.testOutputDirectory}", readonly = true, required = true)
- private File testOutputDirectory;
+ private Path testOutputDirectory;
/**
* This is where the site plugin generates its pages.
@@ -76,7 +81,7 @@ public class CleanMojo extends AbstractMojo {
* @since 2.1.1
*/
@Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true, required = true)
- private File reportDirectory;
+ private Path reportDirectory;
/**
* Sets whether the plugin runs in verbose mode. As of plugin version 2.3, the default value is derived from Maven's
@@ -186,11 +191,11 @@ public class CleanMojo extends AbstractMojo {
* should usually reside on the same volume. The exact conditions are system dependant though, but if an atomic
* move is not supported, the standard deletion mechanism will be used.
*
- * @see #fast
* @since 3.2
+ * @see #fast
*/
@Parameter(property = "maven.clean.fastDir")
- private File fastDir;
+ private Path fastDir;
/**
* Mode to use when using fast clean. Values are: background
to start deletion immediately and
@@ -199,35 +204,35 @@ public class CleanMojo extends AbstractMojo {
* the actual file deletion should be started in the background when the session ends (this should only be used
* when maven is embedded in a long running process).
*
- * @see #fast
* @since 3.2
+ * @see #fast
*/
@Parameter(property = "maven.clean.fastMode", defaultValue = FAST_MODE_BACKGROUND)
private String fastMode;
- @Parameter(defaultValue = "${session}", readonly = true)
- private MavenSession session;
+ @Inject
+ 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 {
+ public void execute() {
if (skip) {
getLog().info("Clean is skipped.");
return;
}
String multiModuleProjectDirectory =
- session != null ? session.getSystemProperties().getProperty("maven.multiModuleProjectDirectory") : null;
- File fastDir;
+ session != null ? session.getSystemProperties().get("maven.multiModuleProjectDirectory") : null;
+ Path fastDir;
if (fast && this.fastDir != null) {
fastDir = this.fastDir;
} else if (fast && multiModuleProjectDirectory != null) {
- fastDir = new File(multiModuleProjectDirectory, "target/.clean");
+ fastDir = Paths.get(multiModuleProjectDirectory, "target/.clean");
} else {
fastDir = null;
if (fast) {
@@ -247,7 +252,7 @@ public void execute() throws MojoExecutionException {
Cleaner cleaner = new Cleaner(session, getLog(), isVerbose(), fastDir, fastMode);
try {
- for (File directoryItem : getDirectories()) {
+ for (Path directoryItem : getDirectories()) {
if (directoryItem != null) {
cleaner.delete(directoryItem, null, followSymLinks, failOnError, retryOnError);
}
@@ -256,7 +261,7 @@ public void execute() throws MojoExecutionException {
if (filesets != null) {
for (Fileset fileset : filesets) {
if (fileset.getDirectory() == null) {
- throw new MojoExecutionException("Missing base directory for " + fileset);
+ throw new MojoException("Missing base directory for " + fileset);
}
final String[] includes = fileset.getIncludes();
final String[] excludes = fileset.getExcludes();
@@ -273,8 +278,9 @@ public void execute() throws MojoExecutionException {
fileset.getDirectory(), selector, fileset.isFollowSymlinks(), failOnError, retryOnError);
}
}
+
} catch (IOException e) {
- throw new MojoExecutionException("Failed to clean project: " + e.getMessage(), e);
+ throw new MojoException("Failed to clean project: " + e.getMessage(), e);
}
}
@@ -292,13 +298,17 @@ private boolean isVerbose() {
*
* @return The directories to clean or an empty array if none, never null
.
*/
- private File[] getDirectories() {
- File[] directories;
+ private Path[] getDirectories() {
+ Path[] directories;
if (excludeDefaultDirectories) {
- directories = new File[0];
+ directories = new Path[0];
} else {
- directories = new File[] {directory, outputDirectory, testOutputDirectory, reportDirectory};
+ directories = new Path[] {directory, outputDirectory, testOutputDirectory, reportDirectory};
}
return directories;
}
+
+ private Log getLog() {
+ return logger;
+ }
}
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 f5c25d2..533a224 100644
--- a/src/main/java/org/apache/maven/plugins/clean/Cleaner.java
+++ b/src/main/java/org/apache/maven/plugins/clean/Cleaner.java
@@ -20,9 +20,6 @@
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.LinkOption;
import java.nio.file.Path;
@@ -30,12 +27,17 @@
import java.nio.file.attribute.BasicFileAttributes;
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 java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+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.apache.maven.api.plugin.Log;
import org.codehaus.plexus.util.Os;
-import org.eclipse.aether.SessionData;
import static org.apache.maven.plugins.clean.CleanMojo.FAST_MODE_BACKGROUND;
import static org.apache.maven.plugins.clean.CleanMojo.FAST_MODE_DEFER;
@@ -49,70 +51,93 @@ class Cleaner {
private static final boolean ON_WINDOWS = Os.isFamily(Os.FAMILY_WINDOWS);
- private static final String LAST_DIRECTORY_TO_DELETE = Cleaner.class.getName() + ".lastDirectoryToDelete";
+ private static final SessionData.Key LAST_DIRECTORY_TO_DELETE =
+ SessionData.key(Path.class, Cleaner.class.getName() + ".lastDirectoryToDelete");
/**
* 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 File fastDir;
+ private final Logger logDebug;
- private final String fastMode;
+ private final Logger logInfo;
+
+ private final Logger logVerbose;
- private final boolean verbose;
+ private final Logger logWarn;
- private Log log;
+ private final Path fastDir;
+
+ private final String fastMode;
/**
* Creates a new cleaner.
*
* @param session The Maven session to be used.
- * @param log The logger to use.
+ * @param log The logger to use, may be null
to disable logging.
* @param verbose Whether to perform verbose logging.
* @param fastDir The explicit configured directory or to be deleted in fast mode.
* @param fastMode The fast deletion mode.
*/
- Cleaner(MavenSession session, final Log log, boolean verbose, File fastDir, String fastMode) {
+ Cleaner(Session session, Log log, boolean verbose, Path fastDir, String fastMode) {
+ logDebug = (log == null || !log.isDebugEnabled()) ? null : logger(log::debug, log::debug);
+
+ logInfo = (log == null || !log.isInfoEnabled()) ? null : logger(log::info, log::info);
+
+ logWarn = (log == null || !log.isWarnEnabled()) ? null : logger(log::warn, log::warn);
+
+ logVerbose = verbose ? logInfo : logDebug;
+
this.session = session;
- // This can't be null as the Cleaner gets it from the CleanMojo which gets it from AbstractMojo class, where it
- // is never null.
- this.log = log;
this.fastDir = fastDir;
this.fastMode = fastMode;
- this.verbose = verbose;
+ }
+
+ private Logger logger(Consumer l1, BiConsumer l2) {
+ return new Logger() {
+ @Override
+ public void log(CharSequence message) {
+ l1.accept(message);
+ }
+
+ @Override
+ public void log(CharSequence message, Throwable t) {
+ l2.accept(message, t);
+ }
+ };
}
/**
* Deletes the specified directories and its contents.
*
- * @param basedir The directory to delete, must not be null
. Non-existing directories will be silently
- * ignored.
- * @param selector The selector used to determine what contents to delete, may be null
to delete
- * everything.
+ * @param basedir The directory to delete, must not be null
. Non-existing directories will be silently
+ * ignored.
+ * @param selector The selector used to determine what contents to delete, may be null
to delete
+ * everything.
* @param followSymlinks Whether to follow symlinks.
- * @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
- * @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
+ * @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
+ * @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @throws IOException If a file/directory could not be deleted and failOnError
is true
.
*/
public void delete(
- File basedir, Selector selector, boolean followSymlinks, boolean failOnError, boolean retryOnError)
+ Path basedir, Selector selector, boolean followSymlinks, boolean failOnError, boolean retryOnError)
throws IOException {
- if (!basedir.isDirectory()) {
- if (!basedir.exists()) {
- if (log.isDebugEnabled()) {
- log.debug("Skipping non-existing directory " + basedir);
+ if (!Files.isDirectory(basedir)) {
+ if (!Files.exists(basedir)) {
+ if (logDebug != null) {
+ logDebug.log("Skipping non-existing directory " + basedir);
}
return;
}
throw new IOException("Invalid base directory " + basedir);
}
- if (log.isInfoEnabled()) {
- log.info("Deleting " + basedir + (selector != null ? " (" + selector + ")" : ""));
+ if (logInfo != null) {
+ logInfo.log("Deleting " + basedir + (selector != null ? " (" + selector + ")" : ""));
}
- File file = followSymlinks ? basedir : basedir.getCanonicalFile();
+ Path file = followSymlinks ? basedir : getCanonicalPath(basedir);
if (selector == null && !followSymlinks && fastDir != null && session != null) {
// If anything wrong happens, we'll just use the usual deletion mechanism
@@ -124,9 +149,8 @@ public void delete(
delete(file, "", selector, followSymlinks, failOnError, retryOnError);
}
- private boolean fastDelete(File baseDirFile) {
- Path baseDir = baseDirFile.toPath();
- Path fastDir = this.fastDir.toPath();
+ private boolean fastDelete(Path baseDir) {
+ Path fastDir = this.fastDir;
// Handle the case where we use ${maven.multiModuleProjectDirectory}/target/.clean for example
if (fastDir.toAbsolutePath().startsWith(baseDir.toAbsolutePath())) {
try {
@@ -135,7 +159,7 @@ private boolean fastDelete(File baseDirFile) {
try {
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);
}
baseDir = tmpDir;
} catch (IOException e) {
@@ -143,8 +167,8 @@ private boolean fastDelete(File baseDirFile) {
throw e;
}
} catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to fast delete directory: ", e);
+ if (logDebug != null) {
+ logDebug.log("Unable to fast delete directory", e);
}
return false;
}
@@ -155,10 +179,10 @@ private boolean fastDelete(File baseDirFile) {
Files.createDirectories(fastDir);
}
} catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug(
+ if (logDebug != null) {
+ logDebug.log(
"Unable to fast delete directory as the path " + fastDir
- + " does not point to a directory or cannot be created: ",
+ + " does not point to a directory or cannot be created",
e);
}
return false;
@@ -172,11 +196,11 @@ private boolean fastDelete(File baseDirFile) {
// or any other exception occurs, an exception will be thrown in which case
// the method will return false and the usual deletion will be performed.
Files.move(baseDir, dstDir, StandardCopyOption.ATOMIC_MOVE);
- BackgroundCleaner.delete(this, tmpDir.toFile(), fastMode);
+ BackgroundCleaner.delete(this, tmpDir, fastMode);
return true;
} catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to fast delete directory: ", e);
+ if (logDebug != null) {
+ logDebug.log("Unable to fast delete directory", e);
}
return false;
}
@@ -185,20 +209,20 @@ private boolean fastDelete(File baseDirFile) {
/**
* Deletes the specified file or directory.
*
- * @param file The file/directory to delete, must not be null
. If followSymlinks
is
- * false
, it is assumed that the parent file is canonical.
- * @param pathname The relative pathname of the file, using {@link File#separatorChar}, must not be
- * null
.
- * @param selector The selector used to determine what contents to delete, may be null
to delete
- * everything.
+ * @param file The file/directory to delete, must not be null
. If followSymlinks
is
+ * false
, it is assumed that the parent file is canonical.
+ * @param pathname The relative pathname of the file, using {@link File#separatorChar}, must not be
+ * null
.
+ * @param selector The selector used to determine what contents to delete, may be null
to delete
+ * everything.
* @param followSymlinks Whether to follow symlinks.
- * @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
- * @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
+ * @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
+ * @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @return The result of the cleaning, never null
.
* @throws IOException If a file/directory could not be deleted and failOnError
is true
.
*/
private Result delete(
- File file,
+ Path file,
String pathname,
Selector selector,
boolean followSymlinks,
@@ -207,46 +231,43 @@ private Result delete(
throws IOException {
Result result = new Result();
- boolean isDirectory = file.isDirectory();
+ boolean isDirectory = Files.isDirectory(file);
if (isDirectory) {
if (selector == null || selector.couldHoldSelected(pathname)) {
- if (followSymlinks || !isSymbolicLink(file.toPath())) {
- File canonical = followSymlinks ? file : file.getCanonicalFile();
- String[] filenames = canonical.list();
- if (filenames != null) {
- String prefix = pathname.length() > 0 ? pathname + File.separatorChar : "";
- for (int i = filenames.length - 1; i >= 0; i--) {
- String filename = filenames[i];
- File child = new File(canonical, filename);
+ final boolean isSymlink = isSymbolicLink(file);
+ Path canonical = followSymlinks ? file : getCanonicalPath(file);
+ if (followSymlinks || !isSymlink) {
+ String prefix = !pathname.isEmpty() ? pathname + File.separatorChar : "";
+ try (Stream children = Files.list(canonical)) {
+ for (Path child : children.toList()) {
result.update(delete(
- child, prefix + filename, selector, followSymlinks, failOnError, retryOnError));
+ child,
+ prefix + child.getFileName(),
+ selector,
+ followSymlinks,
+ failOnError,
+ retryOnError));
}
}
- } else if (log.isDebugEnabled()) {
- log.debug("Not recursing into symlink " + file);
+ } else if (logDebug != null) {
+ logDebug.log("Not recursing into symlink " + file);
}
- } else if (log.isDebugEnabled()) {
- log.debug("Not recursing into directory without included files " + file);
+ } else if (logDebug != null) {
+ logDebug.log("Not recursing into directory without included files " + file);
}
}
if (!result.excluded && (selector == null || selector.isSelected(pathname))) {
- String logmessage;
- if (isDirectory) {
- logmessage = "Deleting directory " + file;
- } else if (file.exists()) {
- logmessage = "Deleting file " + file;
- } else {
- logmessage = "Deleting dangling symlink " + file;
- }
-
- if (verbose && log.isInfoEnabled()) {
- log.info(logmessage);
- } else if (log.isDebugEnabled()) {
- log.debug(logmessage);
+ if (logVerbose != null) {
+ if (isDirectory) {
+ logVerbose.log("Deleting directory " + file);
+ } else if (Files.exists(file)) {
+ logVerbose.log("Deleting file " + file);
+ } else {
+ logVerbose.log("Deleting dangling symlink " + file);
+ }
}
-
result.failures += delete(file, failOnError, retryOnError);
} else {
result.excluded = true;
@@ -255,6 +276,14 @@ private Result delete(
return result;
}
+ private static Path getCanonicalPath(Path path) {
+ try {
+ return path.toRealPath();
+ } catch (IOException e) {
+ return getCanonicalPath(path.getParent()).resolve(path.getFileName());
+ }
+ }
+
private boolean isSymbolicLink(Path path) throws IOException {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
return attrs.isSymbolicLink()
@@ -262,19 +291,13 @@ private boolean isSymbolicLink(Path path) throws IOException {
|| (attrs.isDirectory() && attrs.isOther());
}
- /**
- * Deletes the specified file, directory. If the path denotes a symlink, only the link is removed, its target is
- * left untouched.
- *
- * @param file The file/directory to delete, must not be null
.
- * @param failOnError Whether to abort with an exception in case the file/directory could not be deleted.
- * @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
- * @return 0
if the file was deleted, 1
otherwise.
- * @throws IOException If a file/directory could not be deleted and failOnError
is true
.
- */
- private int delete(File file, boolean failOnError, boolean retryOnError) throws IOException {
- if (!file.delete()) {
- boolean deleted = false;
+ private int delete(Path file, boolean failOnError, boolean retryOnError) throws IOException {
+ try {
+ Files.deleteIfExists(file);
+ return 0;
+ } catch (IOException e) {
+ IOException exception = new IOException("Failed to delete " + file);
+ exception.addSuppressed(e);
if (retryOnError) {
if (ON_WINDOWS) {
@@ -283,24 +306,27 @@ private int delete(File file, boolean failOnError, boolean retryOnError) throws
}
final int[] delays = {50, 250, 750};
- for (int i = 0; !deleted && i < delays.length; i++) {
+ for (int delay : delays) {
try {
- Thread.sleep(delays[i]);
- } catch (InterruptedException e) {
- // ignore
+ Thread.sleep(delay);
+ } catch (InterruptedException e2) {
+ exception.addSuppressed(e2);
+ }
+ try {
+ Files.deleteIfExists(file);
+ return 0;
+ } catch (IOException e2) {
+ exception.addSuppressed(e2);
}
- deleted = file.delete() || !file.exists();
}
- } else {
- deleted = !file.exists();
}
- if (!deleted) {
+ if (Files.exists(file)) {
if (failOnError) {
- throw new IOException("Failed to delete " + file);
+ throw new IOException("Failed to delete " + file, exception);
} else {
- if (log.isWarnEnabled()) {
- log.warn("Failed to delete " + file);
+ if (logWarn != null) {
+ logWarn.log("Failed to delete " + file, exception);
}
return 1;
}
@@ -322,25 +348,30 @@ public void update(Result result) {
}
}
+ private interface Logger {
+
+ void log(CharSequence message);
+
+ void log(CharSequence message, Throwable t);
+ }
+
private static class BackgroundCleaner extends Thread {
- private static final int NEW = 0;
- private static final int RUNNING = 1;
- private static final int STOPPED = 2;
private static BackgroundCleaner instance;
- private final Deque filesToDelete = new ArrayDeque<>();
+
+ private final Deque filesToDelete = new ArrayDeque<>();
+
private final Cleaner cleaner;
+
private final String fastMode;
- private int status = NEW;
- private BackgroundCleaner(Cleaner cleaner, File dir, String fastMode) {
- super("mvn-background-cleaner");
- this.cleaner = cleaner;
- this.fastMode = fastMode;
- init(cleaner.fastDir, dir);
- }
+ private static final int NEW = 0;
+ private static final int RUNNING = 1;
+ private static final int STOPPED = 2;
- public static void delete(Cleaner cleaner, File dir, String fastMode) {
+ private int status = NEW;
+
+ public static void delete(Cleaner cleaner, Path dir, String fastMode) {
synchronized (BackgroundCleaner.class) {
if (instance == null || !instance.doDelete(dir)) {
instance = new BackgroundCleaner(cleaner, dir, fastMode);
@@ -356,9 +387,16 @@ static void sessionEnd() {
}
}
+ private BackgroundCleaner(Cleaner cleaner, Path dir, String fastMode) {
+ super("mvn-background-cleaner");
+ this.cleaner = cleaner;
+ this.fastMode = fastMode;
+ init(cleaner.fastDir, dir);
+ }
+
public void run() {
while (true) {
- File basedir = pollNext();
+ Path basedir = pollNext();
if (basedir == null) {
break;
}
@@ -370,24 +408,25 @@ public void run() {
}
}
- synchronized void init(File fastDir, File dir) {
- if (fastDir.isDirectory()) {
- File[] children = fastDir.listFiles();
- if (children != null && children.length > 0) {
- for (File child : children) {
- doDelete(child);
+ synchronized void init(Path fastDir, Path dir) {
+ if (Files.isDirectory(fastDir)) {
+ try {
+ try (Stream children = Files.list(fastDir)) {
+ children.forEach(this::doDelete);
}
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
doDelete(dir);
}
- synchronized File pollNext() {
- File basedir = filesToDelete.poll();
+ synchronized Path pollNext() {
+ Path basedir = filesToDelete.poll();
if (basedir == null) {
if (cleaner.session != null) {
- SessionData data = cleaner.session.getRepositorySession().getData();
- File lastDir = (File) data.get(LAST_DIRECTORY_TO_DELETE);
+ SessionData data = cleaner.session.getData();
+ Path lastDir = (Path) data.get(LAST_DIRECTORY_TO_DELETE);
if (lastDir != null) {
data.set(LAST_DIRECTORY_TO_DELETE, null);
return lastDir;
@@ -399,7 +438,7 @@ synchronized File pollNext() {
return basedir;
}
- synchronized boolean doDelete(File dir) {
+ synchronized boolean doDelete(Path dir) {
if (status == STOPPED) {
return false;
}
@@ -421,15 +460,10 @@ synchronized boolean doDelete(File dir) {
* to outlive its main execution.
*/
private void wrapExecutionListener() {
- ExecutionListener executionListener = cleaner.session.getRequest().getExecutionListener();
- if (executionListener == null
- || !Proxy.isProxyClass(executionListener.getClass())
- || !(Proxy.getInvocationHandler(executionListener) instanceof SpyInvocationHandler)) {
- ExecutionListener listener = (ExecutionListener) Proxy.newProxyInstance(
- ExecutionListener.class.getClassLoader(),
- new Class[] {ExecutionListener.class},
- new SpyInvocationHandler(executionListener));
- cleaner.session.getRequest().setExecutionListener(listener);
+ synchronized (CleanerListener.class) {
+ if (cleaner.session.getListeners().stream().noneMatch(l -> l instanceof CleanerListener)) {
+ cleaner.session.registerListener(new CleanerListener());
+ }
}
}
@@ -440,8 +474,8 @@ synchronized void doSessionEnd() {
}
if (!FAST_MODE_DEFER.equals(fastMode)) {
try {
- if (cleaner.log.isInfoEnabled()) {
- cleaner.log.info("Waiting for background file deletion");
+ if (cleaner.logInfo != null) {
+ cleaner.logInfo.log("Waiting for background file deletion");
}
while (status != STOPPED) {
wait();
@@ -454,22 +488,12 @@ synchronized void doSessionEnd() {
}
}
- static class SpyInvocationHandler implements InvocationHandler {
- private final ExecutionListener delegate;
-
- SpyInvocationHandler(ExecutionListener delegate) {
- this.delegate = delegate;
- }
-
+ static class CleanerListener implements Listener {
@Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if ("sessionEnded".equals(method.getName())) {
+ public void onEvent(Event event) {
+ if (event.getType() == EventType.SESSION_ENDED) {
BackgroundCleaner.sessionEnd();
}
- if (delegate != null) {
- return method.invoke(delegate, args);
- }
- return null;
}
}
}
diff --git a/src/main/java/org/apache/maven/plugins/clean/Fileset.java b/src/main/java/org/apache/maven/plugins/clean/Fileset.java
index ecd88b0..7508411 100644
--- a/src/main/java/org/apache/maven/plugins/clean/Fileset.java
+++ b/src/main/java/org/apache/maven/plugins/clean/Fileset.java
@@ -18,7 +18,7 @@
*/
package org.apache.maven.plugins.clean;
-import java.io.File;
+import java.nio.file.Path;
import java.util.Arrays;
/**
@@ -32,7 +32,7 @@
*/
public class Fileset {
- private File directory;
+ private Path directory;
private String[] includes;
@@ -45,7 +45,7 @@ public class Fileset {
/**
* @return {@link #directory}
*/
- public File getDirectory() {
+ public Path getDirectory() {
return directory;
}
diff --git a/src/site/apt/examples/delete_additional_files.apt.vm b/src/site/apt/examples/delete_additional_files.apt.vm
index 0fa768c..84ed079 100644
--- a/src/site/apt/examples/delete_additional_files.apt.vm
+++ b/src/site/apt/examples/delete_additional_files.apt.vm
@@ -68,7 +68,7 @@ Delete Additional Files Not Exposed to Maven
is equivalent to:
+--------
- ${project.basedir}/some/relative/path
+ ${basedir}/some/relative/path
+--------
You could also define file set rules in a parent POM. In this case, the clean plugin adds the subproject
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 22287d7..5a5d0d4 100644
--- a/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java
@@ -29,17 +29,17 @@
import java.nio.file.Paths;
import java.util.Collections;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.logging.SystemStreamLog;
-import org.apache.maven.plugin.testing.junit5.InjectMojo;
-import org.apache.maven.plugin.testing.junit5.MojoTest;
+import org.apache.maven.api.plugin.MojoException;
+import org.apache.maven.api.plugin.testing.Basedir;
+import org.apache.maven.api.plugin.testing.InjectMojo;
+import org.apache.maven.api.plugin.testing.MojoTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
-import static org.apache.maven.plugin.testing.junit5.MojoExtension.setVariableValueToObject;
-import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
+import static org.apache.maven.api.plugin.testing.MojoExtension.getBasedir;
+import static org.apache.maven.api.plugin.testing.MojoExtension.setVariableValueToObject;
import static org.codehaus.plexus.util.IOUtil.copy;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -49,30 +49,25 @@
/**
* Test the clean mojo.
- *
- * @author Vincent Siveton
*/
@MojoTest
-class CleanMojoTest {
+public class CleanMojoTest {
+ private static final String LOCAL_REPO = "target/local-repo/";
+
/**
* Tests the simple removal of directories
*
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/basic-clean-test/plugin-pom.xml")
- void testBasicClean(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/basic-clean-test")
+ @InjectMojo(goal = "clean")
+ public void testBasicClean(CleanMojo mojo) throws Exception {
mojo.execute();
- 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");
+ assertFalse(checkExists(getBasedir() + "/buildDirectory"), "Directory exists");
+ assertFalse(checkExists(getBasedir() + "/buildOutputDirectory"), "Directory exists");
+ assertFalse(checkExists(getBasedir() + "/buildTestDirectory"), "Directory exists");
}
/**
@@ -81,13 +76,14 @@ void testBasicClean(CleanMojo mojo) throws Exception {
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/nested-clean-test/plugin-pom.xml")
- void testCleanNestedStructure(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/nested-clean-test")
+ @InjectMojo(goal = "clean")
+ public void testCleanNestedStructure(CleanMojo mojo) throws Exception {
mojo.execute();
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/nested-clean-test/target"));
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/nested-clean-test/target/classes"));
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/nested-clean-test/target/test-classes"));
+ assertFalse(checkExists(getBasedir() + "/target"));
+ assertFalse(checkExists(getBasedir() + "/target/classes"));
+ assertFalse(checkExists(getBasedir() + "/target/test-classes"));
}
/**
@@ -97,17 +93,15 @@ void testCleanNestedStructure(CleanMojo mojo) throws Exception {
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/empty-clean-test/plugin-pom.xml")
- void testCleanEmptyDirectories(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/empty-clean-test")
+ @InjectMojo(goal = "clean")
+ public void testCleanEmptyDirectories(CleanMojo mojo) throws Exception {
mojo.execute();
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/empty-clean-test/testDirectoryStructure"));
- assertTrue(checkExists(
- getBasedir() + "/target/test-classes/unit/empty-clean-test/" + "testDirectoryStructure/file.txt"));
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/empty-clean-test/"
- + "testDirectoryStructure/outputDirectory"));
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/empty-clean-test/"
- + "testDirectoryStructure/outputDirectory/file.txt"));
+ assertTrue(checkExists(getBasedir() + "/testDirectoryStructure"));
+ assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/file.txt"));
+ assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/outputDirectory"));
+ assertTrue(checkExists(getBasedir() + "/testDirectoryStructure/outputDirectory/file.txt"));
}
/**
@@ -116,25 +110,24 @@ void testCleanEmptyDirectories(CleanMojo mojo) throws Exception {
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/fileset-clean-test/plugin-pom.xml")
- void testFilesetsClean(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/fileset-clean-test")
+ @InjectMojo(goal = "clean")
+ public void testFilesetsClean(CleanMojo mojo) throws Exception {
mojo.execute();
// fileset 1
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target"));
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/classes"));
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/test-classes"));
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/subdir"));
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/classes/file.txt"));
- assertTrue(checkEmpty(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/classes"));
- assertFalse(checkEmpty(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/subdir"));
- assertTrue(checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/target/subdir/file.txt"));
+ assertTrue(checkExists(getBasedir() + "/target"));
+ assertTrue(checkExists(getBasedir() + "/target/classes"));
+ assertFalse(checkExists(getBasedir() + "/target/test-classes"));
+ assertTrue(checkExists(getBasedir() + "/target/subdir"));
+ assertFalse(checkExists(getBasedir() + "/target/classes/file.txt"));
+ assertTrue(checkEmpty(getBasedir() + "/target/classes"));
+ assertFalse(checkEmpty(getBasedir() + "/target/subdir"));
+ assertTrue(checkExists(getBasedir() + "/target/subdir/file.txt"));
// fileset 2
- assertTrue(
- checkExists(getBasedir() + "/target/test-classes/unit/fileset-clean-test/" + "buildOutputDirectory"));
- assertFalse(checkExists(
- getBasedir() + "/target/test-classes/unit/fileset-clean-test/" + "buildOutputDirectory/file.txt"));
+ assertTrue(checkExists(getBasedir() + "/" + "buildOutputDirectory"));
+ assertFalse(checkExists(getBasedir() + "/" + "buildOutputDirectory/file.txt"));
}
/**
@@ -143,9 +136,10 @@ void testFilesetsClean(CleanMojo mojo) throws Exception {
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/invalid-directory-test/plugin-pom.xml")
- void testCleanInvalidDirectory(CleanMojo mojo) throws Exception {
- assertThrows(MojoExecutionException.class, mojo::execute);
+ @Basedir("${basedir}/target/test-classes/unit/invalid-directory-test")
+ @InjectMojo(goal = "clean")
+ public void testCleanInvalidDirectory(CleanMojo mojo) throws Exception {
+ assertThrows(MojoException.class, mojo::execute, "Should fail to delete a file treated as a directory");
}
/**
@@ -154,11 +148,12 @@ void testCleanInvalidDirectory(CleanMojo mojo) throws Exception {
* @throws Exception in case of an error.
*/
@Test
- @InjectMojo(goal = "clean", pom = "classpath:/unit/missing-directory-test/plugin-pom.xml")
- void testMissingDirectory(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/missing-directory-test")
+ @InjectMojo(goal = "clean")
+ public void testMissingDirectory(CleanMojo mojo) throws Exception {
mojo.execute();
- assertFalse(checkExists(getBasedir() + "/target/test-classes/unit/missing-directory-test/does-not-exist"));
+ assertFalse(checkExists(getBasedir() + "/does-not-exist"));
}
/**
@@ -171,14 +166,15 @@ void testMissingDirectory(CleanMojo mojo) throws Exception {
*/
@Test
@EnabledOnOs(OS.WINDOWS)
- @InjectMojo(goal = "clean", pom = "classpath:/unit/locked-file-test/plugin-pom.xml")
- void testCleanLockedFile(CleanMojo mojo) throws Exception {
- File f = new File(getBasedir(), "target/test-classes/unit/locked-file-test/buildDirectory/file.txt");
+ @Basedir("${basedir}/target/test-classes/unit/locked-file-test")
+ @InjectMojo(goal = "clean")
+ public void testCleanLockedFile(CleanMojo mojo) throws Exception {
+ File f = new File(getBasedir(), "buildDirectory/file.txt");
try (FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
FileLock ignored = channel.lock()) {
mojo.execute();
fail("Should fail to delete a file that is locked");
- } catch (MojoExecutionException expected) {
+ } catch (MojoException expected) {
assertTrue(true);
}
}
@@ -193,29 +189,29 @@ void testCleanLockedFile(CleanMojo mojo) throws Exception {
*/
@Test
@EnabledOnOs(OS.WINDOWS)
- @InjectMojo(goal = "clean", pom = "classpath:/unit/locked-file-test/plugin-pom.xml")
- void testCleanLockedFileWithNoError(CleanMojo mojo) throws Exception {
+ @Basedir("${basedir}/target/test-classes/unit/locked-file-test")
+ @InjectMojo(goal = "clean")
+ public void testCleanLockedFileWithNoError(CleanMojo mojo) throws Exception {
setVariableValueToObject(mojo, "failOnError", Boolean.FALSE);
assertNotNull(mojo);
- File f = new File(getBasedir(), "target/test-classes/unit/locked-file-test/buildDirectory/file.txt");
+ File f = new File(getBasedir(), "buildDirectory/file.txt");
try (FileChannel channel = new RandomAccessFile(f, "rw").getChannel();
FileLock ignored = channel.lock()) {
mojo.execute();
assertTrue(true);
- } catch (MojoExecutionException expected) {
+ } catch (MojoException expected) {
fail("Should display a warning when deleting a file that is locked");
}
}
/**
* Test the followLink option with windows junctions
- *
* @throws Exception
*/
@Test
@EnabledOnOs(OS.WINDOWS)
- void testFollowLinksWithWindowsJunction() throws Exception {
+ public void testFollowLinksWithWindowsJunction() throws Exception {
testSymlink((link, target) -> {
Process process = new ProcessBuilder()
.directory(link.getParent().toFile())
@@ -233,12 +229,11 @@ void testFollowLinksWithWindowsJunction() throws Exception {
/**
* Test the followLink option with sym link
- *
* @throws Exception
*/
@Test
@DisabledOnOs(OS.WINDOWS)
- void testFollowLinksWithSymLinkOnPosix() throws Exception {
+ public void testFollowLinksWithSymLinkOnPosix() throws Exception {
testSymlink((link, target) -> {
try {
Files.createSymbolicLink(link, target);
@@ -248,9 +243,13 @@ void testFollowLinksWithSymLinkOnPosix() throws Exception {
});
}
+ @FunctionalInterface
+ interface LinkCreator {
+ void createLink(Path link, Path target) throws Exception;
+ }
+
private void testSymlink(LinkCreator linkCreator) throws Exception {
- // We use the SystemStreamLog() as the AbstractMojo class, because from there the Log is always provided
- Cleaner cleaner = new Cleaner(null, new SystemStreamLog(), false, null, null);
+ Cleaner cleaner = new Cleaner(null, null, false, null, null);
Path testDir = Paths.get("target/test-classes/unit/test-dir").toAbsolutePath();
Path dirWithLnk = testDir.resolve("dir");
Path orgDir = testDir.resolve("org-dir");
@@ -263,7 +262,7 @@ private void testSymlink(LinkCreator linkCreator) throws Exception {
Files.write(file, Collections.singleton("Hello world"));
linkCreator.createLink(jctDir, orgDir);
// delete
- cleaner.delete(dirWithLnk.toFile(), null, false, true, false);
+ cleaner.delete(dirWithLnk, null, false, true, false);
// verify
assertTrue(Files.exists(file));
assertFalse(Files.exists(jctDir));
@@ -276,7 +275,7 @@ private void testSymlink(LinkCreator linkCreator) throws Exception {
Files.write(file, Collections.singleton("Hello world"));
linkCreator.createLink(jctDir, orgDir);
// delete
- cleaner.delete(dirWithLnk.toFile(), null, true, true, false);
+ cleaner.delete(dirWithLnk, null, true, true, false);
// verify
assertFalse(Files.exists(file));
assertFalse(Files.exists(jctDir));
@@ -284,6 +283,32 @@ private void testSymlink(LinkCreator linkCreator) throws Exception {
assertFalse(Files.exists(dirWithLnk));
}
+ // @Provides
+ // @Singleton
+ // private Project createProject() {
+ // ProjectStub project = new ProjectStub();
+ // project.setGroupId("myGroupId");
+ // return project;
+ // }
+
+ // @Provides
+ // @Singleton
+ // @SuppressWarnings("unused")
+ // private InternalSession createSession() {
+ // InternalSession session = SessionStub.getMockSession(LOCAL_REPO);
+ // Properties props = new Properties();
+ // props.put("basedir", MojoExtension.getBasedir());
+ // doReturn(props).when(session).getSystemProperties();
+ // return session;
+ // }
+
+ // @Provides
+ // @Singleton
+ // @SuppressWarnings("unused")
+ // private MojoExecution createMojoExecution() {
+ // return new MojoExecutionStub("default-clean", "clean");
+ // }
+
/**
* @param dir a dir or a file
* @return true if a file/dir exists, false otherwise
@@ -300,9 +325,4 @@ private boolean checkEmpty(String dir) {
File[] files = new File(dir).listFiles();
return files == null || files.length == 0;
}
-
- @FunctionalInterface
- interface LinkCreator {
- void createLink(Path link, Path target) throws Exception;
- }
}
diff --git a/src/test/resources/unit/basic-clean-test/plugin-pom.xml b/src/test/resources/unit/basic-clean-test/plugin-pom.xml
deleted file mode 100644
index 38a6000..0000000
--- a/src/test/resources/unit/basic-clean-test/plugin-pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
- maven-clean-plugin
-
- ${basedir}/target/test-classes/unit/basic-clean-test/buildDirectory
- ${basedir}/target/test-classes/unit/basic-clean-test/buildOutputDirectory
- ${basedir}/target/test-classes/unit/basic-clean-test/buildTestDirectory
- true
- true
-
-
-
-
-
diff --git a/src/test/resources/unit/nested-clean-test/plugin-pom.xml b/src/test/resources/unit/basic-clean-test/pom.xml
similarity index 76%
rename from src/test/resources/unit/nested-clean-test/plugin-pom.xml
rename to src/test/resources/unit/basic-clean-test/pom.xml
index 790d14d..ba901f0 100644
--- a/src/test/resources/unit/nested-clean-test/plugin-pom.xml
+++ b/src/test/resources/unit/basic-clean-test/pom.xml
@@ -23,9 +23,9 @@
maven-clean-plugin
- ${basedir}/target/test-classes/unit/nested-clean-test/target
- ${basedir}/target/test-classes/unit/nested-clean-test/target/classes
- ${basedir}/target/test-classes/unit/nested-clean-test/target/test-classes
+ ${project.basedir}/buildDirectory
+ ${project.basedir}/buildOutputDirectory
+ ${project.basedir}/buildTestDirectory
true
true
diff --git a/src/test/resources/unit/empty-clean-test/plugin-pom.xml b/src/test/resources/unit/empty-clean-test/pom.xml
similarity index 100%
rename from src/test/resources/unit/empty-clean-test/plugin-pom.xml
rename to src/test/resources/unit/empty-clean-test/pom.xml
diff --git a/src/test/resources/unit/fileset-clean-test/plugin-pom.xml b/src/test/resources/unit/fileset-clean-test/pom.xml
similarity index 88%
rename from src/test/resources/unit/fileset-clean-test/plugin-pom.xml
rename to src/test/resources/unit/fileset-clean-test/pom.xml
index 5cd3ab3..2457c4e 100644
--- a/src/test/resources/unit/fileset-clean-test/plugin-pom.xml
+++ b/src/test/resources/unit/fileset-clean-test/pom.xml
@@ -23,9 +23,10 @@
maven-clean-plugin
+ true
- ${basedir}/target/test-classes/unit/fileset-clean-test/target
+ ${project.basedir}/target
**/file.txt
**/test-classes/**
@@ -35,7 +36,7 @@
- ${basedir}/target/test-classes/unit/fileset-clean-test/buildOutputDirectory
+ ${project.basedir}/buildOutputDirectory
**
diff --git a/src/test/resources/unit/locked-file-test/plugin-pom.xml b/src/test/resources/unit/invalid-directory-test/pom.xml
similarity index 91%
rename from src/test/resources/unit/locked-file-test/plugin-pom.xml
rename to src/test/resources/unit/invalid-directory-test/pom.xml
index 4101091..5d35e78 100644
--- a/src/test/resources/unit/locked-file-test/plugin-pom.xml
+++ b/src/test/resources/unit/invalid-directory-test/pom.xml
@@ -23,7 +23,7 @@
maven-clean-plugin
- ${basedir}/target/test-classes/unit/locked-file-test/buildDirectory
+ ${project.basedir}/this-is-a-file
true
true
diff --git a/src/test/resources/unit/missing-directory-test/plugin-pom.xml b/src/test/resources/unit/locked-file-test/pom.xml
similarity index 91%
rename from src/test/resources/unit/missing-directory-test/plugin-pom.xml
rename to src/test/resources/unit/locked-file-test/pom.xml
index 15b3923..1f2f429 100644
--- a/src/test/resources/unit/missing-directory-test/plugin-pom.xml
+++ b/src/test/resources/unit/locked-file-test/pom.xml
@@ -23,7 +23,7 @@
maven-clean-plugin
- ${basedir}/target/test-classes/unit/missing-clean-test/does-not-exist
+ ${project.basedir}/buildDirectory
true
true
diff --git a/src/test/resources/unit/invalid-directory-test/plugin-pom.xml b/src/test/resources/unit/missing-directory-test/pom.xml
similarity index 91%
rename from src/test/resources/unit/invalid-directory-test/plugin-pom.xml
rename to src/test/resources/unit/missing-directory-test/pom.xml
index b562122..ec695d1 100644
--- a/src/test/resources/unit/invalid-directory-test/plugin-pom.xml
+++ b/src/test/resources/unit/missing-directory-test/pom.xml
@@ -23,7 +23,7 @@
maven-clean-plugin
- ${basedir}/target/test-classes/unit/invalid-directory-test/this-is-a-file
+ ${project.basedir}/does-not-exist
true
true
diff --git a/src/test/resources/unit/nested-clean-test/pom.xml b/src/test/resources/unit/nested-clean-test/pom.xml
new file mode 100644
index 0000000..5f9e755
--- /dev/null
+++ b/src/test/resources/unit/nested-clean-test/pom.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ maven-clean-plugin
+
+ ${project.basedir}/target
+ ${project.basedir}/target/classes
+ ${project.basedir}/target/test-classes
+ true
+ true
+
+
+
+
+