import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
+import org.eclipse.jgit.junit.JGitTestUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
assertTrue(f.exists());
assertFalse(e.exists());
}
+
+ @Test
+ public void testRenameOverNonExistingFile() throws IOException {
+ File d = new File(trash, "d");
+ FileUtils.mkdirs(d);
+ File f1 = new File(trash, "d/f");
+ File f2 = new File(trash, "d/g");
+ JGitTestUtil.write(f1, "f1");
+ // test
+ FileUtils.rename(f1, f2);
+ assertFalse(f1.exists());
+ assertTrue(f2.exists());
+ assertEquals("f1", JGitTestUtil.read(f2));
+ }
+
+ @Test
+ public void testRenameOverExistingFile() throws IOException {
+ File d = new File(trash, "d");
+ FileUtils.mkdirs(d);
+ File f1 = new File(trash, "d/f");
+ File f2 = new File(trash, "d/g");
+ JGitTestUtil.write(f1, "f1");
+ JGitTestUtil.write(f2, "f2");
+ // test
+ FileUtils.rename(f1, f2);
+ assertFalse(f1.exists());
+ assertTrue(f2.exists());
+ assertEquals("f1", JGitTestUtil.read(f2));
+ }
+
+ @Test
+ public void testRenameOverExistingNonEmptyDirectory() throws IOException {
+ File d = new File(trash, "d");
+ FileUtils.mkdirs(d);
+ File f1 = new File(trash, "d/f");
+ File f2 = new File(trash, "d/g");
+ File d1 = new File(trash, "d/g/h/i");
+ File f3 = new File(trash, "d/g/h/f");
+ FileUtils.mkdirs(d1);
+ JGitTestUtil.write(f1, "f1");
+ JGitTestUtil.write(f3, "f3");
+ // test
+ try {
+ FileUtils.rename(f1, f2);
+ fail("rename to non-empty directory should fail");
+ } catch (IOException e) {
+ assertEquals("f1", JGitTestUtil.read(f1)); // untouched source
+ assertEquals("f3", JGitTestUtil.read(f3)); // untouched
+ // empty directories within f2 may or may not have been deleted
+ }
+ }
+
+ @Test
+ public void testRenameOverExistingEmptyDirectory() throws IOException {
+ File d = new File(trash, "d");
+ FileUtils.mkdirs(d);
+ File f1 = new File(trash, "d/f");
+ File f2 = new File(trash, "d/g");
+ File d1 = new File(trash, "d/g/h/i");
+ FileUtils.mkdirs(d1);
+ JGitTestUtil.write(f1, "f1");
+ // test
+ FileUtils.rename(f1, f2);
+ assertFalse(f1.exists());
+ assertTrue(f2.exists());
+ assertEquals("f1", JGitTestUtil.read(f2));
+ }
}
* Rename a file or folder. If the rename fails and if we are running on a
* filesystem where it makes sense to repeat a failing rename then repeat
* the rename operation up to 9 times with 100ms sleep time between two
- * calls
+ * calls. Furthermore if the destination exists and is directory hierarchy
+ * with only directories in it, the whole directory hierarchy will be
+ * deleted. If the target represents a non-empty directory structure, empty
+ * subdirectories within that structure may or may not be deleted even if
+ * the method fails. Furthermore if the destination exists and is a file
+ * then the file will be deleted and then the rename is retried.
+ * <p>
+ * This operation is <em>not</me> atomic.
*
* @see FS#retryFailedLockFileCommit()
* @param src
while (--attempts >= 0) {
if (src.renameTo(dst))
return;
+ try {
+ if (!dst.delete())
+ delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
+ // On *nix there is no try, you do or do not
+ if (src.renameTo(dst))
+ return;
+ } catch (IOException e) {
+ // ignore and continue retry
+ }
try {
Thread.sleep(100);
} catch (InterruptedException e) {