Cómo usar la salida exec () en gradle

Estoy tratando de implementar una tarea de Gradle para crear dinámicamente un archivo buildsignature.properties a partir de una serie de valores de variables de entorno y ejecuciones de shell. Lo tengo funcionando principalmente, pero parece que no puedo obtener el resultado de los comandos de shell. Esta es mi tarea ...

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" )
    }
}

Pero el campo de propiedades resultante no obtiene los resultados deseados para buildUser y 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.DefaultExecHandl[email protected]
buildSyst[email protected]46f0bf3d
buildTag=dev

¿Cómo consigo que buildUser y buildSystem coincidan con la salida del exec correspondiente en lugar de algunos ExecResultImpl toString predeterminados? Esto realmente no puede ser tan difícil, ¿verdad?

Answer

Esta es mi sintaxis preferida para obtener la salida estándar del ejecutivo:

def stdout = new ByteArrayOutputStream()
exec{
    commandLine "whoami"
    standardOutput = stdout;
}
println "Output:\n$stdout";

Encontrado aquí: http://gradle.1045684.n5.nabble.com/external-process-execution-td1431883.html (Tenga en cuenta que la página tiene un error tipográfico y menciona ByteArrayInputStream en lugar de ByteArrayOutputStream)

Esta publicación describe cómo analizar la salida de una Execinvocación. A continuación, encontrará dos tareas que ejecutan sus comandos.

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
    }
}

En realidad, existe una forma más fácil de obtener esta información sin tener que invocar un comando de shell.

Usuario actualmente conectado: System.getProperty('user.name')

Nombre de host: InetAddress.getLocalHost().getHostName()

Usando el kotlin-dsl:

import java.io.ByteArrayOutputStream

val outputText: String = ByteArrayOutputStream().use { outputStream ->
  project.exec {
    commandLine("whoami")
    standardOutput = outputStream
  }
  outputStream.toString()
}

Parafraseado de los documentos de Gradle para 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()
      }
    }
  }
}

Groovy permite una implementación mucho más simple en muchos casos. Entonces, si está utilizando scripts de compilación basados ​​en Groovy, simplemente puede hacer esto:

def cmdOutput = "command line".execute().text