Skip to content

Commit 270436b

Browse files
committed
feat(core-file): ensure Uri is used for the FileSystemManager
1 parent e6a2853 commit 270436b

File tree

9 files changed

+46
-37
lines changed

9 files changed

+46
-37
lines changed

core/file/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ android {
99
kotlin {
1010
sourceSets {
1111
commonMain.dependencies {
12+
api(libs.uri)
13+
1214
implementation(projects.core.outcome)
1315

14-
implementation(libs.uri)
1516
implementation(libs.kotlinx.io.core)
1617
}
1718
androidUnitTest.dependencies {
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package net.thunderbird.core.file
22

33
import android.content.ContentResolver
4-
import android.net.Uri
5-
import androidx.core.net.toUri
4+
import com.eygraber.uri.Uri
5+
import com.eygraber.uri.toAndroidUri
66
import kotlinx.io.RawSink
77
import kotlinx.io.RawSource
88
import kotlinx.io.asSink
@@ -14,14 +14,12 @@ import kotlinx.io.asSource
1414
class AndroidFileSystemManager(
1515
private val contentResolver: ContentResolver,
1616
) : FileSystemManager {
17-
override fun openSink(uriString: String): RawSink? {
18-
val uri: Uri = uriString.toUri()
17+
override fun openSink(uri: Uri): RawSink? {
1918
// Use truncate/overwrite mode by default
20-
return contentResolver.openOutputStream(uri, "wt")?.asSink()
19+
return contentResolver.openOutputStream(uri.toAndroidUri(), "wt")?.asSink()
2120
}
2221

23-
override fun openSource(uriString: String): RawSource? {
24-
val uri: Uri = uriString.toUri()
25-
return contentResolver.openInputStream(uri)?.asSource()
22+
override fun openSource(uri: Uri): RawSource? {
23+
return contentResolver.openInputStream(uri.toAndroidUri())?.asSource()
2624
}
2725
}

core/file/src/androidUnitTest/kotlin/net/thunderbird/core/file/AndroidFileSystemManagerTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import android.net.Uri
55
import assertk.assertThat
66
import assertk.assertions.isEqualTo
7+
import com.eygraber.uri.toKmpUri
78
import kotlinx.io.Buffer
89
import org.junit.Rule
910
import org.junit.Test
@@ -33,13 +34,13 @@ class AndroidFileSystemManagerTest {
3334
val testText = "Hello Thunderbird Android!"
3435

3536
// Act
36-
val sink = checkNotNull(testSubject.openSink(uri.toString()))
37+
val sink = checkNotNull(testSubject.openSink(uri.toKmpUri()))
3738
val writeBuffer = Buffer().apply { write(testText.encodeToByteArray()) }
3839
sink.write(writeBuffer, writeBuffer.size)
3940
sink.flush()
4041
sink.close()
4142

42-
val source = checkNotNull(testSubject.openSource(uri.toString()))
43+
val source = checkNotNull(testSubject.openSource(uri.toKmpUri()))
4344
val readBuffer = Buffer()
4445
source.readAtMostTo(readBuffer, 1024)
4546
val bytes = ByteArray(readBuffer.size.toInt())

core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileSystemManager.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.thunderbird.core.file
22

3+
import com.eygraber.uri.Uri
34
import kotlinx.io.RawSink
45
import kotlinx.io.RawSource
56

@@ -12,16 +13,16 @@ interface FileSystemManager {
1213
*
1314
* Implementations should open the destination for writing in overwrite/truncate mode.
1415
*
15-
* @param uriString The URI string to open a sink for
16+
* @param uri The URI to open a sink for
1617
* @return A sink for writing to the URI, or null if the URI couldn't be opened
1718
*/
18-
fun openSink(uriString: String): RawSink?
19+
fun openSink(uri: Uri): RawSink?
1920

2021
/**
2122
* Opens a source for reading from a URI.
2223
*
23-
* @param uriString The URI string to open a source for
24+
* @param uri The URI to open a source for
2425
* @return A source for reading from the URI, or null if the URI couldn't be opened
2526
*/
26-
fun openSource(uriString: String): RawSource?
27+
fun openSource(uri: Uri): RawSource?
2728
}

core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/CopyCommand.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ internal class CopyCommand(
1515
) : FileCommand<Unit> {
1616
override suspend fun invoke(fs: FileSystemManager): Outcome<Unit, FileOperationError> {
1717
// Open endpoints
18-
val source = fs.openSource(sourceUri.toString())
18+
val source = fs.openSource(sourceUri)
1919
?: return Outcome.Failure(
2020
FileOperationError.Unavailable(sourceUri, "Unable to open source: $sourceUri"),
2121
)
22-
val sink = fs.openSink(destinationUri.toString())
22+
val sink = fs.openSink(destinationUri)
2323
?: return Outcome.Failure(
2424
FileOperationError.Unavailable(destinationUri, "Unable to open destination: $destinationUri"),
2525
)
@@ -29,31 +29,31 @@ internal class CopyCommand(
2929
while (true) {
3030
val read = try {
3131
source.readAtMostTo(buffer, BUFFER_SIZE)
32-
} catch (t: Throwable) {
33-
return Outcome.Failure(FileOperationError.ReadFailed(sourceUri, t.message), cause = t)
32+
} catch (e: Exception) {
33+
return Outcome.Failure(FileOperationError.ReadFailed(sourceUri, e.message), cause = e)
3434
}
3535
if (read <= 0L) break
3636
try {
3737
sink.write(buffer, read)
38-
} catch (t: Throwable) {
39-
return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, t.message), cause = t)
38+
} catch (e: Exception) {
39+
return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, e.message), cause = e)
4040
}
4141
}
4242
try {
4343
sink.flush()
44-
} catch (t: Throwable) {
45-
return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, t.message), cause = t)
44+
} catch (e: Exception) {
45+
return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, e.message), cause = e)
4646
}
4747
Outcome.Success(Unit)
48-
} catch (t: Throwable) {
49-
Outcome.Failure(FileOperationError.Unknown(t.message), cause = t)
48+
} catch (e: Exception) {
49+
Outcome.Failure(FileOperationError.Unknown(e.message), cause = e)
5050
} finally {
5151
try {
5252
source.close()
53-
} catch (_: Throwable) {}
53+
} catch (_: Exception) {}
5454
try {
5555
sink.close()
56-
} catch (_: Throwable) {}
56+
} catch (_: Exception) {}
5757
}
5858
}
5959

