Skip to content

Extend filesystem support #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d9a0e11
Basic FS options
fzhinkin Aug 15, 2023
406c5ac
Implement move on linux
fzhinkin Aug 15, 2023
7e36522
Updated API dump
fzhinkin Aug 15, 2023
54ad37a
Reimplemented tempFileName
fzhinkin Aug 15, 2023
2969314
Add platform-specific Path.parent
fzhinkin Aug 15, 2023
568fefb
Fixed Path.parent behavior
fzhinkin Aug 15, 2023
58c607b
Support mkdirs
fzhinkin Aug 15, 2023
16b6733
Debug test failure
fzhinkin Aug 15, 2023
c2b8770
Debug test failure
fzhinkin Aug 16, 2023
dbbc66f
Fix dirname on Linux
fzhinkin Aug 16, 2023
6296c41
Added some documentation, implemented eq/hc for Path and fixed tests
fzhinkin Aug 16, 2023
5bcc04e
Cleanup
fzhinkin Aug 16, 2023
1f21fa4
Renamed files
fzhinkin Aug 16, 2023
5a7eb00
Cleanup
fzhinkin Aug 16, 2023
e8640ec
Improve exception message
fzhinkin Aug 16, 2023
7cae417
Fixed test
fzhinkin Aug 16, 2023
eb9293f
Fixed test failures on Windows
fzhinkin Aug 17, 2023
1c7150a
Support Path.name, Path.isAbsolute and path metadata retrieval
fzhinkin Aug 17, 2023
e4c3f8e
Throw FileNotFoundException where applicable
fzhinkin Aug 17, 2023
93f6387
Fix path handling on Windows
fzhinkin Aug 17, 2023
e6e8f66
Updated documentation
fzhinkin Aug 18, 2023
ce99021
Fixed concatenation
fzhinkin Aug 18, 2023
5ec5c5a
Seal FileSystem interface
fzhinkin Aug 18, 2023
63385d2
Update Api
fzhinkin Aug 18, 2023
d664d37
Fixed typos
fzhinkin Aug 23, 2023
87d45f8
Support file size retrieval
fzhinkin Aug 23, 2023
1534d3e
Stub Wasm FS implementation
fzhinkin Sep 1, 2023
70b706f
Renamed test methods
fzhinkin Sep 1, 2023
aad5f56
Sanity test for Path::equals
fzhinkin Sep 1, 2023
ff6ec3d
Fixed/clarified KDoc and added/fixed related tests
fzhinkin Sep 1, 2023
a23f789
Make temporaryDir independent of a particular FS instance
fzhinkin Sep 1, 2023
76506b0
Cleanup
fzhinkin Sep 1, 2023
7ba61cb
Use anonymous system FS subclasses
fzhinkin Sep 1, 2023
15e94ed
Cleanup
fzhinkin Sep 1, 2023
73feef4
Supported append-to-file mode for sinks, changes sink/source signatures
fzhinkin Sep 1, 2023
5dd47e1
Make Path.source/sink regular functions, not expects.
fzhinkin Sep 1, 2023
a086319
Improve move docs and add tests
fzhinkin Sep 1, 2023
82230d4
Updated doc, removed some checks from the atomicMoveDir test
fzhinkin Sep 1, 2023
8ce1616
Improved documentation
fzhinkin Sep 11, 2023
e31befe
Throw exception when createDirectories failed because path exists and…
fzhinkin Sep 11, 2023
1914297
Move Path.separator, FS.SystemFS and FS.SystemTempDir to top-level co…
fzhinkin Sep 12, 2023
6596964
Cleanup
fzhinkin Sep 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,35 @@ kotlin {

configureNativePlatforms()

val nativeTargets = nativeTargets()
val appleTargets = appleTargets()
val mingwTargets = mingwTargets()

/*
Native source sets hierarchy:
native
|-> apple
|-> nonApple
|-> mingw
|-> unix
|-> linux
|-> android
*/

sourceSets {
val nativeMain = createSourceSet("nativeMain", parent = commonMain.get(), children = nativeTargets)
val nativeTest = createSourceSet("nativeTest", parent = commonTest.get(), children = nativeTargets)
val nativeMain = createSourceSet("nativeMain", parent = commonMain.get())
val nativeTest = createSourceSet("nativeTest", parent = commonTest.get())
val nonAppleMain = createSourceSet("nonAppleMain", parent = nativeMain)
val nonAppleTest = createSourceSet("nonAppleTest", parent = nativeTest)
createSourceSet("appleMain", parent = nativeMain, children = appleTargets)
createSourceSet("appleTest", parent = nativeTest, children = appleTargets)
createSourceSet("mingwMain", parent = nonAppleMain, children = mingwTargets)
createSourceSet("mingwTest", parent = nonAppleTest, children = mingwTargets)
val unixMain = createSourceSet("unixMain", parent = nonAppleMain)
val unixTest = createSourceSet("unixTest", parent = nonAppleTest)
createSourceSet("linuxMain", parent = unixMain, children = linuxTargets())
createSourceSet("linuxTest", parent = unixTest, children = linuxTargets())
createSourceSet("androidMain", parent = unixMain, children = androidTargets())
createSourceSet("androidTest", parent = unixTest, children = androidTargets())
}
}

