Is it possible to access the software model from o...
# declarative-gradle
j
Is it possible to access the software model from one plugin to another? It is in normal Kotlin files, not in
.dcl
files. The use case is configuring the X plugin from the Y plugin without having to create a middleware project extension or something similar which complicates the setup a lot.
s
As of now, only one plugin can be applied as a project's software type. When it is, the software type model instance also gets registered as the project's extension with the name matching the software type name. Other plugins should be able to access the extension from the project's extensions container. We are working on a new way to integrate software features, so plugins could contribute extensions for each other's software types. That is going to be the right way to integrate plugins and apply more than one of them to a single project in the Declarative ecosystem.
@Javi, your use case might be a valuable input to our development of this composability mechanism. Our team would appreciate it if you could provide some more details about what you are trying to achieve.
j
I am refactoring Hubdle to support DCL. The current approach I am taking to get the advantage of getting everything modularized is to create a module with a plugin per functionality. For example:
Copy code
hubdle {
    configuration {
        documentation {
            readmeBadges {
                kotlinBadgeEnabled = true
                mavenCentralBadgeEnabled = true
                ...
            }
        }
    }
    kotlin {
        jvm { ... }
    }
}
I have a
hubdle
parent plugin, another for
documentation
, etc. Even though
readmeBadges
is a plugin itself, it can be applied by the parent ones, even if at the end everything will be configured using the hubdle plugin. I have implemented
readmeBadges
and
documentation
(and the wiring with
readmeBadges
). The software type for
documentation
has a
@Configuring
for a
readmeBadges
method and the
readmeBadges
software type from the child project, in order to avoid "duplicating default setups" is being overridden so:
Copy code
val readmeBadgesPlugin = project.plugins.apply(ReadmeBadgesPlugin::class)
documentation.readmeBadges = readmeBadgesPlugin.readmeBadge
The
documentation
plugin has a
Copy code
abstract var readmeBadges: ReadmeBadges // check it is using `var`

@Configuring fun readmeBadges(action: Action<ReadmeBadges>) { ... }
Which allows reassigning it from the
ReadmeBadgesPlugin
. I would like to directly get the child
ReadmeBadges
from the applied plugin without needing this
var
plus manual assignation. Something like:
Copy code
@get:RestrictiveFromPlugin(ReadmeBadgesPlugin::class) abstract val readmeBadges: ReadmeBadges
Another pain point is making decisions based on a configuration but in the configuration phase. For example, based on a
Boolean
flag, applying or not a plugin or registering or not some tasks. This
Boolean
flag can be changed by the consumer in the
.dcl
file, but I haven't a simple way to get that info without using
afterEvaluate { }
For this last, I have created an issue here
@Sergey Igushkin if possible, I would push supporting version catalogs ASAP, I have seen it will not be available on Feb 2025 so I have in mind doing some codegen to expose every dependency inside my DSLs
dependencies
block But it can be a blocker for early adopters.
s
@Javi, thanks for the details! We'll look into this use case. And yeah, we'll see what we can do about the version catalogs. They are on our table, but without a clear priority so far.
j
@Sergey Igushkin is there any open issue on the Gradle repository about this? I opened it on declarative but probably this feature request already exists there and I want to follow it.
s
Sorry, I'm not aware of any other issues about exactly this thing. I think the shape of the model should not depend on the properties in general, but it should be fine to expose functions that apply some non-cancellable changes to the model (including creating tasks and configurations). DCL allows such functions annotated as
@Configuring
(note that they should not modify any other parts of the declarative model, but they can register anything else in the lower-level build model). By reacting to function application instead of property changes, a plugin can avoid waiting for all changes to get applied.
j
I tried that approach but as
@Configuring
does not allow passing flags but just
Action<T>
, the only way to enable/disable things is by commenting the lambda in the DCL. An additional issue is, that you are forced to run a function to enable anything. Still, if the default behavior is enabled there is no workaround to disable it with the function approach.