TLDR; Best way to express “implicit” project dependency?
I am working on a plugin which implies dependency (Project#evaluationDependsOn
sense) between 2 projects. I am having difficulty getting the ordering to work properly.
Long story short, this dependency is defined by the application of a plugin and then the configuration of that plugin’s DSL extension. Not to get too crazy, a simple build example would look like this:
plugins {
id 'jakarta-transformer'
}
jakartaTransformation {
shadow( project( ':hibernate-core' ) ) {
...
}
}
The project applying the plugin needs the evaluation of :hibernate-core
to happen first.
I started playing around with afterEvaluate
to achieve this, so I could e.g. delay “fully” applying the plugin until after :hibernate-core
is evaluated. The trouble I ran into is that afterEvaluate
calls are completely ignored when the project is already evaluated (which seems utterly wrong to me, but that’s a different discussion[1]). And, as far as I could tell, there is no way to actually ask the Project if it is already evaluated.
To better understand how evaluating projects and applying plugins works timing-wise I wrote a simple project with 3 java sub-projects and a buildSrc
plugin.
The root project looks like:
plugins {
id 'the-plugin'
}
allprojects {
...
afterEvaluate {
getLogger().lifecycle( "Finished evaluation: `{}`", path )
}
}
subprojects {
beforeEvaluate {
getLogger().lifecycle( "Before evaluation: `{}` (from root)", path )
}
}
All of the sub-projects are basically the same:
plugins {
id 'java-library'
id 'the-plugin'
}
rootProject.afterEvaluate {
getLogger().lifecycle( "Finished root-project evaluation (callback from `{}`)", path )
}
Which produces the output:
> Configure project :
Applying plugin to `:`
Finished evaluation: `:`
> Configure project :hibernate-core
Before evaluation: `:hibernate-core` (from root)
Applying plugin to `:hibernate-core`
Finished evaluation: `:hibernate-core`
> Configure project :hibernate-envers
Before evaluation: `:hibernate-envers` (from root)
Applying plugin to `:hibernate-envers`
Finished evaluation: `:hibernate-envers`
> Configure project :hibernate-testing
Before evaluation: `:hibernate-testing` (from root)
Applying plugin to `:hibernate-testing`
Finished evaluation: `:hibernate-testing`
You can see the problem with afterEvaluate
in the fact that the callbacks in the sub-projects to the root-project’s afterEvaluate
never happen.
There are a few “work arounds” I can think of, but both seems hacky…
The first would be to use normal project-dependency to express the dependency:
plugins {
id 'jakarta-transformer'
}
dependencies {
implementation project( ':hibernate-core' )
}
jakartaTransformation {
shadow( project( ':hibernate-core' ) ) {
...
}
}
This one is hacky imo, due the nature of the plugin functionality, because it allows the possibility that the user might add multiple dependencies to this Configuration while shadowing is a one-to-one thing. Also internally these shadows define dependency (Configuration sense) substitutions - here we’d always want to substitute references to :hibernate-core
to the project applying the plugin, which here would be a circularity.
The other approach I considered was to instead force / expect the plugin to be applied to a root project and define the shadowing config for all “shadow” projects:
plugins {
id 'jakarta-transformer'
}
jakartaTransformation {
shadow( ':hibernate-core-shadowed' ) {
from project( ':hibernate-core' )
...
}
shadow( ':yet-another-shadowed' ) {
from 'some.external:project:1.2.3'
...
}
}
Not a fan of this one just because it does not “feel as nice” as each shadow project defining what it shadows and configuring that shadowing.
But really, making it work is obviously the main priority so if one of these hack-options is the only option that’s what I’ll do.
A lot of information to read through here, so big thanks in advance…
[1] Is there an explicit reason afterEvaluate
cannot simply immediately execute the passed block when the project is already evaluated? Or at least a way to ask if the Project has been evaluated?