Skip to content

Commit 35ef3a1

Browse files
committed
Implement PlatformNative (except for getAllEnvVars), add deleteFile to Filesystem interface
1 parent 9c6b231 commit 35ef3a1

File tree

5 files changed

+131
-31
lines changed

5 files changed

+131
-31
lines changed

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/util/Filesystem.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ public interface Filesystem {
3131
*/
3232
public suspend fun writeFile(path: String, data: ByteArray)
3333

34+
/**
35+
* Delete the file, if it exists.
36+
* @param path fully qualified path encoded specifically to the target platform's filesystem
37+
*/
38+
public suspend fun deleteFile(path: String)
39+
3440
/**
3541
* Check if a file exists at the [path].
3642
* @param path fully qualified path encoded specifically to the target platform's filesystem
@@ -54,5 +60,7 @@ internal class MapFilesystem(
5460
override suspend fun writeFile(path: String, data: ByteArray) {
5561
memFs[path] = data
5662
}
63+
64+
override suspend fun deleteFile(path: String) { memFs.remove(path) }
5765
override fun fileExists(path: String): Boolean = memFs[path] != null
5866
}

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/util/Platform.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ internal expect object SystemDefaultProvider : PlatformProvider {
4343
override fun getenv(key: String): String?
4444
override suspend fun readFileOrNull(path: String): ByteArray?
4545
override suspend fun writeFile(path: String, data: ByteArray)
46+
override suspend fun deleteFile(path: String)
4647
override val isJvm: Boolean
4748
override val isAndroid: Boolean
4849
override val isBrowser: Boolean
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.smithy.kotlin.runtime.util
6+
7+
import kotlinx.coroutines.test.runTest
8+
import kotlin.test.Test
9+
import kotlin.test.assertContentEquals
10+
import kotlin.test.assertNotEquals
11+
import kotlin.test.assertNotNull
12+
import kotlin.test.assertNull
13+
import kotlin.test.assertTrue
14+
15+
class PlatformTest {
16+
@Test
17+
fun testReadWriteFile() = runTest {
18+
val ps = PlatformProvider.System
19+
val path = "file.txt"
20+
val expected = "Hello, File!".encodeToByteArray()
21+
22+
try {
23+
ps.writeFile(path, expected)
24+
25+
assertTrue(ps.fileExists(path))
26+
27+
val actual = ps.readFileOrNull(path)
28+
assertContentEquals(expected, actual)
29+
} finally {
30+
ps.deleteFile(path)
31+
}
32+
}
33+
34+
@Test
35+
fun testGetEnv() = runTest {
36+
assertNotNull(PlatformProvider.System.getenv("PATH"))
37+
assertNull(PlatformProvider.System.getenv("THIS_ENV_VAR_IS_NOT_SET"))
38+
}
39+
40+
@Test
41+
fun testOsInfo() = runTest {
42+
val osInfo = PlatformProvider.System.osInfo()
43+
assertNotEquals(OsFamily.Unknown, osInfo.family)
44+
}
45+
}

runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/util/PlatformJVM.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ internal actual object SystemDefaultProvider : PlatformProvider {
4848
}
4949
}
5050

51+
actual override suspend fun deleteFile(path: String) {
52+
withContext(Dispatchers.IO) {
53+
File(path).delete()
54+
}
55+
}
56+
5157
actual override fun fileExists(path: String): Boolean = File(path).exists()
5258

5359
public suspend fun readFileOrNull(path: Path): ByteArray? = readFileOrNull(path.toAbsolutePath().toString())

runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/util/PlatformNative.kt

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,90 @@
44
*/
55
package aws.smithy.kotlin.runtime.util
66

7+
import aws.smithy.kotlin.runtime.io.IOException
8+
import kotlinx.cinterop.*
9+
import platform.posix.*
10+
711
internal actual object SystemDefaultProvider : PlatformProvider {
8-
actual override fun getAllEnvVars(): Map<String, String> {
9-
TODO("Not yet implemented")
10-
}
12+
// FIXME How to get all environment variables on Native?
13+
// See if it's possible to get extern char **environ loaded... is not available by default in platform.posix.*
14+
// https://man7.org/linux/man-pages/man7/environ.7.html
15+
actual override fun getAllEnvVars(): Map<String, String> = mapOf<String, String>()
1116

12-
actual override fun getenv(key: String): String? {
13-
TODO("Not yet implemented")
14-
}
17+
actual override fun getenv(key: String): String? = platform.posix.getenv(key)?.toKString()
1518

1619
actual override val filePathSeparator: String
17-
get() = TODO("Not yet implemented")
20+
get() = "/" // Unix-style separator is used in Native
1821

1922
actual override suspend fun readFileOrNull(path: String): ByteArray? {
20-
TODO("Not yet implemented")
23+
return try {
24+
val file = fopen(path, "rb") ?: return null
25+
26+
try {
27+
// Get file size
28+
fseek(file, 0L, SEEK_END)
29+
val size = ftell(file)
30+
fseek(file, 0L, SEEK_SET)
31+
32+
// Read file content
33+
val buffer = ByteArray(size.toInt()).pin()
34+
val rc = fread(buffer.addressOf(0), 1.toULong(), size.toULong(), file)
35+
if (rc == size.toULong()) buffer.get() else null
36+
} finally {
37+
fclose(file)
38+
}
39+
} catch (e: Exception) {
40+
null
41+
}
2142
}
2243

2344
actual override suspend fun writeFile(path: String, data: ByteArray) {
24-
TODO("Not yet implemented")
45+
val file = fopen(path, "wb") ?: throw IOException("Cannot open file for writing: $path")
46+
try {
47+
val wc = fwrite(data.refTo(0), 1.toULong(), data.size.toULong(), file)
48+
if (wc != data.size.toULong()) {
49+
throw IOException("Failed to write all bytes to file $path, expected ${data.size.toLong()}, wrote $wc")
50+
}
51+
} finally {
52+
fclose(file)
53+
}
2554
}
2655

27-
actual override fun fileExists(path: String): Boolean {
28-
TODO("Not yet implemented")
29-
}
56+
actual override suspend fun deleteFile(path: String) { remove(path) }
3057

31-
actual override fun osInfo(): OperatingSystem {
32-
TODO("Not yet implemented")
33-
}
58+
actual override fun fileExists(path: String): Boolean = access(path, F_OK) == 0
3459

35-
actual override val isJvm: Boolean
36-
get() = TODO("Not yet implemented")
37-
actual override val isAndroid: Boolean
38-
get() = TODO("Not yet implemented")
39-
actual override val isBrowser: Boolean
40-
get() = TODO("Not yet implemented")
41-
actual override val isNode: Boolean
42-
get() = TODO("Not yet implemented")
43-
actual override val isNative: Boolean
44-
get() = TODO("Not yet implemented")
45-
46-
actual override fun getAllProperties(): Map<String, String> {
47-
TODO("Not yet implemented")
48-
}
60+
actual override fun osInfo(): OperatingSystem = memScoped {
61+
val utsname = alloc<utsname>()
62+
uname(utsname.ptr)
63+
64+
val sysName = utsname.sysname.toKString().lowercase()
65+
val version = utsname.release.toKString()
66+
val machine = utsname.machine.toKString() // Helps differentiate iOS/macOS
4967

50-
actual override fun getProperty(key: String): String? {
51-
TODO("Not yet implemented")
68+
val family = when {
69+
sysName.contains("darwin") -> {
70+
if (machine.startsWith("iPhone") || machine.startsWith("iPad")) {
71+
OsFamily.Ios
72+
} else {
73+
OsFamily.MacOs
74+
}
75+
}
76+
sysName.contains("linux") -> OsFamily.Linux
77+
sysName.contains("windows") -> OsFamily.Windows
78+
else -> OsFamily.Unknown
79+
}
80+
81+
return OperatingSystem(family, version)
5282
}
83+
84+
actual override val isJvm: Boolean = false
85+
actual override val isAndroid: Boolean = false
86+
actual override val isBrowser: Boolean = false
87+
actual override val isNode: Boolean = false
88+
actual override val isNative: Boolean = true
89+
90+
// Kotlin/Native doesn't have system properties
91+
actual override fun getAllProperties(): Map<String, String> = emptyMap()
92+
actual override fun getProperty(key: String): String? = null
5393
}

0 commit comments

Comments
 (0)