一个可以将外部命令跑在子进程的库,用于Kotlin Native/JVM
Rust 是一门兼顾性能和工程性的优秀语言。
在 1.x 版本中,我们使用以下 API 来提供创建子进程的功能
fork
of [POSIX api]
CreateChildProcess
of [win32 api]
java.lang.ProcessBuilder
of JVM
在 2.0 版本中,我们使用 Rust 标准库来提供创建子进程的功能。
std::process::Command
of Rust
java.lang.ProcessBuilder
of JVM
它将带来
- 更统一的 API
- 更易用的 API
- 性能依旧优秀
- 更易于维护
- 代码结构更清晰
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-pc-windows-gnu (mingw-w64)
- jvm
- Rust Standard Library 1.69.0
- Kotlin Multiplatform 1.9.21
build.gradle.kts
:
// ……
repositories {
mavenCentral()
}
// ……
dependencies {
// should replace with the latest version
implementation("com.kgit2:kommand:2.x")
}
|
package com.kgit2.kommand |
|
|
|
import com.kgit2.kommand.process.Command |
|
import com.kgit2.kommand.process.Stdio |
|
|
|
fun main() { |
|
Command("ping") |
|
.args(listOf("-c", "5", "localhost")) |
|
.stdout(Stdio.Inherit) |
|
.spawn() |
|
.wait() |
|
} |
|
package com.kgit2.kommand |
|
|
|
import com.kgit2.kommand.process.Command |
|
import com.kgit2.kommand.process.Stdio |
|
|
|
fun main() { |
|
val child = Command("ping") |
|
.args(listOf("-c", "5", "localhost")) |
|
.stdout(Stdio.Pipe) |
|
.spawn() |
|
child.bufferedStdout()?.lines()?.forEach { line -> |
|
println(line) |
|
} |
|
child.wait() |
|
} |
|
package com.kgit2.kommand |
|
|
|
import com.kgit2.kommand.process.Command |
|
import com.kgit2.kommand.process.Stdio |
|
|
|
fun main() { |
|
Command("echo") |
|
.arg("nothing") |
|
.stdout(Stdio.Null) |
|
.spawn() |
|
.wait() |
|
} |
|
package com.kgit2.kommand |
|
|
|
import com.kgit2.kommand.process.Command |
|
import kotlinx.coroutines.Dispatchers |
|
import kotlinx.coroutines.IO |
|
import kotlinx.coroutines.async |
|
import kotlinx.coroutines.runBlocking |
|
import kotlinx.coroutines.withTimeout |
|
import kotlinx.datetime.Clock |
|
|
|
fun main() = runBlocking(Dispatchers.Default) { |
|
// Sleep with regular |
|
val start = Clock.System.now() |
|
val status = Command("sleep").arg("5").status() |
|
println("status: $status elapsed: ${Clock.System.now() - start}") |
|
|
|
// Sleep with timeout detection and timeout determination |
|
val start2 = Clock.System.now() |
|
val child = Command("sleep").arg("5").spawn() |
|
val childJob = async(Dispatchers.IO) { |
|
runCatching { |
|
child.wait() |
|
}.onFailure { |
|
println("child result: $it") |
|
}.getOrNull() |
|
} |
|
runCatching { |
|
withTimeout(3000) { |
|
childJob.await() |
|
} |
|
}.onSuccess { |
|
println("status: $it elapsed: ${Clock.System.now() - start2}") |
|
}.onFailure { |
|
child.kill() |
|
println("status: $it elapsed: ${Clock.System.now() - start2}") |
|
} |
|
|
|
// Sleep with timeout detection and determination that it will not timeout |
|
val start3 = Clock.System.now() |
|
val child2 = Command("sleep").arg("2").spawn() |
|
val childJob2 = async(Dispatchers.IO) { |
|
runCatching { |
|
child2.wait() |
|
}.onFailure { |
|
println("child result: $it") |
|
}.getOrNull() |
|
} |
|
runCatching { |
|
withTimeout(3000) { |
|
childJob2.await() |
|
} |
|
}.onSuccess { |
|
println("status: $it elapsed: ${Clock.System.now() - start3}") |
|
}.onFailure { |
|
child2.kill() |
|
println("status: $it elapsed: ${Clock.System.now() - start3}") |
|
} |
|
|
|
Unit |
|
} |
完成示例 kommand-examples/timeout.
依赖:
- rust toolchain - <= 1.69.0 (https://rustup.rs) (建议)
- cross (install with
cargo install cross
)
- just (install with
cargo install just
)
- 交叉编译工具链
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-pc-windows-gnu (mingw-w64)
- docker (可选)
强烈推荐在 macOS 编译所有平台。
Kotlin Multiplatform 在 macOS 有更好的支持
如果你使用 macOS , 你可以用下述命令安装工具链
否则, 你需要自行安装工具链
git clone https://github.com/kgit2/kommand.git
仅 linux 平台支持跨平台测试.
Install Docker Engine
# for x86_64
just linuxX64Test
# for aarch64
just linuxArm64Test
@BppleMan.
@XJMiada.(Original Picture)
Apache2.0 © BppleMan