Introduce overwrite parameter to File.copyRecursively.

#KT-8924 Fixed
This commit is contained in:
Ilya Gorbunov
2016-01-22 06:35:51 +03:00
parent d03c174650
commit 67663c43ae
2 changed files with 70 additions and 19 deletions
+24 -9
View File
@@ -218,7 +218,7 @@ public enum class OnErrorAction {
private class TerminateException(file: File) : FileSystemException(file) {} private class TerminateException(file: File) : FileSystemException(file) {}
/** /**
* Copies this file with all its children to the specified destination [dst] path. * Copies this file with all its children to the specified destination [target] path.
* If some directories on the way to the destination are missing, then they will be created. * If some directories on the way to the destination are missing, then they will be created.
* *
* If any errors occur during the copying, then further actions will depend on the result of the call * If any errors occur during the copying, then further actions will depend on the result of the call
@@ -231,11 +231,13 @@ private class TerminateException(file: File) : FileSystemException(file) {}
* AccessDeniedException - if there was an attempt to open a directory that didn't succeed. * AccessDeniedException - if there was an attempt to open a directory that didn't succeed.
* IOException - if some problems occur when copying. * IOException - if some problems occur when copying.
* *
* @param overwrite `true` if it is allowed to overwrite existing destination files and directories.
* @return `false` if the copying was terminated, `true` otherwise. * @return `false` if the copying was terminated, `true` otherwise.
* *
* Note that if this function fails, then partial copying may have taken place. * Note that if this function fails, then partial copying may have taken place.
*/ */
public fun File.copyRecursively(dst: File, public fun File.copyRecursively(target: File,
overwrite: Boolean = false,
onError: (File, IOException) -> OnErrorAction = onError: (File, IOException) -> OnErrorAction =
{ file, exception -> throw exception } { file, exception -> throw exception }
): Boolean { ): Boolean {
@@ -252,16 +254,29 @@ public fun File.copyRecursively(dst: File,
return false return false
} else { } else {
val relPath = src.toRelativeString(this) val relPath = src.toRelativeString(this)
val dstFile = File(dst, relPath) val dstFile = File(target, relPath)
if (dstFile.exists() && !(src.isDirectory && dstFile.isDirectory)) { if (dstFile.exists() && !(src.isDirectory && dstFile.isDirectory)) {
if (onError(dstFile, FileAlreadyExistsException(file = src, val stillExists = if (!overwrite) true else {
other = dstFile, if (dstFile.isDirectory)
reason = "The destination file already exists")) == OnErrorAction.TERMINATE) !dstFile.deleteRecursively()
return false else
} else if (src.isDirectory) { !dstFile.delete()
}
if (stillExists) {
if (onError(dstFile, FileAlreadyExistsException(file = src,
other = dstFile,
reason = "The destination file already exists")) == OnErrorAction.TERMINATE)
return false
continue
}
}
if (src.isDirectory) {
dstFile.mkdirs() dstFile.mkdirs()
} else { } else {
if (src.copyTo(dstFile, true) != src.length()) { if (src.copyTo(dstFile, overwrite) != src.length()) {
if (onError(src, IOException("src.length() != dst.length()")) == OnErrorAction.TERMINATE) if (onError(src, IOException("src.length() != dst.length()")) == OnErrorAction.TERMINATE)
return false return false
} }
+46 -10
View File
@@ -451,20 +451,22 @@ class FilesTest {
} }
} }
fun compareDirectories(src: File, dst: File) {
for (file in src.walkTopDown()) {
val dstFile = dst.resolve(file.relativeTo(src))
assertTrue(dstFile.exists())
assertEquals(file.isFile, dstFile.isFile)
if (dstFile.isFile) {
assertEquals(file.readText(), dstFile.readText())
}
}
}
@test fun copyRecursively() { @test fun copyRecursively() {
val src = createTempDir() val src = createTempDir()
val dst = createTempDir() val dst = createTempDir()
dst.delete() dst.delete()
fun check() { fun check() = compareDirectories(src, dst)
for (file in src.walkTopDown()) {
val dstFile = dst.resolve(file.relativeTo(src))
assertTrue(dstFile.exists())
if (dstFile.isFile) {
assertEquals(file.readText(), dstFile.readText())
}
}
}
try { try {
val subDir1 = createTempDir(prefix = "d1_", directory = src) val subDir1 = createTempDir(prefix = "d1_", directory = src)
@@ -531,6 +533,40 @@ class FilesTest {
} }
} }
@test fun copyRecursivelyWithOverwrite() {
val src = createTempDir()
val dst = createTempDir()
fun check() = compareDirectories(src, dst)
try {
val srcFile = src.resolve("test")
val dstFile = dst.resolve("test")
srcFile.writeText("text1")
src.copyRecursively(dst)
srcFile.writeText("text1 modified")
src.copyRecursively(dst, overwrite = true)
check()
dstFile.delete()
dstFile.mkdir()
dstFile.resolve("subFile").writeText("subfile")
src.copyRecursively(dst, overwrite = true)
check()
srcFile.delete()
srcFile.mkdir()
srcFile.resolve("subFile").writeText("text2")
src.copyRecursively(dst, overwrite = true)
check()
}
finally {
src.deleteRecursively()
dst.deleteRecursively()
}
}
@test fun helpers1() { @test fun helpers1() {
val str = "123456789\n" val str = "123456789\n"
System.setIn(str.byteInputStream()) System.setIn(str.byteInputStream())