Not directly related to your response, but I am still trying to develop an intuition around Gradle’s laziness and what things should be lazy versus what things should not be lazy.
The Code
Suppose I have this plugin
class DynamicSourceSetsPlugin : Plugin<Project> {
override fun apply(project: Project) {
val objects = project.objects
val builds = objects.domainObjectContainer(Build::class.java) { name ->
objects.newInstance(
Build::class.java,
name
)
}
project.extensions.add("builds", builds)
createSourceSets(project)
}
private fun createSourceSets(project: Project) {
@Suppress("UNCHECKED_CAST") val builds =
project.extensions.getByName("builds") as NamedDomainObjectContainer<Build>
builds.all {
val sourceSetContainer = project.extensions.getByType(SourceSetContainer::class.java)
val sparkVersionFmt = this.sparkVersion.get().replace(".", "")
val scalaBinaryVersionFmt = this.scalaBinaryVersion.get().replace(".", "")
val sourceSetName = "mainSpark${sparkVersionFmt}Scala${scalaBinaryVersionFmt}"
val mainSourceSet = sourceSetContainer.create(sourceSetName) {
val main = sourceSetContainer.getByName("main")
java.setSrcDirs(main.java.srcDirs)
resources.setSrcDirs(main.resources.srcDirs)
}
val testSourceSetName = "testSpark${sparkVersionFmt}Scala${scalaBinaryVersionFmt}"
sourceSetContainer.create(testSourceSetName) {
val test = sourceSetContainer.getByName("test")
java.setSrcDirs(test.java.srcDirs)
resources.setSrcDirs(test.resources.srcDirs)
compileClasspath.plus(mainSourceSet.output)
runtimeClasspath.plus(mainSourceSet.output)
}
}
}
}
abstract class Build @javax.inject.Inject constructor(val name: String) {
abstract val sparkVersion: Property<String>
abstract val scalaBinaryVersion: Property<String>
}
The Problem
When I apply the plugin, and configure it like so:
builds {
create("Spark 3.5.0 with Scala 2.13") {
sparkVersion.set("3.5.0")
scalaBinaryVersion.set("2.13")
}
create("Spark 3.5.0 with Scala 2.12") {
sparkVersion.set("3.5.0")
scalaBinaryVersion.set("2.12")
}
}
I encounter the follow error:
Cannot query the value of property ‘sparkVersion’ because it has no value available.
I understand what the message is telling me, that sparkVersion and scalaBinaryVersion are not known during the evaluation and configuration phases of the project’s lifecycle and I am trying to access them in my plugin by using Property#get() before the value has been set. The thing is that I need those values in order to dynamically create my source sets.
Beyond using Project#afterEvaluate, I am not sure how to overcome this issue.
Side Note: If I swap builds.all for builds.configureEach, no observable changes happen.
Do you have any suggestions? Any solutions?