Slackbot
04/03/2023, 4:29 PMMikhail Lopatkin
04/03/2023, 4:42 PMgrossws
04/03/2023, 4:44 PMwhenReady
it would be cached and accessible from execution phase?Vampire
04/03/2023, 4:49 PMgrossws
04/03/2023, 4:55 PMObjectFactory#property(Class)
.
Just checked it with 8.1-rc-2 and it works as expected:
val taskPaths = objects.listProperty<String>()
gradle.taskGraph.whenReady {
taskPaths.addAll(allTasks.map { it.path })
}
tasks.register("taskPaths") {
val taskPaths = taskPaths
doLast {
logger.lifecycle("tasks: ${taskPaths.get().joinToString(", ")}")
}
}
Running something like ./gradlew clean tP --configuration-cache
twice prints expected tasks: :clean, :taskPaths
Vampire
04/03/2023, 4:57 PMwhenRead
would not have run.grossws
04/03/2023, 6:17 PMBuild_gradle#taskPaths
are read when creating build service early (before taskGraph#whenReady
at least) and parameters.paths
is always empty; paths2
(build service exposed property) contains expected values;
⢠with CC build service parameters contain expected values set from whenReady
(i.e. they are somehow serialized later) and paths2
are empty as you thought.
It seems that build service parameters with CC enabled are always serialized and deserialized and it happens later that without CC.
// taskPaths from previous above
val bs = gradle.sharedServices.registerIfAbsent("testBS", TestBS::class) {
parameters { paths.set(taskPaths) }
}
bs.get().paths2.set(taskPaths)
tasks.register("taskPaths") {
val service = objects.property<TestBS>()
service.set(bs)
usesService(bs)
doLast { service.get().list() }
}
abstract class TestBS : BuildService<TestBS.Params> {
interface Params : BuildServiceParameters {
val paths: ListProperty<String>
}
abstract val paths2: ListProperty<String>
fun list() {
println("from bs params: ${parameters.paths.get().joinToString(", ")}")
println("from bs property: ${paths2.get().joinToString(", ")}")
}
}
# ./gradlew cle tP --no-configuration-cache
> Task :taskPaths
from bs params:
from bs property: :clean, :taskPaths
# ./gradlew cle tP --configuration-cache
> Task :taskPaths
from bs params: :clean, :taskPaths
from bs property:
Vampire
04/03/2023, 10:37 PMbs.get().paths2.set(taskPaths)
you create the build service and it seems in that moment the parameter provider gets evaluated to empty list.
If you avoid such eager realization it works consistently.
For example like
val bs = gradle.sharedServices.registerIfAbsent("testBS", TestBS::class) {
parameters { paths.set(taskPaths) }
}
tasks.register("taskPaths") {
val service = objects.property<TestBS>()
service.set(bs)
usesService(bs)
doLast { service.get().list() }
}
abstract class TestBS : BuildService<TestBS.Params> {
interface Params : BuildServiceParameters {
val paths: ListProperty<String>
}
val paths2 = parameters.paths
fun list() {
println("from bs params: ${parameters.paths.get().joinToString(", ")}")
println("from bs property: ${paths2.get().joinToString(", ")}")
}
}
Vampire
04/03/2023, 10:37 PMgrossws
04/04/2023, 1:22 AMabstract class MyExt {
abstract val javaVersion: Property<Int>
}
// in root project plugin
val ext = extensions.create("my", MyExt::class.java).apply { javaVersion.convention(17) }
java { toolchain { languageVersion.convention(ext.javaVersion.map(JavaLanguageVersion::of) } }
// in subprojects
val rootExt = rootProject.the<MyExt>()
val ext = extensions.create("my", MyExt::class.java).apply { javaVersion.convention(rootExt.javaVersion) }
java { toolchain { languageVersion.convention(ext.javaVersion.map(JavaLanguageVersion::of) } }
grossws
04/04/2023, 1:29 AMregisterIfAbsent
calls it was quite inconvenient.
Maybe ServiceRegistry#getRegistrations()#getByName(String,Class)
would be a good substitute for early service realization to propagate properties from build service parameters