Merge pull request #1251 from gallandarakhneorg/files_clean_folder

[util] Fixing the behavior of the cleanFolder function in Files class.
This commit is contained in:
Christian Dietrich 2019-10-14 09:23:56 +02:00 committed by GitHub
commit 7f78c02aff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 26 deletions

View file

@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright (c) 2019 Universite de Technologie de Belfort-Montbeliard (http://www.utbm.fr) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.util;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
/**
* @author Stephane Galland - Initial contribution and API
*/
public class FilesTest {
private static File makeFile(File root, String... elements) {
File res = root;
for (final String component : elements) {
if (res == null) {
res = new File(component);
} else {
res = new File(res, component);
}
}
return res;
}
private static void touch(File folder, String filename) throws IOException {
folder.mkdirs();
final File file = new File(folder, filename);
file.createNewFile();
}
private File createTestFolder() throws IOException {
File rootPath = makeFile(null, "build", "tmp", "FilesTest" + (int) (Math.random() * 100000000.));
while (rootPath.exists()) {
rootPath = makeFile(null, "build", "tmp", "FilesTest" + (int) (Math.random() * 100000000.));
}
final File folder1 = makeFile(rootPath, "src", "main", "java");
final File folder2 = makeFile(rootPath, "src", "main", "java", "mypack");
final File folder3 = makeFile(rootPath, "src", "generated-sources", "xtend", "mypack");
final File folder4 = makeFile(rootPath, "target", "classes", "mypack");
touch(folder1, "MyFile.java");
touch(folder2, "MyType.xtend");
touch(folder3, "MyType.java");
touch(folder4, "MyType.class");
touch(rootPath, ".hiddenfile");
return rootPath;
}
@Test
public void cleanFolder_deleteParentTrue() throws Exception {
final File root = createTestFolder();
Files.cleanFolder(root, null, true, true);
assertFalse(root.exists());
}
@Test
public void cleanFolder_deleteParentFalse() throws Exception {
final File root = createTestFolder();
Files.cleanFolder(root, null, true, false);
assertTrue(root.exists());
assertEquals(0, root.listFiles().length);
}
}

View file

@ -15,6 +15,9 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
@ -25,6 +28,7 @@ import com.google.common.io.ByteStreams;
/**
* @author Jan Köhnlein - Initial contribution and API
* @author Stephane Galland - fixing cleanFolder behavior
*/
public class Files {
private static Logger log = Logger.getLogger(Files.class);
@ -74,39 +78,54 @@ public class Files {
}
}
/** Clean the content of the the given folder.
*
* @param parentFolder the folder to be cleaned. It must not be {@code null}.
* @param filter a filter for selecting the files to be removed. If it is {@code null}, all the files are removed.
* @param continueOnError indicates if the cleaning should continue after an error occurs.
* @param deleteParentFolder indicates if {@code parentFolder} should be also deleted if it becomes empty.
* @return {@code true} if the cleaning process goes through all the folders and files. {@code false} if the process
* has been stopped before its termination. The value {@code false} could be replied only if the value of
* {@code continueOnError} is {@code false}.
* @throws FileNotFoundException if the given {@code parentFolder} does not exists.
*/
public static boolean cleanFolder(final File parentFolder, final FileFilter filter, boolean continueOnError,
boolean deleteParentFolder) throws FileNotFoundException {
if (!parentFolder.exists()) {
throw new FileNotFoundException(parentFolder.getAbsolutePath());
}
FileFilter myFilter = filter;
if (myFilter == null)
myFilter = new FileFilter() {
@Override
public boolean accept(File pathname) {
return true;
}
};
final FileFilter myFilter = filter == null ? it -> true : filter;
log.debug("Cleaning folder " + parentFolder.toString());
final File[] contents = parentFolder.listFiles(myFilter);
if (contents == null) {
return true;
}
for (int j = 0; j < contents.length; j++) {
final File file = contents[j];
if (file.isDirectory()) {
if (!cleanFolder(file, myFilter, continueOnError, true) && !continueOnError)
return false;
} else {
if (!file.delete()) {
if (contents != null) {
final Deque<File> filesToRemove = new LinkedList<>(Arrays.asList(contents));
while (!filesToRemove.isEmpty()) {
final File file = filesToRemove.pop();
if (file.isDirectory()) {
final File[] children = file.listFiles(myFilter);
if (children != null && children.length > 0) {
// Push back the folder in order to be removed after all its children.
filesToRemove.push(file);
// Push the children in order to be removed before the parent folder.
for (int i = 0; i < children.length; ++i) {
filesToRemove.push(children[i]);
}
} else if (!file.delete()) {
log.error("Couldn't delete " + file.getAbsolutePath());
if (!continueOnError) {
return false;
}
}
} else if (!file.delete()) {
log.error("Couldn't delete " + file.getAbsolutePath());
if (!continueOnError)
if (!continueOnError) {
return false;
}
}
}
}
if (deleteParentFolder) {
String[] children = parentFolder.list();
final String[] children = parentFolder.list();
if (children != null && children.length == 0 && !parentFolder.delete()) {
log.error("Couldn't delete " + parentFolder.getAbsolutePath());
return false;
@ -124,12 +143,7 @@ public class Files {
* @throws FileNotFoundException if folder does not exists
*/
public static boolean sweepFolder(File folder) throws FileNotFoundException {
return Files.cleanFolder(folder, new FileFilter() {
@Override
public boolean accept(File pathname) {
return true;
}
}, true, false);
return cleanFolder(folder, null, true, false);
}
/**