Tuesday, April 30, 2013

beforeEvaluate

In Gradle, I've come upon a development pattern. It usually follows this pattern:
  1. Write plugin
  2. Write Extension, so that the user can customize the behavior of the plugin
  3. Wish I could use Convention Mappings, but then resist since they're not public
  4. Realize that I can't look at the Extension until afterEvaluate, which is after the user's code has had a chance to set values on the Extension
  5. Put all my plugins logic in project.afterEvaluate
  6. Swear at any @DeferredConfigurable plugins
  7. Fight the ordering of my plugins
When I say @DeferredConfigurable, I'm pretty specifically looking at the PublishingPlugin's DefaultPublishingExtension, which will throw an exception if you try to configure it after it's been configured. Honestly this make sense, but it doesn't make it any easier to use. The publish plugin adds it's own afterEvaluate which forces the extension to be configured, since it needs to create tasks before the task graph is built. 

This means that if I have a Plugin that uses an Extension which is going alter a Software Component, it HAS to run before the publish plugin is applied, so that my afterEvaluate is run before the PublishingExtension's afterEvaluate is, keeping in mind that afterEvaluate is evaluated in insertion order. But that's impossible since I can't configure the PublishingExtension until after the PublishingPlugin has added the PublishingExtension to the project. I think I've also seen issues where the IvyPublication is resolved before I can add in my generated/imported dependencies, which is another reason I need to run before the publish plugin's afterEvaluate.

Technically the publish plugin is @Incubating, so I'm not faulting the Gradle guys and don't even expect this to be a bug in its own right, since they're still figuring it out. In my cause, I require the ability to modify the module descriptor, and that's only really possible with the publish plugin, so I'll live with it. Though I'm starting to get the feeling that there's some fundamental ordering issues cropping up, which will eventually grow out of control.

My solution is implement a beforeAfterEvaluate method that lets me jump to the front of the dispatcher LinkedHashMap. Caveat, there's lot of internal classes being used, so I know that it can break in future versions of Gradle.


Loading ....

This doesn't answer the general ordering issue, but it can unblock a stalemate in the order of plugins. It's worth mentioning that Convention Mappings aren't the solution either, they're just an opportunistic lazy evaluation that "typically" works in your favor.