2323import java .lang .reflect .InvocationHandler ;
2424import java .lang .reflect .Method ;
2525import java .lang .reflect .Proxy ;
26+ import java .nio .file .DirectoryStream ;
2627import java .nio .file .Files ;
2728import java .nio .file .LinkOption ;
2829import java .nio .file .Path ;
3738import org .codehaus .plexus .util .Os ;
3839import org .eclipse .aether .SessionData ;
3940
41+ import static java .nio .file .Files .exists ;
42+ import static java .nio .file .Files .isDirectory ;
43+ import static java .nio .file .Files .newDirectoryStream ;
4044import static org .apache .maven .plugins .clean .CleanMojo .FAST_MODE_BACKGROUND ;
4145import static org .apache .maven .plugins .clean .CleanMojo .FAST_MODE_DEFER ;
4246
@@ -56,7 +60,7 @@ class Cleaner {
5660 */
5761 private final MavenSession session ;
5862
59- private final File fastDir ;
63+ private final Path fastDir ;
6064
6165 private final String fastMode ;
6266
@@ -73,7 +77,7 @@ class Cleaner {
7377 * @param fastDir The explicit configured directory or to be deleted in fast mode.
7478 * @param fastMode The fast deletion mode.
7579 */
76- Cleaner (MavenSession session , final Log log , boolean verbose , File fastDir , String fastMode ) {
80+ Cleaner (MavenSession session , final Log log , boolean verbose , Path fastDir , String fastMode ) {
7781 this .session = session ;
7882 // This can't be null as the Cleaner gets it from the CleanMojo which gets it from AbstractMojo class, where it
7983 // is never null.
@@ -96,10 +100,10 @@ class Cleaner {
96100 * @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
97101 */
98102 public void delete (
99- File basedir , Selector selector , boolean followSymlinks , boolean failOnError , boolean retryOnError )
103+ Path basedir , Selector selector , boolean followSymlinks , boolean failOnError , boolean retryOnError )
100104 throws IOException {
101- if (!basedir . isDirectory ()) {
102- if (!basedir . exists ()) {
105+ if (!isDirectory (basedir )) {
106+ if (!exists (basedir )) {
103107 if (log .isDebugEnabled ()) {
104108 log .debug ("Skipping non-existing directory " + basedir );
105109 }
@@ -112,7 +116,7 @@ public void delete(
112116 log .info ("Deleting " + basedir + (selector != null ? " (" + selector + ")" : "" ));
113117 }
114118
115- File file = followSymlinks ? basedir : basedir .getCanonicalFile ();
119+ Path file = followSymlinks ? basedir : basedir .toRealPath ();
116120
117121 if (selector == null && !followSymlinks && fastDir != null && session != null ) {
118122 // If anything wrong happens, we'll just use the usual deletion mechanism
@@ -124,9 +128,7 @@ public void delete(
124128 delete (file , "" , selector , followSymlinks , failOnError , retryOnError );
125129 }
126130
127- private boolean fastDelete (File baseDirFile ) {
128- Path baseDir = baseDirFile .toPath ();
129- Path fastDir = this .fastDir .toPath ();
131+ private boolean fastDelete (Path baseDir ) {
130132 // Handle the case where we use ${maven.multiModuleProjectDirectory}/target/.clean for example
131133 if (fastDir .toAbsolutePath ().startsWith (baseDir .toAbsolutePath ())) {
132134 try {
@@ -135,7 +137,7 @@ private boolean fastDelete(File baseDirFile) {
135137 try {
136138 Files .move (baseDir , tmpDir , StandardCopyOption .REPLACE_EXISTING );
137139 if (session != null ) {
138- session .getRepositorySession ().getData ().set (LAST_DIRECTORY_TO_DELETE , baseDir . toFile () );
140+ session .getRepositorySession ().getData ().set (LAST_DIRECTORY_TO_DELETE , baseDir );
139141 }
140142 baseDir = tmpDir ;
141143 } catch (IOException e ) {
@@ -151,7 +153,7 @@ private boolean fastDelete(File baseDirFile) {
151153 }
152154 // Create fastDir and the needed parents if needed
153155 try {
154- if (!Files . isDirectory (fastDir )) {
156+ if (!isDirectory (fastDir )) {
155157 Files .createDirectories (fastDir );
156158 }
157159 } catch (IOException e ) {
@@ -172,7 +174,7 @@ private boolean fastDelete(File baseDirFile) {
172174 // or any other exception occurs, an exception will be thrown in which case
173175 // the method will return false and the usual deletion will be performed.
174176 Files .move (baseDir , dstDir , StandardCopyOption .ATOMIC_MOVE );
175- BackgroundCleaner .delete (this , tmpDir . toFile () , fastMode );
177+ BackgroundCleaner .delete (this , tmpDir , fastMode );
176178 return true ;
177179 } catch (IOException e ) {
178180 if (log .isDebugEnabled ()) {
@@ -198,7 +200,7 @@ private boolean fastDelete(File baseDirFile) {
198200 * @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
199201 */
200202 private Result delete (
201- File file ,
203+ Path file ,
202204 String pathname ,
203205 Selector selector ,
204206 boolean followSymlinks ,
@@ -207,18 +209,16 @@ private Result delete(
207209 throws IOException {
208210 Result result = new Result ();
209211
210- boolean isDirectory = file . isDirectory ();
212+ boolean isDirectory = isDirectory (file );
211213
212214 if (isDirectory ) {
213215 if (selector == null || selector .couldHoldSelected (pathname )) {
214- if (followSymlinks || !isSymbolicLink (file .toPath ())) {
215- File canonical = followSymlinks ? file : file .getCanonicalFile ();
216- String [] filenames = canonical .list ();
217- if (filenames != null ) {
218- String prefix = pathname .length () > 0 ? pathname + File .separatorChar : "" ;
219- for (int i = filenames .length - 1 ; i >= 0 ; i --) {
220- String filename = filenames [i ];
221- File child = new File (canonical , filename );
216+ if (followSymlinks || !isSymbolicLink (file )) {
217+ Path canonical = followSymlinks ? file : file .toRealPath ();
218+ String prefix = pathname .length () > 0 ? pathname + File .separatorChar : "" ;
219+ try (DirectoryStream <Path > children = newDirectoryStream (canonical )) {
220+ for (Path child : children ) {
221+ String filename = child .getFileName ().toString ();
222222 result .update (delete (
223223 child , prefix + filename , selector , followSymlinks , failOnError , retryOnError ));
224224 }
@@ -235,7 +235,7 @@ private Result delete(
235235 String logmessage ;
236236 if (isDirectory ) {
237237 logmessage = "Deleting directory " + file ;
238- } else if (file . exists ()) {
238+ } else if (exists (file )) {
239239 logmessage = "Deleting file " + file ;
240240 } else {
241241 logmessage = "Deleting dangling symlink " + file ;
@@ -272,7 +272,7 @@ private boolean isSymbolicLink(Path path) throws IOException {
272272 * @return <code>0</code> if the file was deleted, <code>1</code> otherwise.
273273 * @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
274274 */
275- private int delete (File file , boolean failOnError , boolean retryOnError ) throws IOException {
275+ private int delete (Path file , boolean failOnError , boolean retryOnError ) throws IOException {
276276 IOException failure = delete (file );
277277 if (failure != null ) {
278278 boolean deleted = false ;
@@ -290,10 +290,10 @@ private int delete(File file, boolean failOnError, boolean retryOnError) throws
290290 } catch (InterruptedException e ) {
291291 // ignore
292292 }
293- deleted = delete (file ) == null || !file . exists ();
293+ deleted = delete (file ) == null || !exists (file );
294294 }
295295 } else {
296- deleted = !file . exists ();
296+ deleted = !exists (file );
297297 }
298298
299299 if (!deleted ) {
@@ -311,9 +311,9 @@ private int delete(File file, boolean failOnError, boolean retryOnError) throws
311311 return 0 ;
312312 }
313313
314- private static IOException delete (File file ) {
314+ private static IOException delete (Path file ) {
315315 try {
316- Files .delete (file . toPath () );
316+ Files .delete (file );
317317 } catch (IOException e ) {
318318 return e ;
319319 }
@@ -338,19 +338,19 @@ private static class BackgroundCleaner extends Thread {
338338 private static final int RUNNING = 1 ;
339339 private static final int STOPPED = 2 ;
340340 private static BackgroundCleaner instance ;
341- private final Deque <File > filesToDelete = new ArrayDeque <>();
341+ private final Deque <Path > filesToDelete = new ArrayDeque <>();
342342 private final Cleaner cleaner ;
343343 private final String fastMode ;
344344 private int status = NEW ;
345345
346- private BackgroundCleaner (Cleaner cleaner , File dir , String fastMode ) {
346+ private BackgroundCleaner (Cleaner cleaner , Path dir , String fastMode ) throws IOException {
347347 super ("mvn-background-cleaner" );
348348 this .cleaner = cleaner ;
349349 this .fastMode = fastMode ;
350350 init (cleaner .fastDir , dir );
351351 }
352352
353- public static void delete (Cleaner cleaner , File dir , String fastMode ) {
353+ public static void delete (Cleaner cleaner , Path dir , String fastMode ) throws IOException {
354354 synchronized (BackgroundCleaner .class ) {
355355 if (instance == null || !instance .doDelete (dir )) {
356356 instance = new BackgroundCleaner (cleaner , dir , fastMode );
@@ -368,7 +368,7 @@ static void sessionEnd() {
368368
369369 public void run () {
370370 while (true ) {
371- File basedir = pollNext ();
371+ Path basedir = pollNext ();
372372 if (basedir == null ) {
373373 break ;
374374 }
@@ -380,24 +380,23 @@ public void run() {
380380 }
381381 }
382382
383- synchronized void init (File fastDir , File dir ) {
384- if (fastDir .isDirectory ()) {
385- File [] children = fastDir .listFiles ();
386- if (children != null && children .length > 0 ) {
387- for (File child : children ) {
383+ synchronized void init (Path fastDir , Path dir ) throws IOException {
384+ if (isDirectory (fastDir )) {
385+ try (DirectoryStream <Path > children = newDirectoryStream (fastDir )) {
386+ for (Path child : children ) {
388387 doDelete (child );
389388 }
390389 }
391390 }
392391 doDelete (dir );
393392 }
394393
395- synchronized File pollNext () {
396- File basedir = filesToDelete .poll ();
394+ synchronized Path pollNext () {
395+ Path basedir = filesToDelete .poll ();
397396 if (basedir == null ) {
398397 if (cleaner .session != null ) {
399398 SessionData data = cleaner .session .getRepositorySession ().getData ();
400- File lastDir = (File ) data .get (LAST_DIRECTORY_TO_DELETE );
399+ Path lastDir = (Path ) data .get (LAST_DIRECTORY_TO_DELETE );
401400 if (lastDir != null ) {
402401 data .set (LAST_DIRECTORY_TO_DELETE , null );
403402 return lastDir ;
@@ -409,7 +408,7 @@ synchronized File pollNext() {
409408 return basedir ;
410409 }
411410
412- synchronized boolean doDelete (File dir ) {
411+ synchronized boolean doDelete (Path dir ) {
413412 if (status == STOPPED ) {
414413 return false ;
415414 }
0 commit comments