Expand Down Expand Up @@ -137,10 +159,6 @@ fun KotlinMultiplatformExtension.configureNativePlatforms() {
mingwX64()
}

fun nativeTargets(): List<String> {
return linuxTargets() + mingwTargets() + androidTargets()
}

fun appleTargets() = listOf(
"iosArm64",
"iosX64",
Expand Down
23 changes: 23 additions & 0 deletions core/android/src/files/FileSystemAndroid.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

package kotlinx.io.files

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKString
import platform.posix.__posix_basename
import platform.posix.dirname

@OptIn(ExperimentalForeignApi::class)
internal actual fun dirnameImpl(path: String): String {
return dirname(path)?.toKString() ?: ""
}

@OptIn(ExperimentalForeignApi::class)
internal actual fun basenameImpl(path: String): String {
return __posix_basename(path)?.toKString() ?: ""
}

internal actual fun isAbsoluteImpl(path: String): Boolean = path.startsWith('/')
43 changes: 42 additions & 1 deletion core/api/kotlinx-io-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,53 @@ public final class kotlinx/io/Utf8Kt {
public static synthetic fun writeString$default (Lkotlinx/io/Sink;Ljava/lang/String;IIILjava/lang/Object;)V
}

public final class kotlinx/io/files/FileMetadata {
public fun <init> ()V
public fun <init> (ZZJ)V
public synthetic fun <init> (ZZJILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getSize ()J
public final fun isDirectory ()Z
public final fun isRegularFile ()Z
}

public abstract interface class kotlinx/io/files/FileSystem {
public abstract fun atomicMove (Lkotlinx/io/files/Path;Lkotlinx/io/files/Path;)V
public abstract fun createDirectories (Lkotlinx/io/files/Path;Z)V
public static synthetic fun createDirectories$default (Lkotlinx/io/files/FileSystem;Lkotlinx/io/files/Path;ZILjava/lang/Object;)V
public abstract fun delete (Lkotlinx/io/files/Path;Z)V
public static synthetic fun delete$default (Lkotlinx/io/files/FileSystem;Lkotlinx/io/files/Path;ZILjava/lang/Object;)V
public abstract fun exists (Lkotlinx/io/files/Path;)Z
public abstract fun metadataOrNull (Lkotlinx/io/files/Path;)Lkotlinx/io/files/FileMetadata;
public abstract fun sink (Lkotlinx/io/files/Path;Z)Lkotlinx/io/RawSink;
public static synthetic fun sink$default (Lkotlinx/io/files/FileSystem;Lkotlinx/io/files/Path;ZILjava/lang/Object;)Lkotlinx/io/RawSink;
public abstract fun source (Lkotlinx/io/files/Path;)Lkotlinx/io/RawSource;
}

public final class kotlinx/io/files/FileSystemJvmKt {
public static final field SystemFileSystem Lkotlinx/io/files/FileSystem;
public static final field SystemTemporaryDirectory Lkotlinx/io/files/Path;
}

public final class kotlinx/io/files/Path {
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public final fun getParent ()Lkotlinx/io/files/Path;
public fun hashCode ()I
public final fun isAbsolute ()Z
public fun toString ()Ljava/lang/String;
}

public final class kotlinx/io/files/PathsKt {
public final class kotlinx/io/files/PathsJvmKt {
public static final field SystemPathSeparator C
public static final fun Path (Ljava/lang/String;)Lkotlinx/io/files/Path;
public static final fun sink (Lkotlinx/io/files/Path;)Lkotlinx/io/Sink;
public static final fun source (Lkotlinx/io/files/Path;)Lkotlinx/io/Source;
}

public final class kotlinx/io/files/PathsKt {
public static final fun Path (Ljava/lang/String;[Ljava/lang/String;)Lkotlinx/io/files/Path;
public static final fun Path (Lkotlinx/io/files/Path;[Ljava/lang/String;)Lkotlinx/io/files/Path;
public static final fun sinkDeprecated (Lkotlinx/io/files/Path;)Lkotlinx/io/Sink;
public static final fun sourceDeprecated (Lkotlinx/io/files/Path;)Lkotlinx/io/Source;
}

45 changes: 45 additions & 0 deletions core/apple/src/files/FileSystemApple.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
@file:OptIn(ExperimentalForeignApi::class)

package kotlinx.io.files

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toKString
import kotlinx.io.IOException
import platform.Foundation.NSTemporaryDirectory
import platform.posix.*


internal actual fun atomicMoveImpl(source: Path, destination: Path) {
if (rename(source.path, destination.path) != 0) {
throw IOException("Move failed: ${strerror(errno)?.toKString()}")
}
}

public actual val SystemTemporaryDirectory: Path
get() = Path(NSTemporaryDirectory())

internal actual fun dirnameImpl(path: String): String {
memScoped {
return dirname(path.cstr.ptr)?.toKString() ?: ""
}
}

internal actual fun basenameImpl(path: String): String {
memScoped {
return basename(path.cstr.ptr)?.toKString() ?: ""
}
}

internal actual fun isAbsoluteImpl(path: String): Boolean = path.startsWith('/')

internal actual fun mkdirImpl(path: String) {
if (mkdir(path, PermissionAllowAll) != 0) {
throw IOException("mkdir failed: ${strerror(errno)?.toKString()}")
}
}
12 changes: 4 additions & 8 deletions core/apple/test/NSInputStreamSourceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
package kotlinx.io

import kotlinx.io.files.Path
import kotlinx.io.files.sink
import kotlinx.io.files.SystemFileSystem
import platform.Foundation.NSInputStream
import platform.Foundation.NSTemporaryDirectory
import platform.Foundation.NSURL
import platform.Foundation.NSUUID
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
Expand All @@ -28,11 +26,9 @@ class NSInputStreamSourceTest {
@OptIn(ExperimentalStdlibApi::class)
@Test
fun nsInputStreamSourceFromFile() {
// can be replaced with createTempFile() when #183 is fixed
// https://github.com/Kotlin/kotlinx-io/issues/183
val file = "${NSTemporaryDirectory()}${NSUUID().UUIDString()}"
val file = tempFileName()
try {
Path(file).sink().use {
SystemFileSystem.sink(Path(file)).buffered().use {
it.writeString("example")
}

Expand All @@ -42,7 +38,7 @@ class NSInputStreamSourceTest {
assertEquals(7, source.readAtMostTo(buffer, 10))
assertEquals("example", buffer.readString())
} finally {
deleteFile(file)
SystemFileSystem.delete(Path(file))
}
}

Expand Down
4 changes: 4 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ tasks.withType<DokkaTaskPartial>().configureEach {
)
}
}

animalsniffer {
annotation = "kotlinx.io.files.AnimalSnifferIgnore"
}
8 changes: 7 additions & 1 deletion core/common/src/-CommonPlatform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ package kotlinx.io

internal expect fun String.asUtf8ToByteArray(): ByteArray

/**
* Signals about a general issue occurred during I/O operation.
*/
public expect open class IOException(message: String?, cause: Throwable?) : Exception {
public constructor(message: String? = null)
}

/**
* Signals that the end of the file or stream was reached unexpectedly during an input operation.
*/
public expect open class EOFException(message: String? = null) : IOException


Expand All @@ -35,4 +41,4 @@ public expect open class EOFException(message: String? = null) : IOException
// This is a workaround that should be removed as soon as stdlib will support AutoCloseable
// actual typealias on JVM.
@OptIn(ExperimentalStdlibApi::class)
internal typealias AutoCloseableAlias = AutoCloseable
internal typealias AutoCloseableAlias = AutoCloseable
Loading