How to access Model from a Plugin


(Aleksandar Milenovic) #1

Hi,

I am new to Gradle and have just written a Plugin. I also have read about the Model concept, which I really like. I wanted to access Model information from a Plugin.

I tried to get it from Project since my plugin takes Project as input (Plugin). The closest model related property is Model Schema Store. However this looks to be from ‘internal’ package.

Is it possible to access Model from a Plugin? How I can do so? Apologies if I am missing the obvious.

Following topic (https://discuss.gradle.org/t/how-would-you-create-the-model-component-closure-in-a-custom-plugin-since-the-2-3-native-component-changes/4247) looks related.

Thanks,
Aleksandar


(Andreas Axelsson) #2

I suggest you start looking at the documentation and samples here: https://docs.gradle.org/current/userguide/software_model.html, and the sample code in those sections

As far as I’ve seen, you don’t really need to access the model from a plugin directly, you just provide rules that take model elements as inputs, and it’s all automagic from there.


(pledbrook) #3

Following up on what Andreas said, the new software model is a parallel configuration mechanism to the old plugin approach. They’re not mutually exclusive, but there are only limited ways to link between them.

To use the new model, create one or more classes that implement RuleSource. I tried to provide an introduction to the new structure in a presentation. If you have a spare hour, it may help.

If you want to have your RuleSource processed by Gradle automatically when a user applies your plugin, then you can simply make that RuleSource a static inner class of the plugin, as demonstrated here.


(Aleksandar Milenovic) #4

Thanks for that.

Maybe I wasn’t clear enough with what I mean by ‘accessing the model’.

I am working on a PlantUml plugin, which can generate diagrams like Component or Use Case. I would like to be able to read the model (builtin entities like Components but also my own entities like UseCase) and then to generate a diagram.

In essence, I need same information as you can get with ‘gradle model’ command, but programmatically with my own Plugin.

I couldn’t understand how I can do that via RuleSets…

How I can achieve this?

Thanks in advance,
Aleksandar


(Adrian Kelly) #5

@amilenovic there is no public API available to inspect the entire model graph. The model task uses the internal class org.gradle.model.internal.registry.ModelRegistry to cycle through the nodes of the model. Classes like ModelRegistry are under active development and are intentionally not made public. It is not recommended for external plugins or builds to rely on and use such classes so use at your own peril!


(pledbrook) #6

Rules take the form:

void ruleName(<subject>, <input>, ...)

The return type and significance of the rule name both depend on the type of rule, but for now I want to focus on <input>, .... These inputs represent other elements of the model, provided by your own plugin, core Gradle, or some other plugin. Gradle automatically injects the appropriate object of the required type into your rule method. You can then extract the information you need and do something with it.

For example, if you want to create some tasks based on the configured use case, you can do this:

@Mutate
void createUseCaseTasks(ModelMap<Task> tasks, UseCase useCase) {
    tasks.create("useCaseTask") {
        // Configure the task using information from `useCase`
        ...
    }
}

What if you have more than one UseCase in your model? In that case, you either need to use a collection of them (via ModelMap for example) or specify a specific one based on its model path (via the @Path annotation).

If not much of this is making sense, then you’ll need to learn more about the new software model. I used the videos of the relevant workshop from the Gradle Summit. That’s a link to part 1. Just change the 1 for a 2 in the URL to get the second part, although I feel all the important stuff is in the first one.


(Aleksandar Milenovic) #7

Got it, thanks @Adrian_Kelly. I hope you will eventually make such API public - I see it as an excellent base for ecosystem of tooling on top of Gradle.

Regards,
Aleksandar


(Aleksandar Milenovic) #8

Thanks @pledbrook, I will definitively try it out.


(remo) #9

@Mutate
void createUseCaseTasks(ModelMap tasks, UseCase useCase)

creates a tasks by first evaluating “UseCase”. is there a way to achieve this the other way around? Like

@TaskAction
public void doSomething(UseCase useCase)

Meaning that I would like to evaluate the model if a given task is executed (because the task needs this part of the model, but not other parts of the model that are potentially expensive to evaluate)? The given example results in a gradle error.