If you use gradle and you took the path to write your own gradle plugins (try it, it’s fun!) to make your build process more … “enjoyable”, then this might come in handy one day.
I have worked on a few gradle plugins, some of them inside the Netflix Nebula suite, some of them outside Netflix OSS. And in some of those the discussion came up about why occasionally I use afterEvaluate to perform various tasks.
The docco doesn’t do this too much justice to be fair (see https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#afterEvaluate(org.gradle.api.Action)) as it reads:
void afterEvaluate(Action<? super Project> action)
Adds an action to execute immediately after this project is evaluated.
Parameters:
action
– the action to execute.
Go figure :O What does it mean “after this project is evaluated”? To explain this, I’m going to assume you are building a plugin which uses let’s say the project version (project.version
in gradle “speak”). Assume the following build.gradle
file to start with:
apply plugin: 'java' apply plugin: 'application' //... some other configuration version= '1.2.3' // ... other stuff |
At this point let’s say you are developing a plugin 'my.simple.plugin'
— so you go ahead and apply your plugin right after applying the application
plugin (I’m assuming here the buildscript
classpath and dependencies etc are all set):
apply plugin: 'java' apply plugin: 'application' apply pugin: 'my.simple.plugin' //... some other configuration version= '1.2.3' // ... other stuff |
At this point, surprise! Your plugin will “see” the plugin.version
not set! In case you haven’t figured it out, it’s because at the time your plugin (which doesn’t use — yet! — afterEvaluate
) kicks in, the version has not been set!
OK, you think, I’m going to move my plugin right after the version is set:
apply plugin: 'java' apply plugin: 'application' //... some other configuration version= '1.2.3' apply pugin: 'my.simple.plugin' // ... other stuff |
This works, and now your project.version
will reflect the correct value (“1.2.3”). But then it means all of your plugin users now have to be instructed to always apply the plugin after setting the version — which will quite likely make your plugin less popular (we know that any friction for the developers decreases usage).
So this is where afterEvaluate
comes in handy : you can simply apply your plugin in that closure right at the top of the file:
apply plugin: 'java' apply plugin: 'application' afterEvaluate { apply pugin: 'my.simple.plugin' } //... some other configuration version= '1.2.3' // ... other stuff |
And now your plugin will show again the correct version, even though it is applied before the version is set. The thing is your plugin is actually not applied right away — since it’s “behind” an afterEvaluate
now, gradle will parse the whole file, will evaluate first all the properties of the project and then will finally apply your plugin (at which point the version will have already been evaluated and set).
Of course, you need to take this one step further, as you don’t want to recommend now to your plugin users to wrap up your plugin all the time in an afterEvaluate
block, so instead in your plugin apply()
method you should probably do this:
void apply(Project project) { project.afterEvaluate { // call your main plugin method here } } |
At this point regardless where in the build.gradle
your plugin is applied you will always have access to the correctly evaluated project.plugin.
Hopefully this explanation helps more than the GroovyDoc of the method.