Hi everyone, I'm somewhat new to gradle, apart fro...
# community-support
m
Hi everyone, I'm somewhat new to gradle, apart from the pure basics, and I'm currently in the process of modernising a gradle project. Perviously we used a large
build.gradle
file in the root project where we defined all subprojects via
project(":...")
syntax. This has now been migrated to a much smaller
build.gradle.kts
file in the root project and convention plugins to define common build logic and shared dependencies. One of our shared dependecies are the aws java sdk v2, this one includes both
netty
and
apache
http clients, something that is somewhat wasteful as a lot of artifacts are deployed as lambdas in aws. Thus I tried to implement logic in one of our convention plugins to exclude
netty
by default but I seem to run in to some issues. My current attempt looks liks this in the convention plugin:
Copy code
interface ExcludeDependenciesPluginExtension {
    val excludeNetty: Property<Boolean>
}

val excludeExtension = project.extensions.create<ExcludeDependenciesPluginExtension>("excludeDependencies")
excludeExtension.excludeNetty.convention(true)


configurations { 
    implementation.configure {
        if (excludeExtension.excludeNetty.get()) {
            exclude(group = "software.amazon.awssdk", module = "netty-nio-client")
        }
    }
}
And is later used like this in one of the projects.
Copy code
excludeDependencies {
    excludeNetty = false
}
The problem then is that the
excludeNetty
variable in the convention always seems to evalute to true, even though I explicitly set it in one of the subprojects. Perhaps I've misunderstood the order of execution and that this indeed should be the expected behaviour.
v
Yes, this is the expected behavior. Whenever you use
get()
on a provider at configuration time, you introduce race conditions and ordering / timing problems, just like when you use the dreaded
afterEvaluate
that you should avoid at almost all cost. Maybe you should instead have an `includeNetty`function in your extension instead and in its body just add a dependency to netty, or something similar.
There is no definite reliable hook "do this after the buildscript was evaluated", as a buildscript could always also add an action to such a hook which will then run after your action.
e
withDependencies
would be the latest point where you could alter dependencies
v
But could you in there exclude a dependency from a configuration?
e
right, I was going to add that if it's coming in through transitive dependencies, it won't really help
I guess if it's something you want to do codebase-wide, a module metadata rule could do the trick
m
Yeah it would pretty much be codebase wide
m
Thanks for the quick response both of you 🙂
👌 1
A quick follow up, can properties like this be used in other parts of the buildscript or are there timing problems there as well?
e
it depends on how they're used
m
Anywhere one can read up on this or is it mostly knowledge gained from experience?
v
The rule is quite simple. If you call
get()
only at execution phase you are fine, as then all configuration is finalized. If you call
get()
at configuration phase it is problematic, as it could always happen that the configuration is changed after you retrieved the value. The intention how to use `Property`/`Provider` is, that tasks have `Property`s and extensions have `Property`s and you wire properties and providers together and then only when the task actually is executed get the value you need. If you need some value at configuration time and cannot wire it to some
Property
or method that accepts `Provider`s such as
addLater
, then it highly depends on the use-case, but most often the simplest is to have a function in your extension instead, giving the values as arguments and doing the logic that needs those values in the body of the function, eventually preventing that the function is called multiple times if calling with different values cannot adjust the effect of the first call properly.
✅ 1
m
Many thanks!
👌 1