Home > front end >  Gradle copy task runs on clean
Gradle copy task runs on clean

Time:10-25

I have a gradle Copy task that copies assets from the project directory into the build directory:

tasks.register("copyAssets", Copy) {
    def fromDir = "${project.projectDir.toString()}/../assets"
    def toDir = "${project.buildDir.toString()}/assets"

    println "Copying assets"
    println "   from $fromDir"
    println "   into $toDir"

    from fromDir
    into toDir
}

build.dependsOn copyAssets
run.dependsOn copyAssets

This works, but somehow it not only runs on build and run, but also on clean.

If I remove both lines with dependsOn, it doesn't run on build, run, or clean. But as soon as I put the line with build.dependsOn in, the task runs on build, run, and clean. If, on the other hand, I remove build.dependsOn and put in run.dependsOn instead, the outcome is the same: The task runs on build, run, and clean.

How does dependsOn work? How can I make it to run on build and run, but not on clean?

I use gradle wrapper, and it's a multi-module project, i.e.

./gradlew main:clean
./gradlew main:build
./gradlew main:run

The task is in the main module only, not inside the top-level build.gradle.

CodePudding user response:

Interesting question, as it mixes two of the most common mistakes or confusion made when using Gradle:

  • confusion between task configuration and execution phases
  • misuse of task configuration avoidance feature.

Task configuration vs execution phase

Lots of SO questions are dealing with this topic , just search "configuration vs execution phase" for answers explaining this in details. One example : Gradle always does println from any task

In your example: you say that copyAssets task is also executed when running clean task but in fact it's not executed, it's just configured.

Executing gradle build:

> Configure project :sample
Copying assets              <==== the println  are executed, because  they are part of the Configuration phase
   from src
   into /path/sample/build/

> Task :sample:assemble UP-TO-DATE
> Task :sample:check UP-TO-DATE
> Task :sample:copyAssets     <<<=====   task copyAssets is executed as expected
> Task :sample:build

Executing gradle clean:

> Configure project :sample
Copying assets     <==== the println  are still executed, because  they are part of the Configuration phase
   from src
   into /path/sample/build/

> Task :sample:clean    <<<=====   task copyAssets is NOT executed, only clean task is.

You can check that when calling clean, you assets will not be copied, you will just see the println in console. Note that you will also see these println when executing any other task ( e.g. gradle help, gradle tasks ...)

Task configuration avoidance issue

You are declaring your task using the register API, which enables Task configuraiton avoidance feature. So, in theory, the copyAssets should be configured only if it must be executed (=> only when you invoke build or run tasks in your example)

So why is it configured (but not executed) when executing clean in your example ?

This is due to the way you are declaring the tasks dependencies , as explained in the Task configuration avoidance pitfalls section/

build.dependsOn copyAssets

=> this will eagerly create and configure the build task, and in cascade will also create and configure the dependent copyAssets task.

There are several ways to fix this, given in the link above. One example:

// replace 
build.dependsOn copyAssets

// with:
build.dependsOn tasks.named("copyAssets")

CodePudding user response:

Ah! you have put in the default task closure - the steps happen at task initialisation.

tasks.register("copyAssets", Copy) {
    doLast() {
        def fromDir = "${project.projectDir.toString()}/../assets"
        def toDir = "${project.buildDir.toString()}/assets"

        println "Copying assets"
        println "   from $fromDir"
        println "   into $toDir"

        from fromDir
        into toDir
    }
}

read - https://docs.gradle.org/current/userguide/more_about_tasks.html#header

  • Related