I had a convention plugin to extend in feature the...
# plugin-development
d
I had a convention plugin to extend in feature the Android plugin
Copy code
interface EnvironmentPluginExtension : Named {
    val applicationId: Property<String?>
    val applicationIdSuffix: Property<String?>
    val versionNameSuffix: Property<String?>
    val disableDebugBuild: Property<Boolean>
    val disableReleaseBuild: Property<Boolean>
}
Than I in the plugin I had
Copy code
pluginManager.apply("com.android.application")
val extension = extensions.getByType<ApplicationExtension>()
val envContainer = objects.domainObjectContainer(EnvironmentPluginExtension::class.java)
(extension as ExtensionAware).extensions.add("environments", envContainer)
envContainer.whenObjectAdded {
  val customSuffix = applicationIdSuffix.orNull // always null
  // ...
}
and used it to configure environments in the android application from the build.gradle.kts file I could do stuff like this
Copy code
android {
  
    environments {
        create("dev")
        create("stage") {
          applicationIdSuffix = ".staging"
        }
    }
}
I remember it used to work - but I used defaults values since I set this up. now that I needed it - several gradle versions laters - I noticed it doesn’t work anymore apparently
whenObjectAdded
is now running BEFORE the domain object is configured (which is absurd imho). I cannot use
afterEvaluate
can anyone give me some way of achieving what I need?
v
I don't think this ever worked. Things like
whenObjectAdded { ... }
or
configureEach { ... }
and so on always run in registration order "unfortunately". So if you for example have
Copy code
tasks.withType<Foo>().configureEach { /* do A */ }
val foo by tasks.registering(Foo::class) { /* do B */ }
then also
A
runs before
B
, as both are configuration actions and
A
was registered before
B
. Basically any
get()
you do on a
Property
(including
.orNull
which really is
.getOrNull()
) at configuration time introduces race conditions, as you never know whether the value is maybe changed later, unless you lock it first using
finalizeValue
or
finalizeValueOnRead
. Even using
afterEvaluate
does not eliminate race conditions, but just makes things worse. So if in any way possible, try to not read the
applicationSuffix
at configuration time, but only at execution time. If you really need the value at configuration time because you have to derive some domain object name from it or similar, then I usually recommend to not use a
Property
but a function in the extension instead, getting the
applicationIdSuffix
as argument. Hard to say how to do it properly in this specific case from the top of my head. ``````
Maybe make
environments
not a domain object container directly, but some extension with a function to which you give the
applicationIdSuffix
as argument and then do the
create
call in that function or something like that.
e
in this case I assume you're trying to configure the Android plugin, which doesn't have a provider-based configuration. so you can't either
😞 1
d
I'm pretty sure I saw this working when I developed it. I had tested passing functions to it. How do I read it at execution time? I'm just trying to configure the android Gradle plugin with my plugin. And for the function can I use getter/setters? Do you have an example? I don't particularly like the idea of using functions cause I'll need a "final" function to call but if I have to I will
v
How do I read it at execution time? I'm just trying to configure the android Gradle plugin with my plugin
If the latter, then not the former 🙂
And for the function can I use getter/setters?
I don't know, never tried. That's for me wrong semantics if you set a value, you set a value. If that directly causes other configurations to be done and maybe even only be callable once, then a property setter does not feel right to me.
Do you have an example?
Nothing public at hand.
d
The thing is, all I would need is something exactly like named domains containers but with a callback right after the action to create + configure them is done
I kinda don’t want to change the API on the user side
Copy code
android {
  environments {
    create("dev")
    create("stage") {
      // specific stage conf here
    }
  }
}
this is just perfect it would be great if only I could get a callback right after the configuration run
v
well, make
environments
an extension with a function called
create
that gets a string and an optional
Action
as arguments. 🙂