lyng CLI: support for shebang, started shell KMP code
This commit is contained in:
parent
b961296425
commit
83e79f47c7
3
bin/lyng_test
Executable file
3
bin/lyng_test
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env lyng
|
||||||
|
|
||||||
|
println("Hello from lyng!")
|
@ -29,11 +29,11 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
implementation(project(":lynglib"))
|
implementation(project(":lynglib"))
|
||||||
implementation(libs.okio)
|
implementation(libs.okio)
|
||||||
|
|
||||||
implementation(libs.clikt)
|
implementation(libs.clikt)
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
// optional support for rendering markdown in help messages
|
// optional support for rendering markdown in help messages
|
||||||
// implementation(libs.clikt.markdown)
|
// implementation(libs.clikt.markdown)
|
||||||
}
|
}
|
||||||
@ -42,9 +42,15 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("test-common"))
|
implementation(kotlin("test-common"))
|
||||||
implementation(kotlin("test-annotations-common"))
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
implementation(libs.okio.fakefilesystem)
|
implementation(libs.okio.fakefilesystem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// val nativeMain by getting {
|
||||||
|
// dependencies {
|
||||||
|
// implementation(kotlin("stdlib-common"))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
val linuxX64Main by getting {
|
val linuxX64Main by getting {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,28 @@ import okio.use
|
|||||||
|
|
||||||
expect fun exit(code: Int)
|
expect fun exit(code: Int)
|
||||||
|
|
||||||
|
expect class ShellCommandExecutor {
|
||||||
|
fun executeCommand(command: String): CommandResult
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(): ShellCommandExecutor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class CommandResult(
|
||||||
|
val exitCode: Int,
|
||||||
|
val output: String,
|
||||||
|
val error: String
|
||||||
|
)
|
||||||
|
|
||||||
val baseContext = Context().apply {
|
val baseContext = Context().apply {
|
||||||
addFn("exit") {
|
addFn("exit") {
|
||||||
exit(requireOnlyArg<ObjInt>().toInt())
|
exit(requireOnlyArg<ObjInt>().toInt())
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
|
// ObjString.type.addFn("shell") {
|
||||||
|
//
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() {
|
class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() {
|
||||||
@ -90,11 +107,16 @@ class Lyng(val launcher: (suspend () -> Unit) -> Unit) : CliktCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun executeFile(fileName: String) {
|
suspend fun executeFile(fileName: String) {
|
||||||
val text = FileSystem.SYSTEM.source(fileName.toPath()).use { fileSource ->
|
var text = FileSystem.SYSTEM.source(fileName.toPath()).use { fileSource ->
|
||||||
fileSource.buffer().use { bs ->
|
fileSource.buffer().use { bs ->
|
||||||
bs.readUtf8()
|
bs.readUtf8()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( text.startsWith("#!") ) {
|
||||||
|
// skip shebang
|
||||||
|
val pos = text.indexOf('\n')
|
||||||
|
text = text.substring(pos + 1)
|
||||||
|
}
|
||||||
processErrors {
|
processErrors {
|
||||||
Compiler().compile(Source(fileName, text)).execute(baseContext)
|
Compiler().compile(Source(fileName, text)).execute(baseContext)
|
||||||
}
|
}
|
||||||
|
21
lyng/src/jvmMain/kotlin/Shell.jvm.kt
Normal file
21
lyng/src/jvmMain/kotlin/Shell.jvm.kt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package net.sergeych
|
||||||
|
|
||||||
|
// Alternative implementation for native targets
|
||||||
|
actual class ShellCommandExecutor() {
|
||||||
|
actual fun executeCommand(command: String): CommandResult {
|
||||||
|
val process = ProcessBuilder("/bin/sh", "-c", command).start()
|
||||||
|
val exitCode = process.waitFor()
|
||||||
|
val output = process.inputStream.bufferedReader().readText()
|
||||||
|
val error = process.errorStream.bufferedReader().readText()
|
||||||
|
|
||||||
|
return CommandResult(
|
||||||
|
exitCode = exitCode,
|
||||||
|
output = output.trim(),
|
||||||
|
error = error.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual companion object {
|
||||||
|
actual fun create(): ShellCommandExecutor = ShellCommandExecutor()
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,48 @@
|
|||||||
|
@file:OptIn(ExperimentalForeignApi::class, ExperimentalForeignApi::class, ExperimentalForeignApi::class)
|
||||||
|
|
||||||
package net.sergeych
|
package net.sergeych
|
||||||
|
|
||||||
|
import kotlinx.cinterop.*
|
||||||
|
import platform.posix.fgets
|
||||||
|
import platform.posix.pclose
|
||||||
|
import platform.posix.popen
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
actual class ShellCommandExecutor() {
|
||||||
|
actual fun executeCommand(command: String): CommandResult {
|
||||||
|
val outputBuilder = StringBuilder()
|
||||||
|
val errorBuilder = StringBuilder()
|
||||||
|
|
||||||
|
val fp = popen(command, "r") ?: return CommandResult(
|
||||||
|
exitCode = -1,
|
||||||
|
output = "",
|
||||||
|
error = "Failed to execute command"
|
||||||
|
)
|
||||||
|
|
||||||
|
val buffer = ByteArray(4096)
|
||||||
|
while (true) {
|
||||||
|
val bytesRead = buffer.usePinned { pinned ->
|
||||||
|
fgets(pinned.addressOf(0), buffer.size.convert(), fp)
|
||||||
|
}
|
||||||
|
if (bytesRead == null) break
|
||||||
|
outputBuilder.append(bytesRead.toKString())
|
||||||
|
}
|
||||||
|
|
||||||
|
val status = pclose(fp)
|
||||||
|
val exitCode = if (status == 0) 0 else 1
|
||||||
|
|
||||||
|
return CommandResult(
|
||||||
|
exitCode = exitCode,
|
||||||
|
output = outputBuilder.toString().trim(),
|
||||||
|
error = errorBuilder.toString().trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual companion object {
|
||||||
|
actual fun create(): ShellCommandExecutor = ShellCommandExecutor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
actual fun exit(code: Int) {
|
actual fun exit(code: Int) {
|
||||||
exitProcess(code)
|
exitProcess(code)
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user