rmannibucau commented on a change in pull request #6:
URL: https://github.com/apache/maven-clean-plugin/pull/6#discussion_r771980242
##########
File path: src/main/java/org/apache/maven/plugins/clean/Cleaner.java
##########
@@ -286,4 +393,189 @@ public void update( Result result )
}
+ static class BackgroundCleaner extends Thread
+ {
+
+ private static BackgroundCleaner instance;
+
+ private final Deque<File> filesToDelete = new ArrayDeque<>();
+
+ private final Cleaner cleaner;
+
+ private static final int NEW = 0;
+ private static final int RUNNING = 1;
+ private static final int STOPPED = 2;
+
+ private int status = NEW;
+
+ public static void delete( Cleaner cleaner, File dir )
+ {
+ synchronized ( BackgroundCleaner.class )
+ {
+ if ( instance == null || !instance.doDelete( dir ) )
+ {
+ instance = new BackgroundCleaner( cleaner, dir );
+ }
+ }
+ }
+
+ static void sessionEnd()
+ {
+ synchronized ( BackgroundCleaner.class )
+ {
+ if ( instance != null )
+ {
+ instance.doSessionEnd();
+ }
+ }
+ }
+
+ private BackgroundCleaner( Cleaner cleaner, File dir )
+ {
+ this.cleaner = cleaner;
+ init( cleaner.fastDir, dir );
+ }
+
+ public void run()
+ {
+ while ( true )
+ {
+ File basedir = pollNext();
+ if ( basedir == null )
+ {
+ break;
+ }
+ try
+ {
+ cleaner.delete( basedir, "", null, false, false, true );
+ }
+ catch ( IOException e )
+ {
+ // do not display errors
+ }
+ }
+ }
+
+ 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 );
+ }
+ }
+ }
+ doDelete( dir );
+ }
+
+ synchronized File pollNext()
+ {
+ File 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
);
+ if ( lastDir != null )
+ {
+ data.set( LAST_DIRECTORY_TO_DELETE, null );
+ return lastDir;
+ }
+ }
+ status = STOPPED;
+ notifyAll();
+ }
+ return basedir;
+ }
+
+ synchronized boolean doDelete( File dir )
+ {
+ if ( status == STOPPED )
+ {
+ return false;
+ }
+ filesToDelete.add( dir );
+ if ( status == NEW )
+ {
+ status = RUNNING;
+ notifyAll();
+ wrapExecutionListener();
+ start();
+ }
+ return true;
+ }
+
+ /**
+ * If this has not been done already, we wrap the ExecutionListener
inside a proxy
+ * which simply delegates call to the previous listener. When the
session ends, it will
+ * also call {@link BackgroundCleaner#sessionEnd()}.
+ * There's no clean API to do that properly as this is a very unusual
use case for a plugin
+ * 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 void doSessionEnd()
+ {
+ if ( status != STOPPED )
+ {
+ try
+ {
+ cleaner.logInfo.log( "Waiting for background file
deletion" );
+ while ( status != STOPPED )
+ {
+ wait();
+ }
+ }
+ catch ( InterruptedException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ }
+
+ static class SpyInvocationHandler implements InvocationHandler
+ {
+ private final ExecutionListener delegate;
+
+ SpyInvocationHandler( ExecutionListener delegate )
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Object invoke( Object proxy, Method method, Object[] args )
throws Throwable
+ {
+ if ( "sessionEnded".equals( method.getName() ) )
+ {
+ BackgroundCleaner.sessionEnd();
Review comment:
Guess for mvnd case we only need to enable to override clean mojo easily
and not add an useless option upfront so for me it is only atEnd and
integrations can override it at need. I don't see mojo getting mvnd specific
options because:
1. it would be useless option for all mvn builds so doc would be unlikely
IMHO
2. there is no technical blocker to do what you want in mvnd as of today
(worse is done to mention it)
I'm suspicious on the background cause it can create easily not
deterministic behaviors if it is mixed with other commands watching target so
can be better to use some checkpointing (synchronizations are more than
sufficient) - but it is likely a daemon thing only.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]