diff --git a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt index 7f0559bda..36c91aaf3 100644 --- a/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt +++ b/adam/src/integrationTest/kotlin/com/malinskiy/adam/integration/PullE2ETest.kt @@ -20,6 +20,7 @@ import assertk.assertThat import assertk.assertions.isDirectory import assertk.assertions.isEqualTo import assertk.assertions.isFile +import assertk.assertions.isZero import com.malinskiy.adam.request.shell.v1.ShellCommandRequest import com.malinskiy.adam.request.sync.PullRequest import com.malinskiy.adam.rule.AdbDeviceRule @@ -155,5 +156,31 @@ class PullE2ETest { assertThat(x.readText()).isEqualTo("Xcafebabe\n") } } + + @Test + fun testPullFolderWithEmptyFile() { + runBlocking { + adbRule.adb.execute(ShellCommandRequest("mkdir -p /data/local/tmp/testdir/X"), adbRule.deviceSerial) + adbRule.adb.execute(ShellCommandRequest("touch /data/local/tmp/testdir/X/testfilex"), adbRule.deviceSerial) + adbRule.adb.execute(ShellCommandRequest("echo Xcafebabe > /data/local/tmp/testdir/X/testfiley"), adbRule.deviceSerial) + + val dst = temp.newFolder() + val execute = + adbRule.adb.execute( + PullRequest("/data/local/tmp/testdir/X", dst, adbRule.supportedFeatures), + adbRule.deviceSerial + ) + + val X = File(dst, "X") + val x = File(X, "testfilex") + val y = File(X, "testfiley") + + assertThat(x).isFile() + assertThat(y).isFile() + + assertThat(x.length()).isZero() + assertThat(y.readText()).isEqualTo("Xcafebabe\n") + } + } } diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt index 5c7699382..d1bf3554d 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/PullRequest.kt @@ -67,11 +67,13 @@ class PullRequest( remoteFileEntry.isDirectory() -> { throw PullFailedException("Can't pull folder $source: target $destination is a file") } + remoteFileEntry.isRegularFile() || remoteFileEntry.isBlockDevice() || remoteFileEntry.isCharDevice() -> { doPullFile(source, destination, remoteFileEntry.size().toLong(), serial) } + remoteFileEntry.exists() -> { throw PushFailedException( "Source $source exists and is not a directory or a file: mode=${ @@ -81,6 +83,7 @@ class PullRequest( }" ) } + !remoteFileEntry.exists() -> { throw PushFailedException("Source $source doesn't exist") } @@ -88,6 +91,7 @@ class PullRequest( else -> false } } + destination.isDirectory -> { when { remoteFileEntry.isDirectory() -> { @@ -96,12 +100,14 @@ class PullRequest( .last() pullFolder(File(destination, basename), serial) } + remoteFileEntry.isRegularFile() || remoteFileEntry.isBlockDevice() || remoteFileEntry.isCharDevice() -> { val name = source.substringAfterLast(Const.ANDROID_FILE_SEPARATOR) doPullFile(source, File(destination, name), remoteFileEntry.size().toLong(), serial) } + remoteFileEntry.exists() -> { throw PushFailedException( "Source $source exists and is not a directory or a file: mode=${ @@ -111,6 +117,7 @@ class PullRequest( }" ) } + !remoteFileEntry.exists() -> { throw PushFailedException("Source $source doesn't exist") } @@ -118,9 +125,11 @@ class PullRequest( else -> false } } + !destination.exists() -> { pullFolder(destination, serial) } + else -> { throw PushFailedException("Destination $destination is not a directory or a file") } @@ -140,6 +149,15 @@ class PullRequest( for (file in ls.filterNot { Const.SYNC_IGNORED_FILES.contains(it.name) }) { when { file.isDirectory() -> newDirs.add(currentDir + Const.ANDROID_FILE_SEPARATOR + file.name) + file.isRegularFile() && file.size() == 0L.toULong() -> { + val remotePath = currentDir + Const.ANDROID_FILE_SEPARATOR + file.name + val remoteRelativePath = remotePath.substringAfter(source) + val localRelativePath = remoteRelativePath.replace(Const.ANDROID_FILE_SEPARATOR, File.separator) + val local = File(destinationRoot.absolutePath, localRelativePath) + local.parentFile.mkdirs() + local.createNewFile() + } + file.isRegularFile() || file.isCharDevice() || file.isBlockDevice() -> { val remotePath = currentDir + Const.ANDROID_FILE_SEPARATOR + file.name val remoteRelativePath = remotePath.substringAfter(source)