A Gradle task (type: Exec) is not executed during the configuration phase - gradle

I am reading about Gradle build lifecycle
Here is my script:
task startTomcat(type:Exec) {
commandLine 'cmd', '/c', 'echo init startTomcat'
}
task stopTomcat(type:Exec) {
// on windows:
commandLine 'cmd', '/c', 'echo init stopTomcat!'
doLast {
commandLine 'cmd', '/c', 'echo doLast stopTomcat!'
}
}
task configured(type:Exec) {
println 'configured. method body'
}
task test2 {
doLast {
println 'test2 doLast'
}
}
task testBoth2 {
doFirst {
println 'testBoth2 doFirst'
}
doLast {
println 'testBoth2 doLast'
}
println 'testBoth2. method body'
}
I run task2:
gradlew test2
This is the output:
Parallel execution with configuration on demand is an incubating feature.
configured. method body
testBoth2. method body
:test2
test2 doLast
BUILD SUCCESSFUL
It looks like the calls to commandLine were ignored. Why?

The Exec task's commandLine properly only configures what to do if the task is executed. As such you don't see the actual command doing anything during the configuration phase.

Related

Custom Gradle exec tasks won't run in parallel

My goal is that I can run ./gradlew deployStaging, and it executes buildDockerStatic, and buildDockerBackend in parallel, and after both tasks have finished, the deployStaging will run. With the code below, the tasks run serially. I've tried a few things, but buildDockerStatic, and buildDockerBackend always run serially.
tasks.register("buildDockerStatic", BuildDockerStatic) {
workingDir rootDir
}
tasks.register("buildDockerBackend", BuildDockerBackend) {
workingDir rootDir
}
//noinspection GroovyAssignabilityCheck
task deployStaging() {
dependsOn tasks.buildDockerStatic
dependsOn tasks.buildDockerBackend
doLast {
exec {
workingDir rootDir
commandLine 'sh', './scripts/build_deploy_staging.sh'
}
}
}
class BuildDockerStatic extends AbstractExecTask<BuildDockerStatic> {
BuildDockerStatic() {
//noinspection GroovyAssignabilityCheck
super(BuildDockerStatic)
commandLine 'sh', './scripts/build_static.sh'
}
}
class BuildDockerBackend extends AbstractExecTask<BuildDockerBackend> {
BuildDockerBackend() {
//noinspection GroovyAssignabilityCheck
super(BuildDockerBackend)
commandLine 'sh', './scripts/build_backend.sh'
}
}
In order to be run in parallel, the build tasks need to be placed in sub-projects.
They should contain doLast; otherwise they will be executed when calling eg. gradle clean. And probably, a definition using the plain task {..} will be enough.
Parallel: from the docs at Gradle:parallel execution
By using the --parallel switch, you can force Gradle to execute tasks in parallel as long as those tasks are in different projects.
See a modified example below; it will run two sub-tasks (to sleep and log), in parallel.
It can be run with gradle clean deployStaging --parallel
Multi project structure
build-backend
+--build.gradle
build-static
+--build.gradle
build.gradle
settings.gradle
build-backend/build.gradle :
apply plugin: 'base'
task buildDockerBackend {
doLast{
exec {
println 'BuildDockerBackend: started at ' + new java.util.Date()
workingDir rootDir
sleep 4000
//commandLine 'sh', './scripts/build_backend.sh'
commandLine 'echo', 'task: build-backend'
println 'BuildDockerBackend: done at ' + new java.util.Date()
}
}
}
build-static/build.gradle
apply plugin: 'base'
task buildDockerStatic {
doLast{
exec {
println 'BuildDockerStatic: started at ' + new java.util.Date()
workingDir rootDir
sleep 8000
//commandLine 'sh', './scripts/build_static.sh'
commandLine 'echo', 'task: build-static'
println 'BuildDockerStatic: done at ' + new java.util.Date()
}
}
}
build.gradle
apply plugin: 'base'
task deployStaging {
doLast {
exec {
workingDir rootDir
//commandLine 'sh', './scripts/build_deploy_staging.sh'
commandLine 'echo', 'task: deploy-staging'
}
}
}
deployStaging.dependsOn ':build-static:buildDockerStatic'
deployStaging.dependsOn ':build-backend:buildDockerBackend'
settings.gradle
include 'build-static'
include 'build-backend'

how can i add a gradle exec task with properties?

