@Test public void safeRecursiveOverwriteActuallyOverwrite() throws Exception { MockFileOp fop = new MockFileOp(); File s1 = new File("/root/src/a"); File s2 = new File("/root/src/foo/a"); File s3 = new File("/root/src/foo/bar/a"); File d1 = new File("/root/dest/a"); File d2 = new File("/root/dest/foo/b"); fop.recordExistingFile(s1.getPath(), "content1"); fop.recordExistingFile(s2.getPath(), "content2"); fop.recordExistingFile(s3.getPath(), "content3"); fop.recordExistingFile(d1.getPath(), "content4"); fop.recordExistingFile(d2.getPath(), "content5"); FileOpUtils.safeRecursiveOverwrite(new File("/root/src/"), new File("/root/dest"), fop, new FakeProgressIndicator()); assertEquals("content1", new String(fop.getContent(new File("/root/dest/a")))); assertEquals("content2", new String(fop.getContent(new File("/root/dest/foo/a")))); assertEquals("content3", new String(fop.getContent(new File("/root/dest/foo/bar/a")))); assertEquals(3, fop.getExistingFiles().length); }
public static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest, @NonNull FileOp fop, @NonNull ProgressIndicator progress) throws IOException { File destBackup = getTempDir(dest, "backup", fop); boolean success = false; try { if (fop.exists(dest)) { moveOrCopyAndDelete(dest, destBackup, fop, progress); if (fop.exists(dest)) { throw new IOException("Failed to move away or delete existing target file"); } success = true; } } finally { if (!success && fop.exists(destBackup)) { try { recursiveCopy(destBackup, dest, true, fop, progress); fop.deleteFileOrFolder(destBackup); } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } success = false; try { moveOrCopyAndDelete(src, dest, fop, progress); success = true; } finally { if (!success) { fop.deleteFileOrFolder(dest); if (fop.exists(dest)) { File toDelete = getTempDir(dest, "delete", fop); fop.renameTo(dest, toDelete); fop.deleteOnExit(toDelete); } try { if (fop.exists(dest)) { recursiveCopy(destBackup, dest, true, fop, progress); } else { moveOrCopyAndDelete(destBackup, dest, fop, progress); } } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } fop.deleteFileOrFolder(destBackup); }
FileOpUtils { public static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest, @NonNull FileOp fop, @NonNull ProgressIndicator progress) throws IOException { File destBackup = getTempDir(dest, "backup", fop); boolean success = false; try { if (fop.exists(dest)) { moveOrCopyAndDelete(dest, destBackup, fop, progress); if (fop.exists(dest)) { throw new IOException("Failed to move away or delete existing target file"); } success = true; } } finally { if (!success && fop.exists(destBackup)) { try { recursiveCopy(destBackup, dest, true, fop, progress); fop.deleteFileOrFolder(destBackup); } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } success = false; try { moveOrCopyAndDelete(src, dest, fop, progress); success = true; } finally { if (!success) { fop.deleteFileOrFolder(dest); if (fop.exists(dest)) { File toDelete = getTempDir(dest, "delete", fop); fop.renameTo(dest, toDelete); fop.deleteOnExit(toDelete); } try { if (fop.exists(dest)) { recursiveCopy(destBackup, dest, true, fop, progress); } else { moveOrCopyAndDelete(destBackup, dest, fop, progress); } } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } fop.deleteFileOrFolder(destBackup); } }
FileOpUtils { public static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest, @NonNull FileOp fop, @NonNull ProgressIndicator progress) throws IOException { File destBackup = getTempDir(dest, "backup", fop); boolean success = false; try { if (fop.exists(dest)) { moveOrCopyAndDelete(dest, destBackup, fop, progress); if (fop.exists(dest)) { throw new IOException("Failed to move away or delete existing target file"); } success = true; } } finally { if (!success && fop.exists(destBackup)) { try { recursiveCopy(destBackup, dest, true, fop, progress); fop.deleteFileOrFolder(destBackup); } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } success = false; try { moveOrCopyAndDelete(src, dest, fop, progress); success = true; } finally { if (!success) { fop.deleteFileOrFolder(dest); if (fop.exists(dest)) { File toDelete = getTempDir(dest, "delete", fop); fop.renameTo(dest, toDelete); fop.deleteOnExit(toDelete); } try { if (fop.exists(dest)) { recursiveCopy(destBackup, dest, true, fop, progress); } else { moveOrCopyAndDelete(destBackup, dest, fop, progress); } } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } fop.deleteFileOrFolder(destBackup); } private  FileOpUtils(); }
FileOpUtils { public static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest, @NonNull FileOp fop, @NonNull ProgressIndicator progress) throws IOException { File destBackup = getTempDir(dest, "backup", fop); boolean success = false; try { if (fop.exists(dest)) { moveOrCopyAndDelete(dest, destBackup, fop, progress); if (fop.exists(dest)) { throw new IOException("Failed to move away or delete existing target file"); } success = true; } } finally { if (!success && fop.exists(destBackup)) { try { recursiveCopy(destBackup, dest, true, fop, progress); fop.deleteFileOrFolder(destBackup); } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } success = false; try { moveOrCopyAndDelete(src, dest, fop, progress); success = true; } finally { if (!success) { fop.deleteFileOrFolder(dest); if (fop.exists(dest)) { File toDelete = getTempDir(dest, "delete", fop); fop.renameTo(dest, toDelete); fop.deleteOnExit(toDelete); } try { if (fop.exists(dest)) { recursiveCopy(destBackup, dest, true, fop, progress); } else { moveOrCopyAndDelete(destBackup, dest, fop, progress); } } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } fop.deleteFileOrFolder(destBackup); } private  FileOpUtils(); @NonNull static FileOp create(); static void recursiveCopy(@NonNull File src, @NonNull File dest, @NonNull FileOp fop,
            @NonNull ProgressIndicator progress); static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest,
            @NonNull FileOp fop, @NonNull ProgressIndicator progress); @Nullable static File getNewTempDir(@NonNull String base, @NonNull FileOp fileOp); @NonNull @VisibleForTesting static File getTempDir(@NonNull String base, int i); @NonNull static File append(@NonNull File base, @NonNull String... segments); @NonNull static File append(@NonNull String base, @NonNull String... segments); @NonNull static String makeRelative(@NonNull File baseDir, @NonNull File toBeRelative, FileOp fop); static void retainTempDirs(Set<File> retain, String base, FileOp mFop); }
FileOpUtils { public static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest, @NonNull FileOp fop, @NonNull ProgressIndicator progress) throws IOException { File destBackup = getTempDir(dest, "backup", fop); boolean success = false; try { if (fop.exists(dest)) { moveOrCopyAndDelete(dest, destBackup, fop, progress); if (fop.exists(dest)) { throw new IOException("Failed to move away or delete existing target file"); } success = true; } } finally { if (!success && fop.exists(destBackup)) { try { recursiveCopy(destBackup, dest, true, fop, progress); fop.deleteFileOrFolder(destBackup); } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } success = false; try { moveOrCopyAndDelete(src, dest, fop, progress); success = true; } finally { if (!success) { fop.deleteFileOrFolder(dest); if (fop.exists(dest)) { File toDelete = getTempDir(dest, "delete", fop); fop.renameTo(dest, toDelete); fop.deleteOnExit(toDelete); } try { if (fop.exists(dest)) { recursiveCopy(destBackup, dest, true, fop, progress); } else { moveOrCopyAndDelete(destBackup, dest, fop, progress); } } catch (IOException e) { progress.logWarning(String.format( "Failed to move original content of %s back into place! " + "It should be available at %s", dest, destBackup), e); } } } fop.deleteFileOrFolder(destBackup); } private  FileOpUtils(); @NonNull static FileOp create(); static void recursiveCopy(@NonNull File src, @NonNull File dest, @NonNull FileOp fop,
            @NonNull ProgressIndicator progress); static void safeRecursiveOverwrite(@NonNull File src, @NonNull File dest,
            @NonNull FileOp fop, @NonNull ProgressIndicator progress); @Nullable static File getNewTempDir(@NonNull String base, @NonNull FileOp fileOp); @NonNull @VisibleForTesting static File getTempDir(@NonNull String base, int i); @NonNull static File append(@NonNull File base, @NonNull String... segments); @NonNull static File append(@NonNull String base, @NonNull String... segments); @NonNull static String makeRelative(@NonNull File baseDir, @NonNull File toBeRelative, FileOp fop); static void retainTempDirs(Set<File> retain, String base, FileOp mFop);  }