Как использовать вывод exec() в gradle

Я пытаюсь реализовать задачу gradle для динамического создания файла buildsignature.properties из ряда значений переменных среды и выполнения оболочки. У меня это в основном работает, но я не могу получить вывод команд оболочки. Вот моя задача...

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

Но результирующее поле свойств не дает желаемых результатов для buildUser и 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

Как мне заставить buildUser и buildSystem соответствовать выходным данным соответствующего exec, а не некоторому ExecResultImpl toString по умолчанию? Это действительно не может быть так сложно, не так ли?


person Bob Kuhar    schedule 19.06.2012    source источник


Ответы (5)


В этом сообщении описывается, как анализировать вывод из вызова Exec. Ниже вы найдете две задачи, которые запускают ваши команды.

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

На самом деле есть более простой способ получить эту информацию без вызова команды оболочки.

Текущий зарегистрированный пользователь: System.getProperty('user.name')

Имя хоста: InetAddress.getLocalHost().getHostName()

person Benjamin Muschko    schedule 19.06.2012
comment
Легко лучше. Я действительно не ожидал, что для захвата вывода команды оболочки потребуется ручной анализ выходного потока. Независимо от того. Спасибо за руководство. - person Bob Kuhar; 19.06.2012
comment
Быстрый вопрос, не отсутствует ли ваш код standardOutput = os ?? - person Nick Grealy; 21.03.2014
comment
Когда мы это делаем, это кажется асинхронным. Он пытается вывести whoami и имя хоста до того, как они существуют. Идеи? - person JOATMON; 26.03.2014
comment
@ScottBeeson за годы, прошедшие после этого поста, мой build.gradle теперь использует System.getProperty('user.name') и InetAddress.getLocalHost().getHostName() для достижения цели этого поста. Я подозреваю, что это может преодолеть любое состояние гонки, которое вы видите. - person Bob Kuhar; 26.03.2014
comment
Сможете ли вы сделать println whoami? Вы устанавливаете эти свойства для ext задач внутри них, не так ли? Разве это не должно быть project.ext.hostname = os.toString() или я что-то упускаю? - person Taras Leskiv; 23.07.2015
comment
@Taras После определения дополнительного свойства вам больше не нужно быть явным. Оба работают. - person Benjamin Muschko; 23.07.2015

Это мой предпочтительный синтаксис для получения стандартного вывода из exec:

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

Найдено здесь: http://gradle.1045684.n5.nabble.com/external-process-execution-td1431883.html (обратите внимание, что на странице есть опечатка и упоминается ByteArrayInputStream вместо ByteArrayOutputStream)

person Taytay    schedule 01.12.2012
comment
град 3.3: это не работает. Если я закомментирую println ничего не произойдет, если я его раскомментирую - в выводе будет много новых строк, странно, но даже слова вывода нет - person Tertium; 29.03.2017

Используя kotlin-dsl:

import java.io.ByteArrayOutputStream

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

Перефразируя документы Gradle для 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()
      }
    }
  }
}
person javabrett    schedule 01.12.2017
comment
Это ничего не показывает в Android Studio, если задача не выполняется вручную двойным щелчком в окне проекты Gradle. - person zwcloud; 10.08.2018

Groovy во многих случаях допускает гораздо более простую реализацию. Итак, если вы используете сценарии сборки на основе Groovy, вы можете просто сделать это:

def cmdOutput = "command line".execute().text
person swpalmer    schedule 26.09.2020
comment
def x = 'bash -c echo & echo $!'.execute().text должно ли это работать? - person Stefan Falk; 08.01.2021
comment
@StefanFalk bash -c .... похоже, вывод не захвачен должным образом, нет. У меня 'echo hello'.execute().text сработало - person swpalmer; 09.01.2021
comment
самое простое решение здесь - person cdalxndr; 30.03.2021