core/file/src/commonTest/kotlin/net/thunderbird/core/file/FakeFileSystemManager.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.thunderbird.core.file
22

3+
import com.eygraber.uri.Uri
34
import kotlinx.io.Buffer
45
import kotlinx.io.RawSink
56
import kotlinx.io.RawSource
@@ -12,7 +13,8 @@ class FakeFileSystemManager : FileSystemManager {
1213

1314
private val storage = mutableMapOf<String, ByteArray>()
1415

15-
override fun openSink(uriString: String): RawSink? {
16+
override fun openSink(uri: Uri): RawSink? {
17+
val key = uri.toString()
1618
return object : RawSink {
1719
private val collected = mutableListOf<Byte>()
1820

@@ -26,7 +28,7 @@ class FakeFileSystemManager : FileSystemManager {
2628
}
2729

2830
override fun flush() {
29-
storage[uriString] = collected.toByteArray()
31+
storage[key] = collected.toByteArray()
3032
}
3133

3234
override fun close() {
@@ -36,8 +38,9 @@ class FakeFileSystemManager : FileSystemManager {
3638
}
3739
}
3840

39-
override fun openSource(uriString: String): RawSource? {
40-
val bytes = storage[uriString] ?: return null
41+
override fun openSource(uri: Uri): RawSource? {
42+
val key = uri.toString()
43+
val bytes = storage[key] ?: return null
4144
return object : RawSource {
4245
private val buffer = Buffer().apply { write(bytes) }
4346
override fun readAtMostTo(sink: Buffer, byteCount: Long): Long {

core/file/src/jvmMain/kotlin/net/thunderbird/core/file/JvmFileSystemManager.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package net.thunderbird.core.file
22

3+
import com.eygraber.uri.Uri
4+
import com.eygraber.uri.toURI
35
import java.io.File
46
import java.io.FileInputStream
57
import java.io.FileOutputStream
@@ -12,10 +14,10 @@ import kotlinx.io.asSource
1214
* JVM implementation of [FileSystemManager] using java.io streams.
1315
*/
1416
class JvmFileSystemManager : FileSystemManager {
15-
override fun openSink(uriString: String): RawSink? {
17+
override fun openSink(uri: Uri): RawSink? {
1618
// Only support simple file paths for JVM implementation
1719
return try {
18-
val file = File(uriString)
20+
val file = File(uri.toURI())
1921
// create parent directories if necessary
2022
file.parentFile?.mkdirs()
2123
val append = false // overwrite/truncate by default
@@ -25,9 +27,9 @@ class JvmFileSystemManager : FileSystemManager {
2527
}
2628
}
2729

28-
override fun openSource(uriString: String): RawSource? {
30+
override fun openSource(uri: Uri): RawSource? {
2931
return try {
30-
val file = File(uriString)
32+
val file = File(uri.toURI())
3133
FileInputStream(file).asSource()
3234
} catch (_: Throwable) {
3335
null

core/file/src/jvmTest/kotlin/net/thunderbird/core/file/JvmFileSystemManagerTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.thunderbird.core.file
22

33
import assertk.assertThat
44
import assertk.assertions.isEqualTo
5+
import com.eygraber.uri.Uri
56
import java.io.File
67
import kotlinx.io.Buffer
78
import org.junit.Rule
@@ -21,15 +22,16 @@ class JvmFileSystemManagerTest {
2122
// Arrange
2223
val tempFile: File = folder.newFile("tb-file-fs-test.txt")
2324
val testText = "Hello Thunderbird!"
24-
val sink = checkNotNull(testSubject.openSink(tempFile.absolutePath))
25+
val uri = Uri.parse(tempFile.toURI().toString())
26+
val sink = checkNotNull(testSubject.openSink(uri))
2527

2628
// Act
2729
val writeBuffer = Buffer().apply { write(testText.encodeToByteArray()) }
2830
sink.write(writeBuffer, writeBuffer.size)
2931
sink.flush()
3032
sink.close()
3133

32-
val source = checkNotNull(testSubject.openSource(tempFile.absolutePath))
34+
val source = checkNotNull(testSubject.openSource(uri))
3335
val readBuffer = Buffer()
3436
source.readAtMostTo(readBuffer, 1024)
3537
val bytes = ByteArray(readBuffer.size.toInt())

legacy/ui/legacy/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ dependencies {
6969
implementation(libs.mime4j.core)
7070
implementation(libs.kotlinx.coroutines.core)
7171
implementation(libs.kotlinx.coroutines.android)
72+
implementation(libs.uri)
7273

7374
implementation(libs.glide)
7475
annotationProcessor(libs.glide.compiler)

0 commit comments

Comments
 (0)