Robert Elliot
10/06/2024, 9:38 PMExtensionContainer?
I've got a plugin where I want to decorate an existing plugin with one new setter, so that in a build file I can write:
existingPlugin {
myNewProperty = "some value"
}
More details in thread.Robert Elliot
10/06/2024, 9:42 PMclass MyExtension(
private var currentPropertySetting: String,
) {
var myNewProperty: String
get() = currentPropertySetting
set(prefix) {
// do clever stuff here
currentPropertySetting = prefix
}
}
(existingPluginModel as ExtensionAware)
.extensions
.create("myExtension", MyExtension::class.java)
which allows this, which seems verbose:
existingPlugin {
myExtension {
myNewProperty = "some value"
}
}Robert Elliot
10/06/2024, 9:48 PM(existingPluginModel as ExtensionAware)
.extensions
.add(
object : TypeOf<Function1<String, Unit>>() {},
"setMyNewProperty",
) { newValue: String ->
// do clever stuff here
}
which allows:
existingPlugin {
setMyNewProperty("some value")
}
This is less verbose, but apart from losing the setter feel to the DSL it leads to compiler warnings over the generated code, because TypeOf<kotlin.Function1<String, Unit>>() {} uses reflection, so ends up with kotlin.jvm.functions.Function1 rather than kotlin.Function1 as the type specified in the generated code, which kotlinc then warns about because you are meant to use kotlin.Function1.ephemient
10/06/2024, 9:53 PM(existingPluginModel as ExtensionAware)
.extensions
.add<Property<String>>(
"myNewProperty",
objects.property()
)
work? (https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.kotlin.dsl/add.html there's an inline extension with reified T which allows you to avoid new TypeOf())ephemient
10/06/2024, 9:58 PM@SupportsKotlinAssignmentOverloading but Property already exists so why not)Robert Elliot
10/06/2024, 10:02 PMProperty?Robert Elliot
10/06/2024, 10:04 PMProperty with my own implementation that acts on setRobert Elliot
10/06/2024, 10:14 PMLine 6: myNewProperty = "some value"
^ Val cannot be reassigned
I wonder why it thinks it's a val...ephemient
10/06/2024, 10:14 PMplugin.assignment is supposed to turn = into set thereephemient
10/06/2024, 10:15 PMRobert Elliot
10/06/2024, 10:15 PMephemient
10/06/2024, 10:18 PM@SupportsKotlinAssignmentOverloading
class MyProperty<T>(var value: T, private val onSet: (T) -> Unit) {
fun set(value: T) {
this.value = value
onSet(value)
}Robert Elliot
10/06/2024, 10:42 PMephemient
10/06/2024, 11:04 PM.gradle.kts file or .kt?ephemient
10/06/2024, 11:16 PMimport org.gradle.kotlin.dsl.assign
because it's not in the default imports and the IDE won't suggest itVampire
10/07/2024, 1:26 AMexistingPlugin {
myExtension.myNewProperty = "some value"
}
if that suits you better.Vampire
10/07/2024, 1:28 AMset, but assign)ephemient
10/07/2024, 1:31 AMassignephemient
10/07/2024, 1:32 AMProperty then that won't work eitherVampire
10/07/2024, 1:33 AMVampire
10/07/2024, 1:40 AMis there a hook where a plugin can act after the entire build script has been evaluated, but without a task being called? That might be a better place to read the property value and do my workNone you should use. That is exactly
afterEvaluate { ... } which is highly discouraged, as the main earnings you get from using it are timing problems, ordering problems, and race conditions.
Usually you should have `Property`s and similar types and wire those together, only evaluating at execution time.
And if you need to do something at configuration time with the values, I usually recommend to have a function in the extension and do the code in the body of the function, eventually preventing that it is called multiple times if necessary.
But also for that, I would use a proper extension object with the function and not the function directly as extension, as you most probably leave users of one DSL behind if you do it like that.Vampire
10/07/2024, 1:44 AMfun foo(action: Action<Bar>) and Bar has the `Property`s.
Then you can set them like
myExtension {
foo {
bar1 = "x"
bar2 = "y"
}
}
and do the configuration in foo after evaluating the action.Vampire
10/07/2024, 1:49 AMProperty trick btw. works, I just tried it.
But it has the same problem as the Function1 trick.
It only works properly with Kotlin DSL.
With Groovy DSL you get "There's an extension registered with name 'myNewProperty'. You should not reassign it via a property setter."Vampire
10/07/2024, 1:51 AM= in Kotlin DSL, but need to use .set() in Groovy DSL.Robert Elliot
10/07/2024, 9:46 AMGradleRunner.create().withPluginClasspath().build() in a test it doesn't. Perhaps I'm doing something wrong...
Code here: https://github.com/Mahoney-gradle-plugins/lidalia-idea-ext/blob/rework/src/main/kotlin/LidaliaIdeaExtPlugin.kt
Test code here: https://github.com/Mahoney-gradle-plugins/lidalia-idea-ext/blob/rework/src/functionalTest/kotlin/LidaliaIdeaExtPluginFunctionalTest.kt
Test failure visible here: https://github.com/Mahoney-gradle-plugins/lidalia-idea-ext/actions/runs/11213200240/job/31165826776Vampire
10/07/2024, 11:04 AMset that is used, but assign.
Just for the Gradle Property types assign forwards to set.
For ConfigurableFileCollection it for example forwards to setFrom.Vampire
10/07/2024, 11:09 AM.assign manually instead of using =.