Slackbot
04/25/2022, 5:43 AMgrossws
04/25/2022, 6:12 AMephemient
04/25/2022, 6:15 AMfun add(name: String, config: Action<MyType>) {
container.add(objects.newInstance(MyType::class, name).apply { config() })
}
will depend on the container… but it could workgrossws
04/25/2022, 6:15 AMgrossws
04/25/2022, 6:16 AMtony
04/25/2022, 6:44 AMtony
04/25/2022, 7:01 AMLars Ködderitzsch
04/25/2022, 7:06 AMdoThing() is a piece of default configuration logic - my go to solution is using properties all the way through in my custom extensions.
This allows for lazily providing configuration values based on other extension properties.
Something like:
open class MyType (private val theName, objects: ObjectFactory ) : Named {
val isTrue = objects.property<Boolean>().convention(false)
val theThing = objects.property<String>().convention(isTrue.map { if (it) ... })
}
However, properties can be a bit weird to handle for plugin users, as you can't simply use the isTrue = false syntax.
Because of this I tend to have the property as an internal which is then augmented by custom get/set to provide the interface for plugin users.
Like
open class MyType (private val theName, objects: ObjectFactory ) : Named {
var isTrue: Boolean
get() = _isTrue.get()
set(value) = _isTrue.set(value)
internal val _isTrue = objects.property<Boolean>().convention(false)
...
}tony
04/25/2022, 7:38 AMdoThing() registers a task. So if ifTrue is false, no tasks get registered. If true, they're registered. So I can't just keep pushing things down with propertiesLars Ködderitzsch
04/25/2022, 8:23 AMafterEvaluate seems the most logical/understandable place to me...ephemient
04/25/2022, 1:30 PMonlyIf to run it only when a property is true would seem to be the sanest solution to metony
04/25/2022, 4:13 PMephemient
04/25/2022, 5:38 PMtony
04/25/2022, 5:40 PMval c = objects.newInstance(MyType::class.java, name).apply {
config.execute(this)
}
container.add(c)
🤷ephemient
04/25/2022, 5:46 PMcontainer.create("foo") { container["foo"]!! } exists. although perhaps neither is important to youtony
04/25/2022, 5:49 PMcreate _after all_", but who knows when or if that will ever happentony
04/25/2022, 5:50 PMgrossws
04/25/2022, 11:09 PMcreate(String,Action) and register(String,Action) have different behavior for observer using `whenObjectAdded`/`all`.
• create instantiates object, adds to collection (and `all`/`whenObjectAdded` callbacks are called) and only then executes Action passed to callback.
• register does opposite when realized, it instantiates object, executes passed Action (possibly decorated by CollectionCallbackActionDecorator which isn't applied to create AFAIK) and only then it is passed to `all`/`whenObjectAdded`.
So I just override create(String,Action) when extend AbstractNamedDomainObjectContainer with one that has add and configureAction.execute(object) swapped. Original funtion: https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/api/internal/AbstractNamedDomainObjectContainer.java#L79-L80tony
04/25/2022, 11:16 PMgrossws
04/26/2022, 12:13 AMLouis Jacomet
04/26/2022, 2:31 PMcreate on containers. I agree that it would be more natural to have the creation configuration to run first before adding to the container.
However it has been like that for ages.
But learning that register is different is concerning. I’ll raise that internally once more.grossws
04/26/2022, 6:38 PMtony
04/26/2022, 6:40 PMcreate(). Maybe we can get that for Gradle 8 🙏grossws
04/26/2022, 6:44 PMLouis Jacomet
04/26/2022, 6:45 PMcreate and keep the behavior of register sounds like a good plan.ephemient
04/26/2022, 6:48 PMcreate(name, action) = register(name, action).get()?tony
04/26/2022, 6:48 PMregister, would all still cause all elements of the container to be realized? In the current situation, I need those elements available during project configurationgrossws
04/26/2022, 6:52 PMall should realize all objects in the container, yeah. When I wanted to create tasks lazily based on items in the custom container I just registered tasks based on object names and used actual object from the container on demand in configureAction.ephemient
04/26/2022, 6:57 PM// build.gradle.kts
abstract class Foo : Named
val foos = container(Foo::class)
foos.all { println("foos.all($name)") }
foos.register("bar") { println("foos.register($name)") }
prints
# ./gradlew
foos.all(bar)
foos.register(bar)
for me (Gradle 7.4.2)grossws
04/26/2022, 7:00 PMFoo and set it in register's configureAction vs same with create difference should become apparentLouis Jacomet
04/27/2022, 6:42 AMall are executed before the configuration action for both create and register.
@grossws Would you be able to share a reproducer of what you did to see a difference?
With the following in a java project:
configurations.all {
println("Configuration ${this.name} can be resolved ${this.isCanBeResolved()}")
}
configurations.register("testFoo") {
setCanBeResolved(false)
}
it prints
Configuration testFoo can be resolved true
Louis Jacomet
04/27/2022, 6:48 AMall to configureEach results in the same output.
Moving the action to after the register changes the output since it is happening after.grossws
04/27/2022, 8:36 PM