Migrate Extension to Unmanaged Model

Summary

Although Link Extension to Model is a good for a first migration, a plugin author might just decide to completely remove compatibility with older version of a plugin and embrace a new model approach. On the other hand, performing a Migrate Extension to Managed Model might be a step too far as keeping the syntax as close as possible to previous versions of the plugin might make migration for script authors less painful.

A plugin author might also be new to the new software model and might not be au fait with some of the intricacies of managed model elements and would prefer to settle for a more familiar unmanaged element.

Solution

Keep the existing extension class the same and enhance it with some declarative DSL methods. The latter will be necessary as unmanaged DSL object are not decorated as would have been the case with project extension objects. Finish it off by adding a model creation rule to create the unmanaged object.

Examples

Continuing on from Link Extension to Model, we can stay with the external tool metaphor. In this case out legacy extension might look something like below for GNU Make.

Legacy extension for external tool
1 class ExternalToolExtension {
2     String executable = 'make'
3     List<String> execArgs = []
4 
5     void execArgs(String... args) {
6         this.execArgs.addAll(args as List)
7     }
8 }

We can keep our extension code mostly intact and enhance it with some declarative methods. (If we have anything that depends on the legacy Project object we need to rework those sections as we won’t have access to it anymore).

Legacy extension ehanced and ready to be used ans unmanaged model element
 1 class ExternalToolExtension {
 2     String executable = 'make'
 3     List<String> execArgs = []
 4 
 5     void execArgs(String... args) {
 6         this.execArgs.addAll(args as List)
 7     }
 8 
 9     void executable(String exe) { 
10         this.executable = exe
11     }
12 }
  1. This allows for executable '/usr/bin/make' in addition to executable = '/usr/bin/make', which is important if we want to keep the recommended declarative style.

All that remains is to add a model creation rule. As this is an unmanged model element our rule has to return an instance of the model element instead of void as would be the case for managed model elements.

Creating the ruleset
1 class ExtensionContainerRules extends RuleSource {
2     @Model
3     ExternalToolExtension externalTool() {  
4         new ExternalToolExtension() 
5     }
6 }
  1. Model creation rules for unmanaged elements always return an instance of the element type.
  2. Return an instance of the modified extension type. If the original extension’s constructor took a Project object as a parameter, it will need to be modified to operrate without access to the Project instance.

Once the rules are applied we have all of the greatness of the original extension object available within the model element.

Configuring as a model element
 1 model {
 2     externalTool {           
 3         executable = 'gmake' 
 4         execArgs = ['-i']    
 5         execArgs '-s','-B'   
 6     }
 7 
 8     externalTool {
 9         executable 'amake'   
10     }
11 }
  1. As the model rule was called externalTool it is available as a top-level model element by the same name within the model DSL. Anything that was configurable in the original extension is still configurable in the model configuration block as the rest of the callouts demonstrate.
  2. Configuration by assignment.
  3. List configuration assignment.
  4. Append items to the list.
  5. Due to the additional method that was added in the extension, we can still use a declarative form.

Caveats

This is a suggested approach if DSL-compatibility with an older plugin version needs to be maintained. However, the following needs to be kept in mind:

  • As the extension is unmanaged, Gradle can never guarantee the configuration to be immutable.
  • Gradle will not decorate the extension with any other methods, and it is up to the plugin author to add the appropriate enhancements.

References & Credits

  • Mark Viera clarified a number of caveats with this approach. [MViera3]