mirror of
https://github.com/GayPizzaSpecifications/dough.git
synced 2025-08-05 14:31:32 +00:00
Initial Commit
This commit is contained in:
3
dough-fs/build.gradle.kts
Normal file
3
dough-fs/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
dough_component
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
|
||||
interface FsOperations {
|
||||
fun exists(path: FsPath): Boolean
|
||||
fun isDirectory(path: FsPath): Boolean
|
||||
fun isRegularFile(path: FsPath): Boolean
|
||||
fun isSymbolicLink(path: FsPath): Boolean
|
||||
fun isReadable(path: FsPath): Boolean
|
||||
fun isWritable(path: FsPath): Boolean
|
||||
fun isExecutable(path: FsPath): Boolean
|
||||
|
||||
fun list(path: FsPath): Sequence<FsPath>
|
||||
|
||||
fun walk(path: FsPath): Sequence<FsPath>
|
||||
fun visit(path: FsPath, visitor: FsPathVisitor)
|
||||
|
||||
fun readString(path: FsPath): String
|
||||
fun readAllBytes(path: FsPath): ByteArray
|
||||
fun readBytesChunked(path: FsPath, block: (ByteArray, Int) -> Unit)
|
||||
fun <T> readJsonFile(path: FsPath, deserializer: DeserializationStrategy<T>): T
|
||||
|
||||
fun readLines(path: FsPath, block: (String) -> Unit)
|
||||
fun readLines(path: FsPath): Sequence<String>
|
||||
|
||||
fun <T> readJsonLinesToList(path: FsPath, deserializer: DeserializationStrategy<T>, block: (T) -> Unit)
|
||||
fun <T> readJsonLinesToList(path: FsPath, deserializer: DeserializationStrategy<T>): List<T>
|
||||
|
||||
fun writeString(path: FsPath, content: String)
|
||||
fun writeAllBytes(path: FsPath, bytes: ByteArray)
|
||||
fun <T> writeJsonFile(path: FsPath, serializer: SerializationStrategy<T>, value: T)
|
||||
|
||||
fun delete(path: FsPath)
|
||||
fun deleteOnExit(path: FsPath)
|
||||
fun deleteRecursively(path: FsPath)
|
||||
|
||||
fun createDirectories(path: FsPath)
|
||||
}
|
19
dough-fs/src/commonMain/kotlin/gay/pizza/dough/fs/FsPath.kt
Normal file
19
dough-fs/src/commonMain/kotlin/gay/pizza/dough/fs/FsPath.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable(with = FsPathSerializer::class)
|
||||
interface FsPath : Comparable<FsPath> {
|
||||
val fullPathString: String
|
||||
val entityNameString: String
|
||||
|
||||
val parent: FsPath?
|
||||
val operations: FsOperations
|
||||
|
||||
fun resolve(part: String): FsPath
|
||||
fun relativeTo(path: FsPath): FsPath
|
||||
|
||||
override fun compareTo(other: FsPath): Int {
|
||||
return fullPathString.compareTo(other.fullPathString)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
object FsPathSerializer : KSerializer<FsPath> {
|
||||
override val descriptor: SerialDescriptor = String.serializer().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): FsPath {
|
||||
return FsPath(decoder.decodeString())
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: FsPath) {
|
||||
encoder.encodeString(value.fullPathString)
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
interface FsPathVisitor {
|
||||
fun beforeVisitDirectory(path: FsPath): VisitResult
|
||||
fun visitFile(path: FsPath): VisitResult
|
||||
fun visitFileFailed(path: FsPath, exception: Exception): VisitResult
|
||||
fun afterVisitDirectory(path: FsPath): VisitResult
|
||||
|
||||
enum class VisitResult {
|
||||
Continue,
|
||||
Terminate,
|
||||
SkipSubtree,
|
||||
SkipSiblings
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
|
||||
fun FsPath.exists(): Boolean =
|
||||
operations.exists(this)
|
||||
|
||||
fun FsPath.isDirectory(): Boolean =
|
||||
operations.isDirectory(this)
|
||||
|
||||
fun FsPath.isRegularFile(): Boolean =
|
||||
operations.isRegularFile(this)
|
||||
|
||||
fun FsPath.isSymbolicLink(): Boolean =
|
||||
operations.isSymbolicLink(this)
|
||||
|
||||
fun FsPath.isReadable(): Boolean =
|
||||
operations.isReadable(this)
|
||||
|
||||
fun FsPath.isWritable(): Boolean =
|
||||
operations.isWritable(this)
|
||||
|
||||
fun FsPath.isExecutable(): Boolean =
|
||||
operations.isExecutable(this)
|
||||
|
||||
fun FsPath.list(): Sequence<FsPath> =
|
||||
operations.list(this)
|
||||
|
||||
fun FsPath.walk(): Sequence<FsPath> =
|
||||
operations.walk(this)
|
||||
|
||||
fun FsPath.visit(visitor: FsPathVisitor): Unit =
|
||||
operations.visit(this, visitor)
|
||||
|
||||
fun FsPath.readString(): String =
|
||||
operations.readString(this)
|
||||
|
||||
fun FsPath.readAllBytes(): ByteArray =
|
||||
operations.readAllBytes(this)
|
||||
|
||||
fun FsPath.readBytesChunked(block: (ByteArray, Int) -> Unit) =
|
||||
operations.readBytesChunked(this, block)
|
||||
|
||||
fun <T> FsPath.readJsonFile(deserializer: DeserializationStrategy<T>): T =
|
||||
operations.readJsonFile(this, deserializer)
|
||||
|
||||
fun FsPath.readLines(block: (String) -> Unit): Unit =
|
||||
operations.readLines(this, block)
|
||||
|
||||
fun FsPath.readLines(): Sequence<String> =
|
||||
operations.readLines(this)
|
||||
|
||||
fun FsPath.readLinesToList(): List<String> {
|
||||
val lines = mutableListOf<String>()
|
||||
readLines { line -> lines.add(line) }
|
||||
return lines
|
||||
}
|
||||
|
||||
fun <T> FsPath.readJsonLinesToList(deserializer: DeserializationStrategy<T>, block: (T) -> Unit) =
|
||||
operations.readJsonLinesToList(this, deserializer, block)
|
||||
|
||||
fun <T> FsPath.readJsonLinesToList(deserializer: DeserializationStrategy<T>): List<T> =
|
||||
operations.readJsonLinesToList(this, deserializer)
|
||||
|
||||
fun FsPath.writeString(content: String): Unit =
|
||||
operations.writeString(this, content)
|
||||
|
||||
fun FsPath.writeAllBytes(bytes: ByteArray): Unit =
|
||||
operations.writeAllBytes(this, bytes)
|
||||
|
||||
fun <T> FsPath.writeJsonFile(serializer: SerializationStrategy<T>, value: T): Unit =
|
||||
operations.writeJsonFile(this, serializer, value)
|
||||
|
||||
fun FsPath.delete(): Unit =
|
||||
operations.delete(this)
|
||||
|
||||
fun FsPath.deleteOnExit(): Unit =
|
||||
operations.delete(this)
|
||||
|
||||
fun FsPath.deleteRecursively(): Unit =
|
||||
operations.deleteRecursively(this)
|
||||
|
||||
fun FsPath.createDirectories(): Unit =
|
||||
operations.createDirectories(this)
|
@ -0,0 +1,3 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
expect fun FsPath(path: String): FsPath
|
@ -0,0 +1,12 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
fun Path.toFsPath(): FsPath = JavaPath(this)
|
||||
fun FsPath.toJavaPath(): Path {
|
||||
return if (this is JavaPath) {
|
||||
javaPath
|
||||
} else {
|
||||
Path.of(fullPathString)
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.bufferedReader
|
||||
import kotlin.io.path.deleteExisting
|
||||
import kotlin.io.path.inputStream
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
object JavaFsOperations : FsOperations {
|
||||
override fun exists(path: FsPath): Boolean = Files.exists(path.toJavaPath())
|
||||
override fun isDirectory(path: FsPath): Boolean = Files.isDirectory(path.toJavaPath())
|
||||
override fun isRegularFile(path: FsPath): Boolean = Files.isRegularFile(path.toJavaPath())
|
||||
override fun isSymbolicLink(path: FsPath): Boolean = Files.isSymbolicLink(path.toJavaPath())
|
||||
override fun isReadable(path: FsPath): Boolean = Files.isReadable(path.toJavaPath())
|
||||
override fun isWritable(path: FsPath): Boolean = Files.isWritable(path.toJavaPath())
|
||||
override fun isExecutable(path: FsPath): Boolean = Files.isExecutable(path.toJavaPath())
|
||||
|
||||
override fun list(path: FsPath): Sequence<FsPath> = Files.list(path.toJavaPath()).asSequence().map { it.toFsPath() }
|
||||
|
||||
override fun walk(path: FsPath): Sequence<FsPath> = Files.walk(path.toJavaPath()).asSequence().map { it.toFsPath() }
|
||||
override fun visit(path: FsPath, visitor: FsPathVisitor) =
|
||||
Files.walkFileTree(path.toJavaPath(), JavaFsPathVisitorAdapter(visitor)).run {}
|
||||
|
||||
override fun readString(path: FsPath): String = Files.readString(path.toJavaPath())
|
||||
override fun readAllBytes(path: FsPath): ByteArray = Files.readAllBytes(path.toJavaPath())
|
||||
override fun readBytesChunked(path: FsPath, block: (ByteArray, Int) -> Unit) {
|
||||
val javaPath = path.toJavaPath()
|
||||
val stream = javaPath.inputStream()
|
||||
val buffer = ByteArray(1024 * 1024)
|
||||
var count: Int
|
||||
while ((stream.read(buffer).also { count = it }) > 0) {
|
||||
block(buffer, count)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> readJsonFile(path: FsPath, deserializer: DeserializationStrategy<T>): T =
|
||||
Json.decodeFromString(deserializer, readString(path))
|
||||
|
||||
override fun readLines(path: FsPath, block: (String) -> Unit) {
|
||||
readLines(path).forEach(block)
|
||||
}
|
||||
|
||||
override fun readLines(path: FsPath): Sequence<String> {
|
||||
val stream = path.toJavaPath().bufferedReader()
|
||||
return stream.lineSequence()
|
||||
}
|
||||
|
||||
override fun <T> readJsonLinesToList(path: FsPath, deserializer: DeserializationStrategy<T>, block: (T) -> Unit) {
|
||||
readLines(path) { line ->
|
||||
val trimmed = line.trim()
|
||||
val item = Json.decodeFromString(deserializer, trimmed)
|
||||
block(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> readJsonLinesToList(path: FsPath, deserializer: DeserializationStrategy<T>): List<T> {
|
||||
val results = mutableListOf<T>()
|
||||
readJsonLinesToList(path, deserializer) { item ->
|
||||
results.add(item)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
override fun writeString(path: FsPath, content: String): Unit = Files.writeString(path.toJavaPath(), content).run {}
|
||||
override fun writeAllBytes(path: FsPath, bytes: ByteArray): Unit = Files.write(path.toJavaPath(), bytes).run {}
|
||||
override fun <T> writeJsonFile(path: FsPath, serializer: SerializationStrategy<T>, value: T) =
|
||||
writeString(path, Json.encodeToString(serializer, value))
|
||||
|
||||
override fun delete(path: FsPath) {
|
||||
path.toJavaPath().deleteExisting()
|
||||
}
|
||||
|
||||
override fun deleteOnExit(path: FsPath) {
|
||||
path.toJavaPath().toFile().deleteOnExit()
|
||||
}
|
||||
|
||||
override fun deleteRecursively(path: FsPath) {
|
||||
path.toJavaPath().toFile().deleteRecursively()
|
||||
}
|
||||
|
||||
override fun createDirectories(path: FsPath) {
|
||||
Files.createDirectories(path.toJavaPath())
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import java.io.IOException
|
||||
import java.nio.file.FileVisitResult
|
||||
import java.nio.file.FileVisitor
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
|
||||
class JavaFsPathVisitorAdapter(private val visitor: FsPathVisitor) : FileVisitor<Path> {
|
||||
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
|
||||
return visitor.beforeVisitDirectory(dir!!.toFsPath()).adapt()
|
||||
}
|
||||
|
||||
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
|
||||
return visitor.visitFile(file!!.toFsPath()).adapt()
|
||||
}
|
||||
|
||||
override fun visitFileFailed(file: Path?, exc: IOException?): FileVisitResult {
|
||||
return visitor.visitFileFailed(file!!.toFsPath(), exc!!).adapt()
|
||||
}
|
||||
|
||||
override fun postVisitDirectory(dir: Path?, exc: IOException?): FileVisitResult {
|
||||
return visitor.afterVisitDirectory(dir!!.toFsPath()).adapt()
|
||||
}
|
||||
|
||||
private fun FsPathVisitor.VisitResult.adapt(): FileVisitResult = when (this) {
|
||||
FsPathVisitor.VisitResult.Continue -> FileVisitResult.CONTINUE
|
||||
FsPathVisitor.VisitResult.Terminate -> FileVisitResult.TERMINATE
|
||||
FsPathVisitor.VisitResult.SkipSubtree -> FileVisitResult.SKIP_SUBTREE
|
||||
FsPathVisitor.VisitResult.SkipSiblings -> FileVisitResult.SKIP_SIBLINGS
|
||||
}
|
||||
}
|
37
dough-fs/src/jvmMain/kotlin/gay/pizza/dough/fs/JavaPath.kt
Normal file
37
dough-fs/src/jvmMain/kotlin/gay/pizza/dough/fs/JavaPath.kt
Normal file
@ -0,0 +1,37 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import kotlin.io.path.relativeTo
|
||||
|
||||
class JavaPath(val javaPath: Path) : FsPath {
|
||||
override val fullPathString: String
|
||||
get() = javaPath.toString()
|
||||
|
||||
override val entityNameString: String
|
||||
get() = javaPath.fileName.toString()
|
||||
|
||||
override val parent: FsPath?
|
||||
get() = javaPath.parent?.toFsPath()
|
||||
|
||||
override val operations: FsOperations = JavaFsOperations
|
||||
|
||||
override fun resolve(part: String): FsPath = javaPath.resolve(part).toFsPath()
|
||||
override fun relativeTo(path: FsPath): FsPath = javaPath.relativeTo(path.toJavaPath()).toFsPath()
|
||||
|
||||
override fun toString(): String = javaPath.toString()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (other !is FsPath) {
|
||||
return false
|
||||
}
|
||||
|
||||
return other.toJavaPath() == javaPath
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(javaPath)
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package gay.pizza.dough.fs
|
||||
|
||||
import java.nio.file.Paths
|
||||
|
||||
actual fun FsPath(path: String): FsPath {
|
||||
return JavaPath(Paths.get(path))
|
||||
}
|
Reference in New Issue
Block a user