split ci
This commit is contained in:
@@ -3,7 +3,7 @@ on:
|
|||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
publish:
|
||||||
runs-on: linux
|
runs-on: linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: gradle-${{ hashFiles('**/libs.versions.toml') }}
|
key: gradle-${{ hashFiles('**/libs.versions.toml') }}
|
||||||
restore-keys: gradle-
|
restore-keys: gradle
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches/
|
~/.gradle/caches/
|
||||||
~/.gradle/wrapper/
|
~/.gradle/wrapper/
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: konan-${{ hashFiles('**/libs.versions.toml') }}
|
key: konan-${{ hashFiles('**/libs.versions.toml') }}
|
||||||
restore-keys: konan-
|
restore-keys: konan
|
||||||
path: |
|
path: |
|
||||||
~/.konan/
|
~/.konan/
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: node-${{ hashFiles('**/libs.versions.toml') }}
|
key: node-${{ hashFiles('**/libs.versions.toml') }}
|
||||||
restore-keys: node-
|
restore-keys: node
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/nodejs
|
~/.gradle/nodejs
|
||||||
~/.gradle/yarn
|
~/.gradle/yarn
|
||||||
19
README.md
19
README.md
@@ -2,15 +2,6 @@
|
|||||||
|
|
||||||
`shell-kt` is a Kotlin Multiplatform library that enables the execution of shell commands.
|
`shell-kt` is a Kotlin Multiplatform library that enables the execution of shell commands.
|
||||||
|
|
||||||
## Targets
|
|
||||||
|
|
||||||
| Target | Status |
|
|
||||||
|------------------|---------------|
|
|
||||||
| JVM | Supported |
|
|
||||||
| JavaScript | Supported |
|
|
||||||
| Native (Linux) | Supported |
|
|
||||||
| Native (Windows) | Not Supported |
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Add the following to your `build.gradle.kts`.
|
Add the following to your `build.gradle.kts`.
|
||||||
@@ -21,21 +12,15 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.infendro:shell:1.0.0")
|
implementation("com.infendro:shell:1.1.0")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import com.infendro.shell.Shell
|
|
||||||
|
|
||||||
suspend fun main() {
|
suspend fun main() {
|
||||||
// the command to execute
|
val result = execute("echo", "Hello World!")
|
||||||
val command = arrayOf("echo", "Hello World!")
|
|
||||||
|
|
||||||
// execute the command
|
|
||||||
val result = Shell.run(command)
|
|
||||||
|
|
||||||
println(result.code) // 0
|
println(result.code) // 0
|
||||||
println(result.value) // Hello World!
|
println(result.value) // Hello World!
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import com.infendro.plugin.infendro
|
|||||||
import com.infendro.plugin.token
|
import com.infendro.plugin.token
|
||||||
|
|
||||||
group = "com.infendro"
|
group = "com.infendro"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.infendro)
|
alias(libs.plugins.infendro)
|
||||||
@@ -13,9 +13,11 @@ plugins {
|
|||||||
kotlin {
|
kotlin {
|
||||||
jvm()
|
jvm()
|
||||||
linuxX64()
|
linuxX64()
|
||||||
js {
|
linuxArm64()
|
||||||
nodejs()
|
mingwX64()
|
||||||
}
|
macosX64()
|
||||||
|
macosArm64()
|
||||||
|
js { nodejs() }
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[versions]
|
[versions]
|
||||||
infendro = "1.0.0"
|
infendro = "1.1.0"
|
||||||
kotlin = "2.2.21"
|
kotlin = "2.3.0"
|
||||||
node = "2025.12.5-24.7.1"
|
node = "2026.2.11-24.10.4"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
|
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package com.infendro.shell
|
package com.infendro.shell
|
||||||
|
|
||||||
object Shell {
|
data class Result(
|
||||||
suspend fun run(
|
|
||||||
command: Array<String>,
|
|
||||||
directory: String? = null,
|
|
||||||
): Result {
|
|
||||||
return execute(command, directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Result(
|
|
||||||
val code: Int,
|
val code: Int,
|
||||||
val value: String,
|
val value: String,
|
||||||
)
|
) {
|
||||||
|
val success: Boolean
|
||||||
|
get() = code == 0
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
fun from(code: Int, value: String) = Result(code, value)
|
||||||
|
|
||||||
|
fun from(code: Int, success: () -> String, error: () -> String) = when (code) {
|
||||||
|
0 -> Result(code, success())
|
||||||
|
else -> Result(code, error())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal expect suspend fun execute(
|
expect suspend fun execute(vararg command: String, directory: String? = null): Result
|
||||||
command: Array<String>,
|
|
||||||
directory: String?,
|
|
||||||
): Shell.Result
|
|
||||||
|
|||||||
@@ -5,15 +5,13 @@ import node.childProcess.exec
|
|||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
internal actual suspend fun execute(
|
actual suspend fun execute(vararg command: String, directory: String?): Result = suspendCoroutine { continuation ->
|
||||||
command: Array<String>,
|
val command = command.joinToString(" ") { """"$it"""" }
|
||||||
directory: String?,
|
val options = ExecOptions(cwd = directory)
|
||||||
): Shell.Result = suspendCoroutine { continuation ->
|
|
||||||
val command = command.joinToString(" ") { "\"$it\"" }
|
|
||||||
val options = ExecOptions.invoke(cwd = directory)
|
|
||||||
exec(command, options) { error, stdout, stderr ->
|
exec(command, options) { error, stdout, stderr ->
|
||||||
val code = if (error == null) 0 else error.code!!.toInt()
|
val code = error?.code?.toInt() ?: 0
|
||||||
val value = (if (error == null) stdout else stderr) as String
|
|
||||||
continuation.resume(Shell.Result(code, value))
|
val result = Result.from(code, { stdout as String }, { stderr as String })
|
||||||
|
continuation.resume(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package com.infendro.shell
|
package com.infendro.shell
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
internal actual suspend fun execute(
|
actual suspend fun execute(vararg command: String, directory: String?): Result = suspendCoroutine { continuation ->
|
||||||
command: Array<String>,
|
|
||||||
directory: String?,
|
|
||||||
): Shell.Result {
|
|
||||||
val process = ProcessBuilder(*command).also {
|
val process = ProcessBuilder(*command).also {
|
||||||
if (directory != null) {
|
if (directory != null) {
|
||||||
it.directory(File(directory))
|
val dir = File(directory)
|
||||||
|
it.directory(dir)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
val code = process.waitFor()
|
val code = process.waitFor()
|
||||||
val value = (if (code == 0) process.inputReader() else process.errorReader()).readText()
|
|
||||||
return Shell.Result(code, value)
|
val result = Result.from(code, { process.inputReader().readText() }, { process.errorReader().readText() })
|
||||||
|
continuation.resume(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,27 @@ import kotlinx.cinterop.CPointer
|
|||||||
import kotlinx.cinterop.refTo
|
import kotlinx.cinterop.refTo
|
||||||
import kotlinx.cinterop.toKString
|
import kotlinx.cinterop.toKString
|
||||||
import platform.posix.*
|
import platform.posix.*
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
internal actual suspend fun execute(
|
actual suspend fun execute(vararg command: String, directory: String?): Result = suspendCoroutine { continuation ->
|
||||||
command: Array<String>,
|
val command = command.joinToString(" ") { """"$it"""" }
|
||||||
directory: String?,
|
|
||||||
): Shell.Result {
|
|
||||||
val command = command.joinToString(" ") { "\"$it\"" }
|
|
||||||
if (directory != null) {
|
if (directory != null) {
|
||||||
chdir(directory)
|
chdir(directory)
|
||||||
}
|
}
|
||||||
val stream = popen(command, "r")!!
|
val stream = popen(command, "r")!!
|
||||||
val value = stream.readLines().joinToString("")
|
val value = stream.readLines().joinToString("")
|
||||||
val code = pclose(stream)
|
val code = pclose(stream)
|
||||||
return Shell.Result(code, value)
|
|
||||||
|
val result = Result.from(code, value)
|
||||||
|
continuation.resume(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CPointer<FILE>.readLines(): List<String> {
|
private fun CPointer<FILE>.readLines(): List<String> {
|
||||||
val lines = mutableListOf<String>()
|
val lines = mutableListOf<String>()
|
||||||
val buffer = ByteArray(4096)
|
val buffer = ByteArray(4096)
|
||||||
while (true) {
|
while (true) {
|
||||||
val line = fgets(buffer.refTo(0), buffer.size, this)
|
val line = fgets(buffer.refTo(0), buffer.size, this) ?: break
|
||||||
if (line == null) break
|
|
||||||
lines.add(line.toKString())
|
lines.add(line.toKString())
|
||||||
}
|
}
|
||||||
return lines
|
return lines
|
||||||
|
|||||||
Reference in New Issue
Block a user