diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2013-03-27 09:03:23 -0400 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org <gerrit@eclipse.org> | 2013-03-27 09:03:23 -0400 |
commit | b1d191a1550891f349896373ff428e59571e4885 (patch) | |
tree | bba1cac18479105f96737a7fa22708bf632f093a | |
parent | 7f1c2ec1eb81fa1dfca7bfe55bdfb9e8559dcaa2 (diff) | |
parent | d0e92885e911c96be917574a5f804bf64d622cf9 (diff) | |
download | jgit-b1d191a1550891f349896373ff428e59571e4885.tar.gz jgit-b1d191a1550891f349896373ff428e59571e4885.zip |
Merge "Extend FileUtils.rename to common git semantics"
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java | 69 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java | 18 |
2 files changed, 86 insertions, 1 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java index d0680cab74..f6f6753c75 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.util; 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; @@ -52,6 +53,7 @@ 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; @@ -321,4 +323,71 @@ public class FileUtilTest { 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)); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java index dc0bbcb380..5fbbda7c50 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -171,7 +171,14 @@ public class FileUtils { * 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 @@ -189,6 +196,15 @@ public class FileUtils { 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) { throw new IOException(MessageFormat.format( |