This message was deleted.
# kotlin-dsl
s
This message was deleted.
v
127 usually means "command not found". Maybe your working directory is not as expected to find the
script.sh
or it calls something that is not found. Also I don't think you can display the streams that way, especially when the command failed as your
doLast
action will then not be found. You should probably either set the property to ignore the exit code and then fail after outputting the streams in your
doLast
action, or right away do not use an
Exec
task, but use
exec { ... }
instead. But also there you will need to configure to ignore the exit code and then fail after outputting the streams.
Also, your question has not much to do with Kotlin DSL except that you use it, so #CAHSN3LDN would have been more appropriate. 😉
1
g
I can move it (or reference) there no problem 🙂
Maybe your working directory is not as expected to find the
script.sh
or it calls something that is not found.
Shouldn’t the same behavior apply to the terminal? I can run my script via the terminal in the same directory. Does Gradle have different access policies?
I’ve project where I can run command via terminal in a jvm app, I’ve tried to apply the same logic but the errors were similar
Copy code
Oh wow I could make it work by this:

tasks.register("runBashScript") {
    doFirst {
        println("> Executing runBashScript task")
    }

    val output = listOf("zsh", "-c", "./script.sh").runCommand(project.projectDir)

    doLast {
        println("> Output: $output")
    }
}

fun List<String>.runCommand(workingDir: File = File("."), timeoutAmount: Long = 60, timeoutUnit: TimeUnit = TimeUnit.SECONDS): String {
    return try {
        runCatching {
            ProcessBuilder(this)
                .directory(workingDir)
                .redirectOutput(ProcessBuilder.Redirect.PIPE)
                .redirectError(ProcessBuilder.Redirect.PIPE)
                .start()
                .also { it.waitFor(timeoutAmount, timeoutUnit) }
                .inputStream.bufferedReader().readText()
        }.onFailure { it.printStackTrace() }.getOrThrow()
    } catch (e: Exception) {
        e.message ?: e.cause?.message ?: "Exception occurred, but no message found"
    }
}
I still cannot see the output from the script, but it gives me success 🤔
v
Your working dir might not be what you expect. It is not necessarily the project directory. This is sometimes the case, sometimes not. That's also why any build that depends on something using
File
constructor with a relative path is inherently broken and can fail any time.
g
could be a false positive but:
Copy code
./gradlew runBashScript
> Task :runBashScript
> Executing runBashScript task
> Output: 
BUILD SUCCESSFUL in 2s
I think this made it work:
project.projectDir
v
As I said, set the working directory to the project directory and it might work with
Exec
or
exec
Then also configure to ignore the exit code, so that you can output the streams even in failure case and fail after that if the exit code was not success
g
I was doing this:
Copy code
tasks.register<Exec>("script") {
    workingDir = project.projectDir
}
but for some reason it wasn’t working. Then I removed the “exec” type and used my helper function and now I have BUILD SUCCESSFUL.
how can I configure this:
ignore the exit code
I was trying to find an Exec property
v
_isIgnoreExitValue_ = true
1
But you might need to use
exec { ... }
instead of an
Exec
task to then access the exit value to actually make it fail after outputting the streams. Iirc you cannot do this with an
Exec
task.
Something like
Copy code
tasks.register("script") {
    doLast {
        val result = exec {
            workingDir(layout.projectDirectory)
            // ...
            isIgnoreExitValue = true
        }
        // output streams
        result.assertNormalExitValue()
    }
}
g
like this?
Copy code
tasks.register("runBashScript") {
    doLast {
        println("> Executing runBashScript task")
        val result = exec {
            workingDir(layout.projectDirectory)
            isIgnoreExitValue = true
            commandLine("bash", "-c", "./script.sh")
        }
        result.assertNormalExitValue()
        println(result.exitValue)
    }
}
v
No,
assertNormalExitValue
throws on non-0, so your println will only reached on success, so it will print either 0 or not be called. The assert should be last, as it actually fails the task immediately.
And you miss your outputting of the streams
"output streams" was not an explanation, but a placeholder where you should put the outputting of the streams
g
always getting that 127 😞
OK made it work!
I’ve changed a little the approach:
Copy code
tasks.register("runBashScript") {
    doFirst {
        println("> Executing runBashScript task")
    }

    val process = ProcessBuilder("fuuuuuuuuulPath/script.sh")
        .directory(layout.projectDirectory.asFile)
        .redirectOutput(ProcessBuilder.Redirect.PIPE)
        .redirectError(ProcessBuilder.Redirect.PIPE)
        .start()

    val output = process.inputStream.bufferedReader().readText()

    doLast {
        val exitCode = process.waitFor()
        if (exitCode == 0) {
            println("> Script executed successfully: \n $output")
        } else {
            println("> Script execution failed with exit code $exitCode.")
        }
    }
}
now I just have to be able to get the relative path instead of the “full path”
I thought this would be enough 🤔
Copy code
.directory(layout.projectDirectory.asFile)
v
This works perfectly fine here:
Copy code
tasks.register("runBashScript") {
    doLast {
        println("> Executing runBashScript task")

        val out = ByteArrayOutputStream()
        val err = ByteArrayOutputStream()
        val result = exec {
            standardOutput = out
            errorOutput = err
            workingDir(layout.projectDirectory)
            isIgnoreExitValue = true
            commandLine("bash", "-c", "./script.sh")
        }

        println("Command Output:")
        println(out.toString())
        println("Command Error:")
        println(err.toString())

        result.assertNormalExitValue()
    }
}
But only necessary if you als want to check the contents of out and err
If you just want to print them, that's not necessary, then you can simply do
Copy code
tasks.register<Exec>("runBashScript") {
    doFirst {
        println("> Executing runBashScript task")
    }
    workingDir(layout.projectDirectory)
    commandLine("bash", "-c", "./script.sh")
}
Also works fine here
If it does not for you, please share an MCVE
g
it does work 🙂
../script.sh
instead of
./script.sh
👀 🤦 😞
v
Seems the script is not in the project directory of the project where you have the task, but one directory up 🙂
1
g
yeah i was calling it from a module build.gradle and not from the projects’ root build.gradle
I need the weekend. 😅
👌 1