Extending a model using Rule based model configuration

Hi

My question is on how it is done or if it may be in the future to extend a Rule based model configuration applied from a custom plugin. As far as I can read the current documentation it is possible to add a new top element with @Model, but I haven’t figured out how to add an element to an existing model provided by third part plugin

The use case is that the android plugin has an extensive project based model and we (Sony Mobile) have extended their model, for example at the flavor level added properties to hold relevant data for uploading apk/aar to relevant locations. Different teams may work with different flavors so having all configuration within the flavor is preferred.

Let me show an example

Let say there exists a plugin “CoolPlugin” which has the following DSL

project {
  coolPlugin {
    coolStuff {
      coolName = 'Its cool'
    } 
  }
}

Then in the project based model configuration I can create my own plugin ‘HotPlugin’ which applies the CoolPlugin and then extend the DSL with

Assuming the extension adds the hotStuff block {}
project.coolPlugin.CoolStuff.extensions.create(‘hotStuff’, HotStuff.class, this).

Then in build.gradle I would have.

apply plugin: 'CoolPlugin'
apply plugin: 'HotPlugin'

project {
  coolPlugin {
    coolStuff {
      coolName = "It's cool"
      hotStuff {                 //
        hotName = "It's hot"     // Added by the extension
      }                          //
    } 
  }
}

Now looking into Rule based model configuration (0.6.0-beta2) I haven’t figured out how to do this yet or if it is even possible. Assuming the CoolPlugin is like this

// Assuming this is all a part of the CoolPlugin 

@Managed interface CoolStuff {
    String getCoolName()
    void setCoolName(String coolName)
}

@Managed interface CoolPlugin {
    CoolStuff getCoolStuff()
}

class CoolRules extends RuleSource {
    @Model void coolPlugin(CoolPlugin coolPlugin) {}
}

apply plugin: CoolRules

model {
    coolPlugin {
        coolStuff {
            coolName = "Cool"
        }
    }
    tasks {
        cool(Task) {
            def p = $.coolPlugin.coolStuff
            doLast {
                println "Hello $p.coolName!"
            }
        }
    }
}

Running the task cool will successfully print
Hello Cool!

Now to my problem. I want to extend the DSL provided by CoolPlugin with my HotStuff. I can create the manage object HotStuff, but I don’t know how to get it into the model using the HotRules class

//Assume this is the HotPlugin

apply plugin: 'CoolPlugin'

@Managed
interface HotStuff {
    String getHotName()
    void setHotName(String coolName)
}

class HotRules extends RuleSource {
  // It is possible to extend the model with HotStuff into the model provided by the Coolplugin.
  // If it is, how is it done.
  // If not, is this something that will come eventually 
  //- corresponding functionality exists in the project based model.
}

model {
    coolPlugin {
        coolStuff {
            coolName = "It's cool"
            hotStuff {
              hotName = "and hot"
            }
        }
    }
    tasks {
        cool(Task) {
            def p = $.coolPlugin.coolStuff
            doLast {
                println "Hello $p.coolName $p.hotStuff.hotName!"
            }
        }
    }
}

Any ideas and thoughts about this!

BR / JO Sivtoft, Application Build Team, Sony Mobile, Lund

Is this connected with the experimental Android plugin for Gradle? If so, it would be useful if you could provide a more concrete example based on that.

From my own experiences with the new software model, the plugin you want to extend has to be designed such that it’s possible. Perhaps through custom binary types or source sets. If it’s not designed that way, then I don’t think there’s much you can do. It really depends on precisely what you want to achieve.

Within the context of CoolStuff and HotStuff, you can’t arbitrarily add properties to CoolStuff unless the model type itself provides a mechanism to do so. You might be able to provide your own custom model type:

@Managed
interface HotCoolStuff extends CoolStuff {
    String getHotName()
    void setHotName(String coolName)
}

You then need to work out how to get the relevant rule to create instances of HotCoolStuff rather than simply CoolStuff.

Hi,

Yes it concerns the experimental Android plugin for Gradle.

Today we have extended the Android plugin for Gradle with something like this.

android {
    defaultConfig {
         ...
         custom {
             data1 =
             data2 =
        } 
   }
   productFlavors {
       flavorA {
             ...
             custom {
                 data1 =
                 data2 =
             }
        } 
      flavorB { ... }
   }
}

We have done this so that the users (i.e. the application development teams) can have packaging and composition data related to a flavor in the custom block making it easy to read and understand what data is related to a specific flavor.

This is done with the extension mechanism provided with Gradle project based model.

So what I’m looking for is way to achieve the same in the Gradle rule based model.

I have been digging into the ModelRegistry class and others to figure out if there is a way around this.

At the moment, I can only think of adding a property to ProductFlavor that stores arbitrary properties (requiring a change to the plugin) or having a feature in Gradle that allows you to register your own implementation of ProductFlavor with the extra properties you want.

Anyway, I’m afraid I can’t really help, sorry. Hopefully a core developer will pass by and offer some advice.