This message was deleted.
# community-support
s
This message was deleted.
j
First of all, this is the repro with the instruction in the
README.md
https://github.com/Reproducers/repro-gradle-dsl
The main idea is creating all extensions eagerly, run the
configure
function when they are being created and later with the "manual" accessor modify them.
Copy code
repro {
  nestedRepro {
    someProperty.set("foo")
  }
}
But it is not working, the
repro
extension is using
the()
to fetch a extension which for some reason it doesn't exist yet,
ReproNestedExtension
Copy code
open class ReproExtension
@Inject
constructor(
    project: Project,
    objects: ObjectFactory,
) : BaseReproExtension(project, objects) {

    val reproNested: ReproNestedExtension
        get() = the()

    fun reproNested(action: Action<ReproNestedExtension> = Action {}) {
        action.execute(reproNested)
    }
}

abstract class BaseReproExtension
@Inject
constructor(
    project: Project,
    objects: ObjectFactory,
) : Project by project, ObjectFactory by objects {

    internal open fun configure() {
        val className = this::class.simpleName ?: "Unknown"
        val configurationName =
            if (name.endsWith("_Decorated")) className.substringBefore("_Decorated") else className
        println("Configuring $configurationName")
    }
}
And the consumer is in this state:
Copy code
plugins {
    id("com.javiersc.repro.plugin") version "0.1.0"
}

// Those both works
the<ReproExtension>()
the<ReproNestedExtension>()

// This works
repro {

}

// This doesn't work, the reported error is
// > Extension of type 'ReproNestedExtension' does not exist.
// > Currently registered extension types: [ExtraPropertiesExtension]
repro {
    reproNested {

    }
}
Maybe the problem is the
Project
delegation in the
BaseReproExtension
? Each extension is a "different" project so they haven't the extension registered? It is weird to me but I haven't used the Kotlin delegation feature a lot
m
Each extension is a "different" project
How are they different projects?
j
F*** my life, that is the problem
I would expect that the project is the same, but they aren't. I think it is due Gradle dependency injection
m
Wuuuuut?
What project is it injecting then ? 🤔
j
I am going to remove
@Inject
to confirm, one second
Nop, it isn't. Not sure why but with delegation it doesn't work
m
Maybe your extension is itself ExtensionAware
so
this.extensions
goes to your extension extensions (!) and not the project extensions
Gotta love extensions 😂
j
Looks like I postponed it many time
😅 2
m
Maybe your extension is itself ExtensionAware
Looks like your extension itself isn't ExtensionAware but Gradle might decorate it into something that is ExtensionAware
ReproExtension_Decorated
j
yeah, I am trying to workaround it by registering
nestedExtension
inside the
reproExtension
but it doesn't work too
Copy code
open class ReproPlugin : Plugin<Project> {

    override fun apply(target: Project) {
        val reproExtension = target.extensions.create<ReproExtension>("_InternalRepro")
        reproExtension.configure()

        val reproNestedExtension =
            reproExtension.extensions.create<ReproNestedExtension>("_InternalReproNested")
        reproNestedExtension.configure()
    }
}
m
I'm not sure what the use case is. Do you "just" want nested blocks? Or something else?
j
Nested blocks that are configured eagerly, the delegation is only to remove boilerplate
I can remove it and it would work, but I have tons of extensions with that configuration right now 🙃
m
configured eagerly
what do you mean by that?
j
The usual approach is using
objects.newInstance()
, but that mean if a user doesn't call the parent wrapper, it will not be created, so that is the reason I need to create them eagerly.
In the
ReproPlugin
class, all extension are eagerly created, then the default configuration is executed. Later the user can modify it via the custom accessor
Copy code
fun Project.repro(action: Action<ReproExtension>) {
    action.execute(the())

    println("After configuration `someProperty`: ${the<ReproNestedExtension>().someProperty.get()}")
}
I have a more complex configuration in the real plugin but that is the base idea
m
What's wrong with
Copy code
val repoExtension = target.extensions.create<ReproExtension>("repo")
        repoExtension.configure()
?
Then you don't need a custom accessor. Gradle will generate one for you
I'm missing something there
j
the
println
part, in the real example it is not a
println
, it does some configurations and lazy configurations, check the total state of all configuration is correct, and so on.
Copy code
hubdle {
  kotlin {
    // disallowed more than one Kotlin at the same time
    android()
    jvm()
    multiplatform()
  }
}
Copy code
fun Project.hubdle(action: Action<HubdleExtension>) {
    action.execute(the())

    checkOnlyOneKotlinIsEnabled()

    for (applicablePlugin in applicablePlugins) applicablePlugin.apply()
    for (configurable in configurables) configurable.configure()
    for (lazyConfigurable in lazyConfigurables) lazyConfigurable.get().configure()
    
    ...
}
m
For this kind of stuff, I usually add one artifical layer of nesting
j
it is only one, the root one, rest are created by Gradle
m
I mean if you do
Copy code
hubdle {
  someArtificialFunction {
    kotlin {
      // disallowed more than one Kotlin at the same time
      android()
      jvm()
      multiplatform()
    }
  }
}
Then
someArtificialFunction
is a function you control where you have the
action
and can do checks before/after
j
kotlin
is indeed my extension. It could be that too, but I think it is easier to remove delegation to get it working. I would like to bypass it tho.
not sure if using a custom
the
based on the below one would work
nah, the below one is the called
looks like injecting
extensions
solves my problem, anyway, thank you for all your help as it was caused by
ExtensionAware
and you give me the hint 😄
m
Nice! Glad I could be of some assistance 😄