i have a problem with a gradle exec task.
code:
task startup {
final GradleVersion gradleVersion = GradleVersion.current()
println "##### start script #####"
println "gradle version: ${gradleVersion}"
println "project: ${project.group}.fmp-${project.name}-${project.version}"
}
task create(type: Exec) {
workingDir "./scripts"
commandLine "./create_service_from_template.sh", sn, gwv
}
So when I execute gradle create -Psn=test -Pgwv=4.0 then it works.
but when I start another task (like gradle startup then an error appears:
Could not get unknown property 'sn' for task ':create' of type org.gradle.api.tasks.Exec.
I thought I can put the lines in the create Task into a doLast block, but then it doesn't work.
Can some one help me please?
Thanks.
This happens because Gradle will run the Configuration phase on all tasks.
One fix is to use local variables which are initialized with a check to see if the property was specified. See the beginning:
def sn = project.hasProperty('sn') ? project.sn : ''
def gwv = project.hasProperty('gwv') ? project.gwv : ''
task startup {
final GradleVersion gradleVersion = GradleVersion.current()
println "##### start script #####"
println "gradle version: ${gradleVersion}"
println "project: ${project.group}.fmp-${project.name}-${project.version}"
}
task create(type: Exec) {
workingDir "./scripts"
commandLine "./create_service_from_template.sh", sn, gwv
}

Gradle set ext property in one task and use it in another

I have several tasks which executes different SQL scripts via psql.
task runScript1(type: Exec) {
commandLine 'cmd', '/c', "psql -f script1.sql"
}
task runScript2(type: Exec) {
commandLine 'cmd', '/c', "psql -f script2.sql"
}
Now I want to write one generic exec task and pass only the script name to it.
ext {
scriptName = ''
}
task runScriptGeneric(type: Exec) {
commandLine 'cmd', '/c', "psql -f ${scriptName}"
}
task runScript1() {
scriptName = 'script1.sql'
}
runScript1.finalizedBy runScriptGeneric
task runScript2() {
scriptName = 'script2.sql'
}
runScript2.finalizedBy runScriptGeneric
Unfortunately this approach is not working. The scriptName stays empty in the runScriptGeneric task.
I suspect this has to do with the Exec type because the following simple task working well.
ext {
scriptName = ''
}
task runScriptGeneric() {
doLast {
println "${scriptName}"
}
}
task runScript1() {
doLast {
scriptName = 'script1.sql'
}
}
runScript1.finalizedBy runScriptGeneric
task runScript2() {
doLast {
scriptName = 'script2.sql'
}
}
runScript2.finalizedBy runScriptGeneric
I do not want do pass it over as a command line parameter (-PscriptName), because I want to keep the individual tasks for each script. Is there any other way to pass the scriptName from each individual task to the generic task?
Actually, it's not an answer to my question, but it's a solution I can live with.
I've created a dynamic task instead of passing the variable to the executing script:
['Script1', 'Script2'].each {taskName ->
task "run${taskName}"(type: Exec) {
commandLine 'cmd', '/c', "psql -f ${taskName}"
}
}

Gradle, task type: Exec - commandLine not work in onLast

I want execute some command from command line in gradle task(e.g. print all files in dir):
task dir(type: Exec) {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
doLast {
println ("result = " + standardOutput)
}
}
It's work. OK. But when I put it on onLast section it's not work:
task dir(type: Exec) {
doLast {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
println ("result = " + standardOutput)
}
}
I get error:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:dir'.
execCommand == null!
The reason is in the fact, that task of Exec should be configured during configuration phase of the build, otherwise your task will be not configured and fail.
In you first example everything works due to configuration happens at the configuratyion phase. Your second example tries to configure the task within doLast closure - right after the task is executed yet.
If you really need to execute something in doLast, you can use something like this, without creating special task:
task someTaskName {
doLast {
exec {
commandLine adbCommand
}
}
}
Here is exec-specification used to execute some command and it's configured and executed at the same time.

Gradle, commandLine 'cmd', '/c', 'echo doLast!' does nothing

I'm reading about Gradle Exec and created the following build.gradle:
task startTomcat(type:Exec) {
commandLine 'cmd', '/c', 'echo init startTomcat'
}
task stopTomcat(type:Exec) {
// on windows:
commandLine 'cmd', '/c', 'echo init stopTomcat!'
doLast {
commandLine 'cmd', '/c', 'echo doLast stopTomcat!'
}
}
When I run gradlew stopTomcat, the output looks like this:
Parallel execution with configuration on demand is an incubating feature.
:stopTomcat
init stopTomcat!
I don't see the line doLast stopTomcat! Why can't I execute a command in doLast?
Your task is of type Exec. The commandLine method call configures the task by passing the cmd, /c and echo init stopTomcat! to it. This happens in the config phase.
Then the task runs in execution phase and prints:
init stopTomcat!
Then the doLast blocks starts and configures the task, passing cmd, /c and echo doLast stopTomcat! to it. This configuration has no effect as the taks already ran.
To get the second print out, you could do:
task stopTomcat(type:Exec) {
// on windows:
commandLine 'cmd', '/c', 'echo init stopTomcat!'
doLast {
exec {
commandLine 'cmd', '/c', 'echo doLast stopTomcat!'
}
}
}
This is another way how to invoke the exec task.

Resources