I'd like to know if there's a way in kotlin native to call a command via posix and receive it's terminal output. For example, I'd like to get the "git diff" command working without having to create a temporary file, write output to it and then read from that file.
On SO I've only found solutions requiring ProcessBuilder, which isn't available on kotlin-native, as it's a Java library.
I found a working piece of code I wanted to use, so I'm posting it here for future viewers!
fun executeCommand(command: String): String{
val fp: CPointer<FILE>? = popen(command, "r")
val buffer = ByteArray(4096)
val returnString = StringBuilder()
/* Open the command for reading. */
if (fp == NULL) {
printf("Failed to run command\n" )
exit(1)
}
/* Read the output a line at a time - output it. */
var scan = fgets(buffer.refTo(0), buffer.size, fp)
if(scan != null) {
while (scan != NULL) {
returnString.append(scan!!.toKString())
scan = fgets(buffer.refTo(0), buffer.size, fp)
}
}
/* close */
pclose(fp)
return returnString.trim().toString()
}
Usually you can use the POSIX api and use fork and wait and some I/O related functions for your purpose
fun main() {
val childPid: pid_t = fork()
if (childPid == 0) {
val commands = listOf("git", "diff", "HEAD^1", "$projectDir/path/to/file", null)
val cwd = "$projectDir"
chdir(cwd)
memScoped {
execvp(commands[0], allocArrayOf(commands.map { it?.cstr?.ptr }))
}
} else {
wait(null)
}
}
Of course, this needs to deal with a lot of c-style code, so I also wrote a more practical library for this
repositories {
mavenCentral()
}
// add dependencies into your native target sourceSet
dependencies {
implementation("com.kgit2:kommand:1.0.1")
}
It is also very simple to use
fun main(args: Array<String>) {
val diffResult = Command("git")
.args("diff", "HEAD^1", "$projectDir/path/to/file")
.cwd("$projectDir")
.spawn()
.output()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With