Reputation: 11140
I am trying to implement a gradle task to dynamically create a buildsignature.properties file from a series of environment variable values and shell executions. I have it mostly working, but I can't seem to get the output of the shell commands. Here's my task...
task generateBuildSignature << {
ext.whoami = exec() {
executable = "whoami"
}
ext.hostname = exec() {
executable = "hostname"
}
ext.buildTag = System.env.BUILD_TAG ?: "dev"
ant.propertyfile(
file: "${buildDir}/buildsignature.properties",
comment: "This file is automatically generated - DO NOT EDIT!" ) {
entry( key: "version", value: "${project.version}" )
entry( key: "buildTimestamp", value: "${new Date().format('yyyy-MM-dd HH:mm:ss z')}" )
entry( key: "buildUser", value: "${ext.whoami}" )
entry( key: "buildSystem", value: "${ext.hostname}" )
entry( key: "buildTag", value: "$ext.buildTag" )
}
}
But the resulting properties field does not get the desired results for buildUser and buildSystem.
#This file is automatically generated - DO NOT EDIT!
#Mon, 18 Jun 2012 18:14:14 -0700
version=1.1.0
buildTimestamp=2012-06-18 18\:14\:14 PDT
buildUser=org.gradle.process.internal.DefaultExecHandle$ExecResultImpl@2e6a54f9
buildSystem=org.gradle.process.internal.DefaultExecHandle$ExecResultImpl@46f0bf3d
buildTag=dev
How do I get buildUser and buildSystem to match the output of the corresponding exec rather than some default ExecResultImpl toString? This really can't be that hard, can it?
Upvotes: 62
Views: 84255
Reputation: 26811
If you need a lazy configuration method (i.e. Provider
/Property
), you can use the ProviderFactory#exec
method (introduced in Gradle 7.5), which exposes an ExecOutput
which you can then get the standard output from via getStandardOutput
:
// Provider<String>
val outputText = project.providers.exec {
commandLine("whoami")
}.standardOutput.asText // Retrieve stdout as text
// Provider<Array<Byte>>
val outputBytes = project.providers.exec {
commandLine("whoami")
}.standardOutput.asBytes // Or as bytes
You can get a ProviderFactory
from a Project
, or by @Inject
ing it where needed:
// In regular build-scripts:
project.providers.exec { /* ... */ }
// Or
providers.exec { /* ... */ }
// In tasks
class MyTask @Inject constructor(private val providers: ProviderFactory) : DefaultTask() {
val example = providers.exec { /* ... */ }
}
Note that this API is also now stable for use since the Gradle 8.11 release.
Upvotes: 2
Reputation: 757
in buildSrc:
import org.codehaus.groovy.runtime.ProcessGroovyMethods
fun String.execute(): Process = ProcessGroovyMethods.execute(this)
fun Process.text(): String = ProcessGroovyMethods.getText(this)
build.gradle.kts:
"any command you want".execute().text().trim()
in buildSrc:
import org.gradle.api.Project
import org.gradle.process.ExecSpec
import java.io.ByteArrayOutputStream
fun Project.execWithOutput(spec: ExecSpec.() -> Unit) = ByteArrayOutputStream().use { outputStream ->
exec {
this.spec()
this.standardOutput = outputStream
}
outputStream.toString().trim()
}
build.gradle.kts
:
val outputText = project.execWithOutput {
commandLine("whoami")
}
//variable project is actually optional
val outputText = execWithOutput {
commandLine("whoami")
}
Upvotes: 8
Reputation: 4380
Groovy allows for a much simpler implementation in many cases. So if you are using Groovy-based build scripts you can simply do this:
def cmdOutput = "command line".execute().text
Upvotes: 13
Reputation: 47299
Using the kotlin-dsl
:
import java.io.ByteArrayOutputStream
val outputText: String = ByteArrayOutputStream().use { outputStream ->
project.exec {
commandLine("whoami")
standardOutput = outputStream
}
outputStream.toString()
}
Upvotes: 21
Reputation: 11372
This is my preferred syntax for getting the stdout from exec:
def stdout = new ByteArrayOutputStream()
exec{
commandLine "whoami"
standardOutput = stdout;
}
println "Output:\n$stdout";
Found here: http://gradle.1045684.n5.nabble.com/external-process-execution-td1431883.html (Note that page has a typo though and mentions ByteArrayInputStream instead of ByteArrayOutputStream)
Upvotes: 79
Reputation: 7676
Paraphrased from the Gradle docs for Exec:
task execSomething {
doFirst {
exec {
workingDir '/some/dir'
commandLine '/some/command', 'arg'
...
//store the output instead of printing to the console:
standardOutput = new ByteArrayOutputStream()
//extension method execSomething.output() can be used to obtain the output:
ext.output = {
return standardOutput.toString()
}
}
}
}
Upvotes: 7
Reputation: 33456
This post describes how to parse the output from an Exec
invocation. Below you'll find two tasks that run your commands.
task setWhoamiProperty {
doLast {
new ByteArrayOutputStream().withStream { os ->
def result = exec {
executable = 'whoami'
standardOutput = os
}
ext.whoami = os.toString()
}
}
}
task setHostnameProperty {
doLast {
new ByteArrayOutputStream().withStream { os ->
def result = exec {
executable = 'hostname'
standardOutput = os
}
ext.hostname = os.toString()
}
}
}
task printBuildInfo {
dependsOn setWhoamiProperty, setHostnameProperty
doLast {
println whoami
println hostname
}
}
There's actually an easier way to get this information without having to invoke a shell command.
Currently logged in user: System.getProperty('user.name')
Hostname: InetAddress.getLocalHost().getHostName()
Upvotes: 61