How to run execute string as a shell command in Kotlin DSL?

I’m migrating to Kotlin DSL.
The old commands look like:

final gitBranch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()
final gitTag = "git tag -l --points-at HEAD".execute().text.trim()
final gitCommitId = "git rev-parse --short=8 HEAD".execute().text.trim()

In Kotlin DSL i have not found the same way.
Tried this approach:https://stackoverflow.com/questions/35421699/how-to-invoke-external-command-from-within-kotlin-code

but is there is any built-in way?

Perhaps the kotlin equivalent of

project.exec {
   commandLine = "git rev-parse --abbrev-ref HEAD".split(" ")
} 

But how than i capture the output?

String.execute() is a groovy enhancement which is why it’s not available in Kotlin. It has nothing to do with Gradle. See Groovy String Enhancements

But how than i capture the output?

See Project.exec(ExecSpec)

Eg:

ByteArrayOutputStream byteOut = new ByteArrayOutputStream() 
project.exec {
   commandLine = "git rev-parse --abbrev-ref HEAD".split(" ")
   standardOutput = byteOut
} 
String output = new String(byteOut.toByteArray())

I hoped to have smth shorter ((. Than i’d better introduce a function, like in this answer:

fun String.runCommand(workingDir: File = file("./")): String {
    val parts = this.split("\\s".toRegex())
    val proc = ProcessBuilder(*parts.toTypedArray())
            .directory(workingDir)
            .redirectOutput(ProcessBuilder.Redirect.PIPE)
            .redirectError(ProcessBuilder.Redirect.PIPE)
            .start()

    proc.waitFor(1, TimeUnit.MINUTES)
    return proc.inputStream.bufferedReader().readText().trim()
}

I’d use project.exec rather than ProcessBuilder directly. I’m sure there’s some nice error handling etc in the Gradle version

unfortunately i’ve not understood how to use that code snippe with project.exec. Shall i repeat all these 5 lines for each command i want to execute?

with ProcessBuilder i declare fun runCommand once and reuse it in the build script:

fun String.runCommand(workingDir: File = file("./")): String {
    val parts = this.split("\\s".toRegex())
    val proc = ProcessBuilder(*parts.toTypedArray())
            .directory(workingDir)
            .redirectOutput(ProcessBuilder.Redirect.PIPE)
            .redirectError(ProcessBuilder.Redirect.PIPE)
            .start()

    proc.waitFor(1, TimeUnit.MINUTES)
    return proc.inputStream.bufferedReader().readText().trim()
}

val gitBranch = "git rev-parse --abbrev-ref HEAD".runCommand()
val gitTag = "git tag -l --points-at HEAD".runCommand()
val gitCommitId = "git rev-parse --short=8 HEAD".runCommand()

Here’s what it might look like in groovy

def runCommand = { Project project, String command ->
   ByteArrayOutputStream byteOut = new 
   ByteArrayOutputStream() 
   project.exec {
      commandLine = command.split(" ")
      standardOutput = byteOut
   } 
   return new String(byteOut.toByteArray()).trim()
}
def gitBranch = runCommand(project, "git rev-parse --abbrev-ref HEAD") 
def gitTag = runCommand(project, "git tag -l --points-at HEAD") 
def gitCommitId = runCommand(project, "git rev-parse --short=8 HEAD") 
1 Like

ok, for Kotlin DSL it looks like this:

fun String.runCommand(currentWorkingDir: File = file("./")): String {
    val byteOut = ByteArrayOutputStream()
    project.exec {
        workingDir = currentWorkingDir
        commandLine = this@runCommand.split("\\s".toRegex())
        standardOutput = byteOut
    }
    return String(byteOut.toByteArray()).trim()
}

val gitBranch = "git branch --show-current".runCommand()
val gitTag = "git tag -l --points-at HEAD".runCommand()
val gitCommitId = "git rev-parse HEAD".runCommand()
1 Like

There is a kotlin library for easy run external command

Add this gradle dependency:

implementation("com.sealwu:kscript-tools:1.0.1")

And can run comamnd like this:

"cd ~ && ls".runCommand()

Output:

Applications   Downloads      MavenDep       Pictures       iOSProjects
Desktop        IdeaProjects   Movies         Public         scripts
Documents      Library        Music          StudioProjects

Also you can get the output of command line by using evalBash

val date = "date".evalBash().getOrThrow()  //execute shell command `date` and get the command's output and set the content to date variable
println(date) //This will print Fri Aug 19 21:59:56 CEST 2022 on console
val year = date.substringAfterLast(" ") // will get 2022 and assign to 
println(year)

Output:

Fri Aug 19 21:59:56 CEST 2022
2022

And still you shouldn’t use it, but should use Exec task or exec methods to call external processes in the Gradle context. :wink: