Home > Net >  Example from Gradle documentation: Configuration and execution phase
Example from Gradle documentation: Configuration and execution phase

Time:04-24

The Gradle documentation, chapter "Avoiding traps", has an example "Configuration and execution phase". Link

It is important to keep in mind that Gradle has a distinct configuration and execution phase (see Build Lifecycle).

def classesDir = file('build/classes')
classesDir.mkdirs()
tasks.register('clean', Delete) {
    delete 'build'
}
tasks.register('compile') {
    dependsOn 'clean'
    doLast {
        if (!classesDir.isDirectory()) {
            println 'The class directory does not exist. I can not operate'
            // do something
        }
        // do something
    }
}

There are 2 tasks, compile and clean. The build directory is created as part of the project. The clean task contains a command to delete the build directory. The compile task contains a check, whether a subdirectory of the build directory exists.

At first this seemed to be an easy-to-understand example: a directory isn't available, because it gets deleted earlier. But then i noticed something that i can't understand.

As the creation of the directory happens during the configuration phase, the clean task removes the directory during the execution phase.

I understand the first part, as the build directory is created during the configuration phase of the project. What i don't understand is the second part. The documentation says this happens during the execution phase. But the removal of the directory isn't wrapped in a doFirst or doLast block, so this part of the task should happen during the configuration phase.

Trying to understand, round 1

To get a better overview, i added more println and removed the comment-only lines.

def classesDir = file('build/classes')
classesDir.mkdirs()
println "configuration phase of project";
tasks.register('clean', Delete) {
    println "step 1 in configuration phase of " getName();
    delete 'build'
    println "step 3 in configuration phase of " getName();
}
tasks.register('compile') {
    println "configuration phase of " getName();
    dependsOn 'clean'
    doLast {
        if (!classesDir.isDirectory()) {
            println 'The class directory does not exist. I can not operate'
        }
    }
}

Starting gradle via ./gradlew compile --info provided the following output.

configuration phase of project
All projects evaluated.
configuration phase of compile
Selected primary task 'compile' from project :
step 1 in configuration phase of clean
step 3 in configuration phase of clean
Tasks to be executed: [task ':clean', task ':compile']
Tasks that were excluded: []
:clean (Thread[Execution worker for ':',5,main]) started.

> Task :clean
Caching disabled for task ':clean' because:
  Build cache is disabled
Task ':clean' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
:clean (Thread[Execution worker for ':',5,main]) completed. Took 0.002 secs.
:compile (Thread[Execution worker for ':',5,main]) started.

> Task :compile
Caching disabled for task ':compile' because:
  Build cache is disabled
Task ':compile' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
The class directory does not exist. I can not operate
:compile (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.

I didn't get more information from this output, regarding my question. Why is the directory deleted during the execution phase, despite not being wrapped in a doFirst or doLast block? Does this have something to do with Delete?

Trying to understand, round 2

I wanted to believe this is a mistake in the documentation, but after modifying the code a little bit more, this doesn't fit.

def classesDir = file('build/classes');
classesDir.mkdirs();

tasks.register('clean', Delete) {
    doFirst {
        delete 'build';
        println "[debug-print] (" getName() ") build directory exists in doFirst: " file("build").exists();
    }
    doLast {
        println "[debug-print] (" getName() ") build directory exists in doLast: " file("build").exists();
    }
}

tasks.register('compile') {
    dependsOn 'clean'
    doFirst {
        println "[debug-print] (" getName() ") build directory exists in doFirst: " file("build").exists();
    }
    doLast {
        println "[debug-print] (" getName() ") build directory exists in doLast: " file("build").exists();
    }
}

The output of ./gradlew compile is:

> Task :clean
[debug-print] (clean) build directory exists in doFirst: true
[debug-print] (clean) build directory exists in doLast: false

> Task :compile
[debug-print] (compile) build directory exists in doFirst: false
[debug-print] (compile) build directory exists in doLast: false

This looks like delete isn't actually deleting the directory, or at least not right away. This matches the javadoc of Delete:

Adds some files to be deleted by this task.

But then again, i don't understand when the actual directory removal happens. During the execution phase, but not in doFirst and not in doLast? This doesn't match my understanding of the execution phase.

CodePudding user response:

tasks.register('clean', Delete) {
    println "step 1 in configuration phase of " getName();
    delete 'build'
    println "step 3 in configuration phase of " getName();
}

This one configures the Delete task via Delete.delete(), which queues what to delete during configuration, but the actual action of the task does not happen until the execution phase.

tasks.register('clean', Delete) {
    doFirst {
        delete 'build';
        println "[debug-print] (" getName() ") build directory exists in doFirst: " file("build").exists();
    }
    doLast {
        println "[debug-print] (" getName() ") build directory exists in doLast: " file("build").exists();
    }
}

This one appears to be queueing the directory to delete via Delete.delete() during the execution phase (modifying the task configuration on-the-fly), before the task action executes. It seems this way because doFirst { } runs during execution, and the directory is gone during doLast { }.

  • Related