jvmMain.com.xebia.functional.xef.io.JvmCommandExecutor.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xef-filesystem-jvm Show documentation
Show all versions of xef-filesystem-jvm Show documentation
Building applications with LLMs through composability in Kotlin
package com.xebia.functional.xef.io
import kotlinx.coroutines.runBlocking
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.withContext
actual val CommandExecutor.Companion.DEFAULT: CommandExecutor
get() = JvmCommandExecutor
object JvmCommandExecutor : CommandExecutor {
// TODO Remove RunBlocking
private val platform: Platform by lazy {
val osName = System.getProperty("os.name").lowercase()
when {
osName.startsWith("windows") -> {
val uname = runBlocking {
try {
executeCommandAndCaptureOutput(
listOf("where", "uname"),
ExecuteCommandOptions(
directory = ".",
abortOnError = true,
redirectStderr = false,
trim = true,
),
)
executeCommandAndCaptureOutput(
listOf("uname", "-a"),
ExecuteCommandOptions(
directory = ".",
abortOnError = true,
redirectStderr = true,
trim = true,
),
)
} catch (e: Exception) {
""
}
}
// if (uname.isNotBlank()) println("uname: $uname")
when {
uname.startsWith("MSYS") -> Platform.LINUX
uname.startsWith("MINGW") -> Platform.LINUX
uname.startsWith("CYGWIN") -> Platform.LINUX
else -> Platform.WINDOWS
} // .also { println("platform is $it") }
}
osName.startsWith("linux") -> Platform.LINUX
osName.startsWith("mac") -> Platform.MACOS
osName.startsWith("darwin") -> Platform.MACOS
else -> error("unknown osName: $osName")
}
}
override suspend fun executeCommandAndCaptureOutput(command: List, options: ExecuteCommandOptions): String =
withContext(Dispatchers.IO) {
val process = ProcessBuilder().apply {
command(command.filter { it.isNotBlank() })
directory(File(options.directory))
}.start()
val stdout = process.inputStream.bufferedReader().use { it.readText() }
val stderr = process.errorStream.bufferedReader().use { it.readText() }
val exitCode = runInterruptible { process.waitFor() }
if (options.abortOnError) assert(exitCode == 0)
val output = if (stderr.isBlank()) stdout else "$stdout $stderr"
if (options.trim) output.trim() else output
}
override suspend fun pwd(options: ExecuteCommandOptions): String =
File(".").absolutePath
override suspend fun findExecutable(executable: String): String =
when (platform) {
Platform.WINDOWS -> executeCommandAndCaptureOutput(
listOf("where", executable),
ExecuteCommandOptions(".", true, false, true)
)
else -> executeCommandAndCaptureOutput(
listOf("which", executable),
ExecuteCommandOptions(".", true, false, true)
)
}
}