Browse Source

Merge "Extend FileUtils.rename to common git semantics"

stable-3.0
Matthias Sohn 12 years ago committed by Gerrit Code Review @ Eclipse.org
parent
commit
b1d191a155
  1. 69
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
  2. 18
      org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java

69
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.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -52,6 +53,7 @@ import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -321,4 +323,71 @@ public class FileUtilTest {
assertTrue(f.exists()); assertTrue(f.exists());
assertFalse(e.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));
}
} }

18
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 * 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 * 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 * 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() * @see FS#retryFailedLockFileCommit()
* @param src * @param src
@ -188,6 +195,15 @@ public class FileUtils {
while (--attempts >= 0) { while (--attempts >= 0) {
if (src.renameTo(dst)) if (src.renameTo(dst))
return; 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 { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {

Loading…
Cancel
Save