From 78666e3ecb2bf0d9087dd8e5d00c401a87ad83fb Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Fri, 24 Jun 2022 11:06:47 +0300 Subject: [PATCH] Provide visit extension functions for java.nio.file.Path #KT-52910 --- .../src/kotlin/io/path/FileVisitorBuilder.kt | 119 +++++++ .../jdk7/src/kotlin/io/path/PathUtils.kt | 114 ++++++ .../jdk7/test/FileVisitorBuilderTest.kt | 335 ++++++++++++++++++ .../kotlin-stdlib-jdk7.txt | 12 + 4 files changed, 580 insertions(+) create mode 100644 libraries/stdlib/jdk7/src/kotlin/io/path/FileVisitorBuilder.kt create mode 100644 libraries/stdlib/jdk7/test/FileVisitorBuilderTest.kt diff --git a/libraries/stdlib/jdk7/src/kotlin/io/path/FileVisitorBuilder.kt b/libraries/stdlib/jdk7/src/kotlin/io/path/FileVisitorBuilder.kt new file mode 100644 index 00000000000..149663a0120 --- /dev/null +++ b/libraries/stdlib/jdk7/src/kotlin/io/path/FileVisitorBuilder.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2010-2022 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/LICENSE.txt file. + */ + +package kotlin.io.path + +import java.io.IOException +import java.nio.file.FileVisitResult +import java.nio.file.FileVisitor +import java.nio.file.Path +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes + +/** + * The builder to provide implementation of the file visitor that [fileVisitor] builds. + */ +@ExperimentalPathApi +@SinceKotlin("1.7") +public sealed interface FileVisitorBuilder { + /** + * Overrides the corresponding function of the built file visitor with the provided [function]. + * + * By default, [FileVisitor.preVisitDirectory] of the built file visitor returns [FileVisitResult.CONTINUE]. + */ + public fun onPreVisitDirectory(function: (directory: Path, attributes: BasicFileAttributes) -> FileVisitResult): Unit + + /** + * Overrides the corresponding function of the built file visitor with the provided [function]. + * + * By default, [FileVisitor.visitFile] of the built file visitor returns [FileVisitResult.CONTINUE]. + */ + public fun onVisitFile(function: (file: Path, attributes: BasicFileAttributes) -> FileVisitResult): Unit + + /** + * Overrides the corresponding function of the built file visitor with the provided [function]. + * + * By default, [FileVisitor.visitFileFailed] of the built file visitor re-throws the I/O exception + * that prevented the file from being visited. + */ + public fun onVisitFileFailed(function: (file: Path, exception: IOException) -> FileVisitResult): Unit + + /** + * Overrides the corresponding function of the built file visitor with the provided [function]. + * + * By default, if the directory iteration completes without an I/O exception, + * [FileVisitor.postVisitDirectory] of the built file visitor returns [FileVisitResult.CONTINUE]; + * otherwise it re-throws the I/O exception that caused the iteration of the directory to terminate prematurely. + */ + public fun onPostVisitDirectory(function: (directory: Path, exception: IOException?) -> FileVisitResult): Unit +} + + +@ExperimentalPathApi +internal class FileVisitorBuilderImpl : FileVisitorBuilder { + private var onPreVisitDirectory: ((Path, BasicFileAttributes) -> FileVisitResult)? = null + private var onVisitFile: ((Path, BasicFileAttributes) -> FileVisitResult)? = null + private var onVisitFileFailed: ((Path, IOException) -> FileVisitResult)? = null + private var onPostVisitDirectory: ((Path, IOException?) -> FileVisitResult)? = null + private var isBuilt: Boolean = false + + override fun onPreVisitDirectory(function: (directory: Path, attributes: BasicFileAttributes) -> FileVisitResult): Unit { + checkIsNotBuilt() + checkNotDefined(onPreVisitDirectory, "onPreVisitDirectory") + onPreVisitDirectory = function + } + + override fun onVisitFile(function: (file: Path, attributes: BasicFileAttributes) -> FileVisitResult): Unit { + checkIsNotBuilt() + checkNotDefined(onVisitFile, "onVisitFile") + onVisitFile = function + } + + override fun onVisitFileFailed(function: (file: Path, exception: IOException) -> FileVisitResult): Unit { + checkIsNotBuilt() + checkNotDefined(onVisitFileFailed, "onVisitFileFailed") + onVisitFileFailed = function + } + + override fun onPostVisitDirectory(function: (directory: Path, exception: IOException?) -> FileVisitResult): Unit { + checkIsNotBuilt() + checkNotDefined(onPostVisitDirectory, "onPostVisitDirectory") + onPostVisitDirectory = function + } + + fun build(): FileVisitor { + checkIsNotBuilt() + isBuilt = true + return FileVisitorImpl(onPreVisitDirectory, onVisitFile, onVisitFileFailed, onPostVisitDirectory) + } + + private fun checkIsNotBuilt() { + if (isBuilt) throw IllegalStateException("This builder was already built") + } + + private fun checkNotDefined(function: Any?, name: String) { + if (function != null) throw IllegalStateException("$name was already defined") + } +} + + +private class FileVisitorImpl( + private val onPreVisitDirectory: ((Path, BasicFileAttributes) -> FileVisitResult)?, + private val onVisitFile: ((Path, BasicFileAttributes) -> FileVisitResult)?, + private val onVisitFileFailed: ((Path, IOException) -> FileVisitResult)?, + private val onPostVisitDirectory: ((Path, IOException?) -> FileVisitResult)?, +) : SimpleFileVisitor() { + override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult = + this.onPreVisitDirectory?.invoke(dir, attrs) ?: super.preVisitDirectory(dir, attrs) + + override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = + this.onVisitFile?.invoke(file, attrs) ?: super.visitFile(file, attrs) + + override fun visitFileFailed(file: Path, exc: IOException): FileVisitResult = + this.onVisitFileFailed?.invoke(file, exc) ?: super.visitFileFailed(file, exc) + + override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult = + this.onPostVisitDirectory?.invoke(dir, exc) ?: super.postVisitDirectory(dir, exc) +} diff --git a/libraries/stdlib/jdk7/src/kotlin/io/path/PathUtils.kt b/libraries/stdlib/jdk7/src/kotlin/io/path/PathUtils.kt index 48cd8c8d422..cfe6aee2d1b 100644 --- a/libraries/stdlib/jdk7/src/kotlin/io/path/PathUtils.kt +++ b/libraries/stdlib/jdk7/src/kotlin/io/path/PathUtils.kt @@ -15,6 +15,8 @@ import java.nio.file.* import java.nio.file.FileAlreadyExistsException import java.nio.file.NoSuchFileException import java.nio.file.attribute.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.jvm.Throws /** @@ -1015,3 +1017,115 @@ public inline fun URI.toPath(): Path = @ExperimentalPathApi @SinceKotlin("1.7") public fun Path.walk(vararg options: PathWalkOption): Sequence = PathTreeWalk(this, options) + +/** + * Visits this directory and all its content with the specified [visitor]. + * + * The traversal is in depth-first order and starts at this directory. The specified [visitor] is invoked on each file encountered. + * + * @param visitor the [FileVisitor] that receives callbacks. + * @param maxDepth the maximum depth to traverse. By default, there is no limit. + * @param followLinks specifies whether to follow symbolic links, `false` by default. + * + * @see Files.walkFileTree + */ +@ExperimentalPathApi +@SinceKotlin("1.7") +public fun Path.visitFileTree(visitor: FileVisitor, maxDepth: Int = Int.MAX_VALUE, followLinks: Boolean = false): Unit { + val options = if (followLinks) setOf(FileVisitOption.FOLLOW_LINKS) else setOf() + Files.walkFileTree(this, options, maxDepth, visitor) +} + +/** + * Visits this directory and all its content with the [FileVisitor] defined in [builderAction]. + * + * This function works the same as [Path.visitFileTree]. It is introduced to streamline + * the cases when a [FileVisitor] is created only to be immediately used for a file tree traversal. + * The trailing lambda [builderAction] is passed to [fileVisitor] to get the file visitor. + * + * Example: + * + * ``` kotlin + * projectDirectory.visitFileTree { + * onPreVisitDirectory { directory, _ -> + * if (directory.name == "build") { + * directory.toFile().deleteRecursively() + * FileVisitResult.SKIP_SUBTREE + * } else { + * FileVisitResult.CONTINUE + * } + * } + * + * onVisitFile { file, _ -> + * if (file.extension == "class") { + * file.deleteExisting() + * } + * FileVisitResult.CONTINUE + * } + * } + * ``` + * + * @param maxDepth the maximum depth to traverse. By default, there is no limit. + * @param followLinks specifies whether to follow symbolic links, `false` by default. + * @param builderAction the function that defines [FileVisitor]. + * + * @see Path.visitFileTree + * @see fileVisitor + */ +@ExperimentalPathApi +@SinceKotlin("1.7") +public fun Path.visitFileTree( + maxDepth: Int = Int.MAX_VALUE, + followLinks: Boolean = false, + builderAction: FileVisitorBuilder.() -> Unit +): Unit { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + visitFileTree(fileVisitor(builderAction), maxDepth, followLinks) +} + +/** + * Builds a [FileVisitor] whose implementation is defined in [builderAction]. + * + * By default, the returned file visitor visits all files and re-throws I/O errors, that is: + * * [FileVisitor.preVisitDirectory] returns [FileVisitResult.CONTINUE]. + * * [FileVisitor.visitFile] returns [FileVisitResult.CONTINUE]. + * * [FileVisitor.visitFileFailed] re-throws the I/O exception that prevented the file from being visited. + * * [FileVisitor.postVisitDirectory] returns [FileVisitResult.CONTINUE] if the directory iteration completes without an I/O exception; + * otherwise it re-throws the I/O exception that caused the iteration of the directory to terminate prematurely. + * + * To override a function provide its implementation to the corresponding + * function of the [FileVisitorBuilder] that was passed as a receiver to [builderAction]. + * Note that each function can be overridden only once. + * Repeated override of a function throws [IllegalStateException]. + * + * The builder is valid only inside [builderAction] function. + * Using it outside the function throws [IllegalStateException]. + * + * Example: + * + * ``` kotlin + * val cleanVisitor = fileVisitor { + * onPreVisitDirectory { directory, _ -> + * if (directory.name == "build") { + * directory.toFile().deleteRecursively() + * FileVisitResult.SKIP_SUBTREE + * } else { + * FileVisitResult.CONTINUE + * } + * } + * + * onVisitFile { file, _ -> + * if (file.extension == "class") { + * file.deleteExisting() + * } + * FileVisitResult.CONTINUE + * } + * } + * ``` + */ +@ExperimentalPathApi +@SinceKotlin("1.7") +public fun fileVisitor(builderAction: FileVisitorBuilder.() -> Unit): FileVisitor { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return FileVisitorBuilderImpl().apply(builderAction).build() +} diff --git a/libraries/stdlib/jdk7/test/FileVisitorBuilderTest.kt b/libraries/stdlib/jdk7/test/FileVisitorBuilderTest.kt new file mode 100644 index 00000000000..ccb4dd26b08 --- /dev/null +++ b/libraries/stdlib/jdk7/test/FileVisitorBuilderTest.kt @@ -0,0 +1,335 @@ +/* + * Copyright 2010-2022 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/LICENSE.txt file. + */ + +package kotlin.jdk7.test + +import java.io.FileOutputStream +import java.nio.file.* +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream +import kotlin.io.path.* +import kotlin.jdk7.test.PathTreeWalkTest.Companion.createTestFiles +import kotlin.jdk7.test.PathTreeWalkTest.Companion.referenceFilenames +import kotlin.jdk7.test.PathTreeWalkTest.Companion.referenceFilesOnly +import kotlin.jdk7.test.PathTreeWalkTest.Companion.testVisitedFiles +import kotlin.jdk7.test.PathTreeWalkTest.Companion.tryCreateSymbolicLinkTo +import kotlin.test.* + +class FileVisitorBuilderTest : AbstractPathTest() { + @Test + fun visitOnce() { + val basedir = createTestFiles().cleanupRecursively() + + val preVisit = hashSetOf() + val postVisit = hashSetOf() + val files = hashSetOf() + + val visitor = fileVisitor { + onPreVisitDirectory { directory, _ -> + assertFalse(directory in preVisit) + if (directory == basedir) { + assertTrue(preVisit.isEmpty()) + } else { + assertTrue(directory.parent in preVisit) + } + preVisit.add(directory) + + FileVisitResult.CONTINUE + } + + onVisitFile { file, _ -> + assertTrue(file.parent in preVisit) + assertFalse(file.parent in postVisit) + files.add(file) + + FileVisitResult.CONTINUE + } + + onPostVisitDirectory { directory, exception -> + assertNull(exception) + assertTrue(directory in preVisit) + assertFalse(directory in postVisit) + if (directory != basedir) { + assertFalse(directory.parent in postVisit) + } + postVisit.add(directory) + + FileVisitResult.CONTINUE + } + } + + basedir.visitFileTree(visitor) + + assertEquals(preVisit, postVisit) + val referenceDirectoryNames = listOf("", "1", "1/2", "1/3", "6", "8") + testVisitedFiles(referenceDirectoryNames, preVisit.asSequence(), basedir) + testVisitedFiles(referenceFilesOnly, files.asSequence(), basedir) + } + + @Test + fun overrideOnce() { + assertFailsWith { + fileVisitor { + onVisitFile { _, _ -> FileVisitResult.CONTINUE } + onVisitFile { _, _ -> FileVisitResult.CONTINUE } + } + } + } + + @Test + fun overrideInAlreadyBuilt() { + val builder: FileVisitorBuilder + fileVisitor { builder = this } + assertFailsWith { + builder.onVisitFile { _, _ -> FileVisitResult.CONTINUE } + } + } + + @Test + fun restrictedRead() { + val basedir = createTestFiles().cleanupRecursively() + val restrictedDir = basedir.resolve("1/3") + + withRestrictedRead(restrictedDir) { + assertFailsWith { + val visitor = fileVisitor { } + basedir.visitFileTree(visitor) + } + + var didFail = false + + basedir.visitFileTree { + onVisitFileFailed { file, exception -> + assertEquals(restrictedDir, file) + assertIs(exception) + + didFail = true + + FileVisitResult.CONTINUE + } + } + + assertTrue(didFail) + } + } + + @Test + fun skipDirectory() { + val basedir = createTestFiles().cleanupRecursively() + val dirToSkip = basedir.resolve("1/3") + val visitedFiles = mutableListOf() + + basedir.visitFileTree { + onPreVisitDirectory { directory, _ -> + if (directory == dirToSkip) + FileVisitResult.SKIP_SUBTREE + else + FileVisitResult.CONTINUE + } + + onVisitFile { file, _ -> + assertTrue(file.parent != dirToSkip) + + visitedFiles.add(file) + + FileVisitResult.CONTINUE + } + } + + testVisitedFiles(listOf("7.txt", "8/9.txt"), visitedFiles.asSequence(), basedir) + } + + @Test + fun maxDepth() { + val basedir = createTestFiles().cleanupRecursively() + + val visitor = fileVisitor { + onVisitFile { file, _ -> + assertNotEquals("1/3/5.txt", file.relativeToOrSelf(basedir).invariantSeparatorsPathString) + assertNotEquals("1/3/6.txt", file.relativeToOrSelf(basedir).invariantSeparatorsPathString) + FileVisitResult.CONTINUE + } + } + + basedir.visitFileTree(visitor, maxDepth = 2) + } + + @Test + fun followLinks() { + val basedir = createTestFiles().cleanupRecursively() + val original = basedir.resolve("8") + basedir.resolve("1/3/link").tryCreateSymbolicLinkTo(original) ?: return + + // directory "8" contains "9.txt" file + var didFollowLinks = false + val visitor = fileVisitor { + onVisitFile { file, _ -> + if (file.relativeToOrSelf(basedir).invariantSeparatorsPathString == "1/3/link/9.txt") { + didFollowLinks = true + } + FileVisitResult.CONTINUE + } + } + + basedir.visitFileTree(visitor) + assertFalse(didFollowLinks) + + basedir.visitFileTree(visitor, followLinks = true) + assertTrue(didFollowLinks) + } + + @Test + fun copyRecursively() { + val srcRoot = createTestFiles().cleanupRecursively() + val dstRoot = createTempDirectory().cleanupRecursively() + + srcRoot.resolve("1/2/.dir").createDirectory() + srcRoot.resolve("1/3/.file").createFile() + + srcRoot.visitFileTree { + onPreVisitDirectory { directory, _ -> + if (directory.name.startsWith(".")) { + FileVisitResult.SKIP_SUBTREE + } else { + if (directory != srcRoot) { + val dst = dstRoot.resolve(directory.relativeTo(srcRoot)) + directory.copyTo(dst, StandardCopyOption.COPY_ATTRIBUTES) + } + FileVisitResult.CONTINUE + } + } + + onVisitFile { file, _ -> + if (!file.name.startsWith(".")) { + val dst = dstRoot.resolve(file.relativeTo(srcRoot)) + file.copyTo(dst, StandardCopyOption.COPY_ATTRIBUTES) + } + FileVisitResult.CONTINUE + } + } + + val dstWalk = dstRoot.walk(PathWalkOption.INCLUDE_DIRECTORIES) + testVisitedFiles(referenceFilenames + listOf(""), dstWalk, dstRoot) + val srcWalk = srcRoot.walk(PathWalkOption.INCLUDE_DIRECTORIES) + testVisitedFiles(referenceFilenames + listOf("", "1/2/.dir", "1/3/.file"), srcWalk, srcRoot) + } + + @Test + fun deleteRecursively() { + val basedir = createTestFiles() + + basedir.visitFileTree { + onVisitFile { file, _ -> + file.deleteExisting() + FileVisitResult.CONTINUE + } + + onPostVisitDirectory { directory, _ -> + directory.deleteExisting() + FileVisitResult.CONTINUE + } + } + + assertFalse(basedir.exists()) + } + + private fun deleteWith(excludePredicate: (Path) -> Boolean) = fileVisitor { + onPreVisitDirectory { directory, _ -> + if (excludePredicate(directory)) { + FileVisitResult.SKIP_SUBTREE + } else { + FileVisitResult.CONTINUE + } + } + + onVisitFile { file, _ -> + if (!excludePredicate(file)) { + file.deleteExisting() + } + FileVisitResult.CONTINUE + } + + onPostVisitDirectory { directory, _ -> + val shouldDelete = directory.useDirectoryEntries { it.none() } + if (shouldDelete) { + directory.deleteExisting() + } + FileVisitResult.CONTINUE + } + } + + @Test + fun deleteWithPredicate() { + val basedir = createTestFiles().cleanupRecursively() + basedir.resolve("image1.png").createFile() + basedir.resolve("1/3/image2.png").createFile() + + val visitor = deleteWith { path -> + when { + path.name == "8" -> true + path.extension == "png" -> true + else -> false + } + } + basedir.visitFileTree(visitor) + + val expected = listOf("", "1", "1/3", "1/3/image2.png", "8", "8/9.txt", "image1.png") + testVisitedFiles(expected, basedir.walk(PathWalkOption.INCLUDE_DIRECTORIES), basedir) + } + + private fun zipify(rootPath: Path, zipOutputStream: ZipOutputStream): FileVisitor = fileVisitor { + onPreVisitDirectory { directory, _ -> + if (directory != rootPath) { + val entry = ZipEntry(directory.relativeTo(rootPath).toString()) + + zipOutputStream.putNextEntry(entry) + zipOutputStream.closeEntry() + } + FileVisitResult.CONTINUE + } + + onVisitFile { file, attributes -> + val entry = ZipEntry(file.relativeTo(rootPath).toString()) + + entry.size = attributes.size() + zipOutputStream.putNextEntry(entry) + Files.copy(file, zipOutputStream) + zipOutputStream.closeEntry() + + FileVisitResult.CONTINUE + } + + onVisitFileFailed { _, exception -> + zipOutputStream.close() + + throw exception + } + } + + @Test + fun archive() { + val basedir = createTestFiles().cleanupRecursively() + + val ninthFile = Path("8/9.txt") + basedir.resolve(ninthFile).writeText("ninth") + + val zipFile = createTempFile("testFiles", ".zip").toFile() + ZipOutputStream(FileOutputStream(zipFile)).use { zipOutputStream -> + val visitor = zipify(basedir, zipOutputStream) + basedir.visitFileTree(visitor) + } + + ZipFile(zipFile).use { zip -> + val entriesPath = zip.entries().toList().map { Path(it.name).invariantSeparatorsPathString } + assertEquals(referenceFilenames.sorted(), entriesPath.sorted()) + + val ninthEntry = zip.getEntry(ninthFile.pathString) + zip.getInputStream(ninthEntry).bufferedReader().use { reader -> + assertEquals("ninth", reader.readText()) + } + } + } +} diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-jdk7.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-jdk7.txt index 2b315b76bae..9d6d0316fc0 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-jdk7.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-jdk7.txt @@ -1,6 +1,13 @@ public abstract interface annotation class kotlin/io/path/ExperimentalPathApi : java/lang/annotation/Annotation { } +public abstract interface class kotlin/io/path/FileVisitorBuilder { + public abstract fun onPostVisitDirectory (Lkotlin/jvm/functions/Function2;)V + public abstract fun onPreVisitDirectory (Lkotlin/jvm/functions/Function2;)V + public abstract fun onVisitFile (Lkotlin/jvm/functions/Function2;)V + public abstract fun onVisitFileFailed (Lkotlin/jvm/functions/Function2;)V +} + public final class kotlin/io/path/PathWalkOption : java/lang/Enum { public static final field BREADTH_FIRST Lkotlin/io/path/PathWalkOption; public static final field FOLLOW_LINKS Lkotlin/io/path/PathWalkOption; @@ -17,6 +24,7 @@ public final class kotlin/io/path/PathsKt { public static final fun createTempFile (Ljava/nio/file/Path;Ljava/lang/String;Ljava/lang/String;[Ljava/nio/file/attribute/FileAttribute;)Ljava/nio/file/Path; public static synthetic fun createTempFile$default (Ljava/nio/file/Path;Ljava/lang/String;Ljava/lang/String;[Ljava/nio/file/attribute/FileAttribute;ILjava/lang/Object;)Ljava/nio/file/Path; public static final fun fileAttributeViewNotAvailable (Ljava/nio/file/Path;Ljava/lang/Class;)Ljava/lang/Void; + public static final fun fileVisitor (Lkotlin/jvm/functions/Function1;)Ljava/nio/file/FileVisitor; public static final fun getExtension (Ljava/nio/file/Path;)Ljava/lang/String; public static final fun getInvariantSeparatorsPathString (Ljava/nio/file/Path;)Ljava/lang/String; public static final fun getName (Ljava/nio/file/Path;)Ljava/lang/String; @@ -28,6 +36,10 @@ public final class kotlin/io/path/PathsKt { public static final fun relativeTo (Ljava/nio/file/Path;Ljava/nio/file/Path;)Ljava/nio/file/Path; public static final fun relativeToOrNull (Ljava/nio/file/Path;Ljava/nio/file/Path;)Ljava/nio/file/Path; public static final fun relativeToOrSelf (Ljava/nio/file/Path;Ljava/nio/file/Path;)Ljava/nio/file/Path; + public static final fun visitFileTree (Ljava/nio/file/Path;IZLkotlin/jvm/functions/Function1;)V + public static final fun visitFileTree (Ljava/nio/file/Path;Ljava/nio/file/FileVisitor;IZ)V + public static synthetic fun visitFileTree$default (Ljava/nio/file/Path;IZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public static synthetic fun visitFileTree$default (Ljava/nio/file/Path;Ljava/nio/file/FileVisitor;IZILjava/lang/Object;)V public static final fun walk (Ljava/nio/file/Path;[Lkotlin/io/path/PathWalkOption;)Lkotlin/sequences/Sequence; public static final fun writeText (Ljava/nio/file/Path;Ljava/lang/CharSequence;Ljava/nio/charset/Charset;[Ljava/nio/file/OpenOption;)V public static synthetic fun writeText$default (Ljava/nio/file/Path;Ljava/lang/CharSequence;Ljava/nio/charset/Charset;[Ljava/nio/file/OpenOption;ILjava/lang/Object;)V