gradle / kotlin-dsl-samples

Samples builds using the Gradle Kotlin DSL
https://gradle.org/kotlin/
Other
3.71k stars 434 forks source link

tasks.create is always eagerly executed #1336

Closed masoudy closed 5 years ago

masoudy commented 5 years ago
tasks.register("HelloThereTask"){
    println("Please dont print this!!!!!")
}

consider the simplest code possible that is written above

why is always it is being configured and println statement is executed i am really confused!!!!

thc202 commented 5 years ago

That's being executed in the configuration phase, that's why it's printed always. If you do that in a doLast block it will be done in the execution phase, more details in: https://docs.gradle.org/current/userguide/build_lifecycle.html

masoudy commented 5 years ago

i know it myself the difference between execution and configuration phase

but as i know , after gradle 5 , if we use register and not create function , then its configuration phase will be executed when the task is being created for example by calling functions like tasks.getByName or ......

the doLast block was always executed in execution phase from the day 1.so what is the benefit of registering task

StefMa commented 5 years ago

The difference is that the configuration for the task will not be execute when gradle detects that it don't have to configure the task.

Run the task "help" with your example above. The output should be the println. When you change the task creation to "register", then nothing should be printed... That is the difference...

masoudy commented 5 years ago

i edited my code

it is register function now being called and as i meant it to , but i mistakenly wrote create

as you said the help task is acting as expected

but why the other tasks dont

if i run any task other than help , the tasks configuraion block will be executed immidiatly why is that?!

what is the benefit of register when it is only useful with help task, that is rediculous!

thc202 commented 5 years ago

Thanks for updating the example, more clear what the question is about.

This blog post provides a good example of the benefits: https://blog.gradle.org/preview-avoiding-task-configuration-time

if you have many tasks that are not needed avoiding configuring them pays off. Of course if you have just a couple of them and are always needed then there's no gain/benefit.

masoudy commented 5 years ago

i wanted to use it as a solution for my jar task which its files are being generated in the execution of a task which is being dependent on

tasks.register("createDependenciesBundleJar" ,  Jar::class ) {
    dependsOn("generateDependencyFilesNeeded")
    from("a file which is not generated yet")
}

i`ve searched the internet for almost a week seeking the solution with no luck

i thought gradle new configuration avoidance api is primarly an answer addressing these kind of problems

if it is not , then with new poweful machines , this feature does not worth celebration

and what should i do know

masoudy commented 5 years ago

i knew that configuration phase is a built in mechanism of Groovy language and i hoped with the Kotlin dsl we will get rid of this trouble maker . and with the introduction of configuration avoidance api , i thought that the dark days are gone at last

but know all i see is some useless change of api invocation and nothing is changed in the internal model of gradle , it is still suffering what is it being made of , no matter what the interface be

so i take this silence as "No" answer to my simple question : Is There a way to write a task which its being configured after its dependencies

masoudy commented 5 years ago

i even cannot call "from()" inside "doLast" block , because it says that it isnt possible to add after configuration

now i have to write a custom Jar making function and call it inside doLast block of a simple task , because gradle is not able to do the simple obvious Jar stuff , which is coping after being generated

masoudy commented 5 years ago

i have put println statements at the beginning and end of every build file and every block and event inside every task

my project has 10 sub modules and it has got variety of plugins inside each module

here is what i have got:

first buildSrc module build.gradle file is executed and then its build task is executed

after that the rootProject`s buildScript is executed , no matter where it is located

after that the rootProject`s build.gradle file is executed from top to bottom , ignoring buildScript block , because it executed that before this step(that is intresting)

then subProject block is executed for every sub module and after that allProject block (maybe if i change the order , it execute the other way)

after that it execute all sub module build gradle files from beginnig to end

so far so good to this position , because up to this position in configuration phase , all the registered tasks are deffered for configuration

but suddenly at the end , all registered tasks start cofiguring eagerly , and i dont find the source of problem

if i run help task , none of registered tasks run , but if click on ImportChanges notification , it starts configuring evertything and i dont understand what is it that it calls at the end that causes all registered tasks being configured immidiately!

masoudy commented 5 years ago

there is more:

within each module all tasks with "create" method are eagerly configured , but after configuring each module , all of its registered tasks are configured

i dont understand , what is the point of registering task instead of creating , if it will run its configuration anyway at the end of its host gradle build file

could someone please explain to me

masoudy commented 5 years ago

looks like everybody knows nothing

i fiddled with tasks and find out that registered tasks are somehow dependencies of a task within discoverMainScriptsExtensions task and all registered tasks are being created and called , when this task is called .but in the second run , because the task result is cached , it wont call its dependencies , so registered tasks wont run

and as @StefMa said , its only useful for performance not anything else

masoudy commented 5 years ago

if someone just needed to configure a task in execution time , simple just create another task and assign it as dependency to the original task

then in the new task add a doLast block and in that , call "configure" function of project and configure your task

i was using configuration avoidance feature(CA) inappropriately CA feature is meant to increase configuration speed as my friends told me before

thanks everybody

JLLeitschuh commented 5 years ago

@masoudy You can also do this:

tasks.register("createDependenciesBundleJar" ,  Jar::class ) {
    dependsOn("generateDependencyFilesNeeded")
    from({ "a file which is not generated yet" })
}

The lambda you pass to the from will be lazily evaluated.

masoudy commented 5 years ago

that aint a solution , that does not work at all and people keep suggesting that in every blog!!

StefMa commented 5 years ago

Of course it works. See: ezgif com-video-to-gif

Don't get confused that I use the Copy task instead of the Jar task. At the end both of them inherited from the AbstractCopyTask which provides the from() method...