[MCLEAN-45] Clean plugin should support a silent retry in case the first attemp fails
o Added parameter to disable re-attempts as suggested by Brett
git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@985474 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/maven/plugin/clean/CleanMojo.java b/src/main/java/org/apache/maven/plugin/clean/CleanMojo.java
index 2531002..ef8f74d 100644
--- a/src/main/java/org/apache/maven/plugin/clean/CleanMojo.java
+++ b/src/main/java/org/apache/maven/plugin/clean/CleanMojo.java
@@ -131,6 +131,16 @@
private boolean failOnError;
/**
+ * Indicates whether the plugin should undertake additional attempts (after a short delay) to delete a file if the
+ * first attempt failed. This is meant to help deleting files that are temporarily locked by third-party tools like
+ * virus scanners or search indexing.
+ *
+ * @parameter expression="${maven.clean.retryOnError}" default-value="true"
+ * @since 2.4.2
+ */
+ private boolean retryOnError;
+
+ /**
* Disables the deletion of the default output directories configured for a project. If set to <code>true</code>,
* only the files/directories selected via the parameter {@link #filesets} will be deleted.
*
@@ -165,7 +175,7 @@
File directory = directories[i];
if ( directory != null )
{
- cleaner.delete( directory, null, followSymLinks, failOnError );
+ cleaner.delete( directory, null, followSymLinks, failOnError, retryOnError );
}
}
@@ -179,7 +189,8 @@
throw new MojoExecutionException( "Missing base directory for " + fileset );
}
GlobSelector selector = new GlobSelector( fileset.getIncludes(), fileset.getExcludes() );
- cleaner.delete( fileset.getDirectory(), selector, fileset.isFollowSymlinks(), failOnError );
+ cleaner.delete( fileset.getDirectory(), selector, fileset.isFollowSymlinks(), failOnError,
+ retryOnError );
}
}
}
diff --git a/src/main/java/org/apache/maven/plugin/clean/Cleaner.java b/src/main/java/org/apache/maven/plugin/clean/Cleaner.java
index ed333e6..306fe2c 100644
--- a/src/main/java/org/apache/maven/plugin/clean/Cleaner.java
+++ b/src/main/java/org/apache/maven/plugin/clean/Cleaner.java
@@ -87,9 +87,11 @@
* 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.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
*/
- public void delete( File basedir, Selector selector, boolean followSymlinks, boolean failOnError )
+ public void delete( File basedir, Selector selector, boolean followSymlinks, boolean failOnError,
+ boolean retryOnError )
throws IOException
{
if ( !basedir.isDirectory() )
@@ -112,7 +114,7 @@
File file = followSymlinks ? basedir : basedir.getCanonicalFile();
- delete( file, "", selector, followSymlinks, failOnError );
+ delete( file, "", selector, followSymlinks, failOnError, retryOnError );
}
/**
@@ -126,10 +128,12 @@
* 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.
* @return The result of the cleaning, never <code>null</code>.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
*/
- private Result delete( File file, String pathname, Selector selector, boolean followSymlinks, boolean failOnError )
+ private Result delete( File file, String pathname, Selector selector, boolean followSymlinks, boolean failOnError,
+ boolean retryOnError )
throws IOException
{
Result result = new Result();
@@ -151,7 +155,8 @@
{
String filename = filenames[i];
File child = new File( canonical, filename );
- result.update( delete( child, prefix + filename, selector, followSymlinks, failOnError ) );
+ result.update( delete( child, prefix + filename, selector, followSymlinks, failOnError,
+ retryOnError ) );
}
}
}
@@ -183,7 +188,7 @@
logVerbose.log( "Deleting dangling symlink " + file );
}
}
- result.failures += delete( file, failOnError );
+ result.failures += delete( file, failOnError, retryOnError );
}
else
{
@@ -199,34 +204,42 @@
*
* @param file The file/directory to delete, must not be <code>null</code>.
* @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 <code>0</code> if the file was deleted, <code>1</code> otherwise.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
*/
- private int delete( File file, boolean failOnError )
+ private int delete( File file, boolean failOnError, boolean retryOnError )
throws IOException
{
if ( !file.delete() )
{
- if ( ON_WINDOWS )
- {
- // try to release any locks held by non-closed files
- System.gc();
- }
-
boolean deleted = false;
- int[] delays = { 125, 250, 750 };
- for ( int i = 0; !deleted && i < delays.length; i++ )
+ if ( retryOnError )
{
- try
+ if ( ON_WINDOWS )
{
- Thread.sleep( delays[i] );
+ // try to release any locks held by non-closed files
+ System.gc();
}
- catch ( InterruptedException e )
+
+ int[] delays = { 50, 250, 750 };
+ for ( int i = 0; !deleted && i < delays.length; i++ )
{
- // ignore
+ try
+ {
+ Thread.sleep( delays[i] );
+ }
+ catch ( InterruptedException e )
+ {
+ // ignore
+ }
+ deleted = file.delete() || !file.exists();
}
- deleted = file.delete() || !file.exists();
+ }
+ else
+ {
+ deleted = !file.exists();
}
if ( !deleted )