Why are automatic clean tasks not called as part of the default / global clean?

Is there any good reason why automatically generated clean tasks are not called when just doing “./gradlew clean”? What is the recommended way of actually making them get called?

1 Like

Doh, I just realized that “clean” seems to always be called, not matter what tasks I execute. That is, with

clean {
    println "CLEAN"
}

I see “CLEAN” printed out even if I just say “./gradlew tasks”! That sort of explains why automatic clean tasks are not called as part of “clean”, but why is then “clean” always executed?

Tasks are always configured, but not always executed. The ‘println’ above is part of configuring the task. Code that is part of executing the task needs to go into a task action (‘doLast { … }’).

I see. I though “clean” would be some sort of special task, as in all examples I’ve seen to far it is not prefixed with “task”. What is the meaning of omitting “task” here? Does it mean that the existing default “clean” task gets “extended” by whatever is written here?

It means that an existing task is being (further) configured, rather than a new task created (and configured).

All build outputs should go somewhere under the build output directory (which defaults to ‘build/’), and ‘clean’ deletes that whole directory. Hence it’s typically not necessary to make ‘clean’ depend on task-specific clean tasks. If ‘clean’ needs to delete additional directories, it can be configured to do so:

clean {
    delete "foo"
    delete "bar/baz"
}

But as I said, in most cases it’s better to make sure that all build outputs go under ‘build/’.

1 Like

So if I understand correctly what you are saying, in your example “foo” and “bar/baz” would be deleted during the configuration phase (of the “clean” task). Is that really how it’s supposed to be? So far my understanding was that “real work” should be done in the execution phase. Couldn’t I also add further actions to an existing task with a similar syntax like

clean {
    doLast {
        delete "foo"
        delete "bar/baz"
    }
}

In my case, I’d like to clean copied files (see my “unzipDependencies” task over here). I’m not using a Copy task, but the copy method, as the Copy task does not define its outputs in a way I could rely on it for cleaning. So would this be the right way to include the unzipDependencies’ auto clean task into the default clean:

clean {
    tasks['cleanUnzipDependencies'].execute()
}

This just look very verbose to me, which is why I’m asking.

There are several misconceptions here. ‘clean { delete … }’ configures the task to delete additional directories once it gets executed. It is not the same as calling ‘project.delete(…)’. Also, a task cannot execute another task. (‘task.execute()’ is an internal method that should never be used in a build script.) Instead, it should depend on that task. I recommend to study at least the first several chapters of the Gradle User Guide before continuing.

1 Like

Ok, so coming back to my original question, to sum up:

  • Automatic clean tasks are not called as part of ‘clean’ by design, because Gradle assumes build outputs to only be created under the build output directory, which is deleted by ‘clean’ anyway.

  • If you want to run an automatic clean task as part of ‘clean’, you can do so by writing something like

clean.dependsOn cleanUnzipDependencies

where ‘cleanUnzipDependencies’ is the automatic clean task for the ‘unzipDependencies’ task.

Thanks. It was really confusing me that there’s a difference between ‘clean { delete … }’ and ‘clean { project.delete(…) }’.

If I’m not supposed to call ‘task.execute()’ directly, how am I supposed to run the ‘unzipDependencies’ task before

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
}

is resolved, but after

dependencies {
    zip 'group-of-zip-file:name-of-zip-file:version-of-zip-file@zip'
}

is resolved?

In short, by establishing the correct task dependencies. But that should be a separate topic.

I agree, the separate topic is already here.