package org.robolectric.util; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayDeque; import java.util.LinkedHashSet; import java.util.Queue; import java.util.Set; public class TempDirectory { private static final TempDirectory instance = new TempDirectory(); private final Set<String> deletePaths; TempDirectory() { deletePaths = new LinkedHashSet<>(); // Use a manual hook that actually clears the directory // This is necessary because File.deleteOnExit won't delete non empty directories Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { for (String file : deletePaths) { try { Path path = Paths.get(file); clearDirectory(path); Files.delete(path); } catch (IOException ignored) { } } } })); } public static Path create() { return instance.createImpl(); } /** * @deprecated Use {@link #create()} instead. */ @Deprecated public static Path createDeleteOnExit() { return create(); } public static void destroy(Path path) { if (path != null) { instance.destroyImpl(path); } } private Path createImpl() { try { Path directory = Files.createTempDirectory("robolectric"); deleteOnExit(directory); return directory; } catch (IOException e) { throw new RuntimeException(e); } } void destroyImpl(Path path) { if (!Files.exists(path)) return; try { clearDirectory(path); } catch (IOException ignored) { // We failed to clear the directory, just try again at exit } deleteOnExit(path); } private void clearDirectory(final Path directory) throws IOException { Files.walkFileTree(directory, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (!dir.equals(directory)) { Files.delete(dir); } return FileVisitResult.CONTINUE; } }); } private void deleteOnExit(Path path) { deletePaths.add(path.toString()); } }