Reputation: 1305
I'm writing a custom Gradle plugin which requires a certain dependency to be added to the subproject. This dependency requires version information from the user so I decided to create an Extension
. However, since my properties are referenced in my plugin's apply
method, I can't actually mutate them until after they're referenced. My plugin looks some thing like this:
class MyPluginExtension {
abstract String scalaLibraryVersion
abstract String macroParadiseVersion
}
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("myConfig", PluginExtension)
project.configure(project) {
apply plugin: 'scala'
}
String pluginConfiguration = 'myPluginConfiguration'
project.configurations.create(pluginConfiguration)
String scalaLib = project.myConfig.scalaLibraryVersion
String paradise = project.myConfig.macroParadiseVersion
String paradiseDependency = "org.scalamacros:paradise_${scalaLib}:${paradise}"
project.dependencies.add(pluginConfiguration, paradiseDependency)
project.tasks.withType(ScalaCompile) {
scalaCompileOptions.additionalParameters += [
"-Xplugin:" + project.configurations.getByName(pluginConfiguration).asPath,
"-Xplugin-require:macroparadise"
]
}
}
}
And it will be applied like this:
project("incorrect-subproject-1") {
apply plugin: "carter.my-plugin"
myConfig.scalaLibraryVersion = "2.11.12" // This is too late. The library version is already set to null
}
project("incorrect-subproject-2") {
myConfig.scalaLibraryVersion = "2.11.12" // This is too early. myConfig references nothing
apply plugin: "carter.my-plugin"
}
Is there a better way to do this? This plugin is to be used by other developers so I'm really keen to keep the API as nice as possible. Ideally I'd want something like:
project("incorrect-module-1") {
apply plugin: "carter.my-plugin" {
scalaLibraryVersion = "2.11.12"
macroParadiseVersion = "2.1.1"
}
// rest of this subproject's configuration
}
I have tried to add the dependency during one of the lifecycle callbacks as described in this Gradle support thread. However, I have found that the beforeResolve
callback happens too early and my extension config isn't used and the afterEvaluate
callback happens too late and I get:
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':incorrect-subproject-1'.
> Cannot change dependencies of configuration ':incorrect-subproject-1:myPluginConfiguration' after it has been resolved.
Surely if beforeResolve
isn't late enough then this kind of thing is impossible? Is there a way to delay dependency resolution until after the project is "evaluated"?
By the way I am using Gradle version 5.1
Upvotes: 1
Views: 435
Reputation: 36
You should be able to achieve this by referencing these settings in project.beforeEvaluate. To give you an example:
void apply(Project project) {
super.apply(project)
project.extensions.create("myConfig", Configuration)
project.beforeEvaluate {
String scalaLib = project.myConfig.scalaLibraryVersion
String paradise = project.myConfig.macroParadiseVersion
String paradiseDependency = "org.scalamacros:paradise_${scalaLib}:${paradise}"
project.dependencies.add(pluginConfiguration, paradiseDependency)
project.tasks.withType(ScalaCompile) {
scalaCompileOptions.additionalParameters += [
"-Xplugin:" + project.configurations.getByName(pluginConfiguration).asPath,
"-Xplugin-require:macroparadise"
]
}
}
}
Upvotes: 2