Inversion-of-control for build task impl


(Anne Stellingwerf) #1

In our current Ant build logic, there are several occasions where we use some jars from the build output in build steps later in the process. If I’d wanna fit this in the Gradle build (probably with a buildSrc subproject plugin) there’s a need for Inversion of Control. During the build the way to build certain artifacts will become available (either by truly compiling or dependency downloading in case of dependency substitution).

Example:

  1. Assume 27 projects :proprietaryZip and :componentA through :componentZ. All those 27 projects produce artifacts that end up in production.
  2. Also, buildSrc has a subproject (after following to documentation) that’s responsible for getting the components packaged in our proprietary format.
  3. :proprietaryZip is dependent on :componentA.
  4. :componentC through :componentZ are to be packaged with the proprietary format.

Now, how would one properly do this in Gradle?

  1. How can a project implement an interface that’s also available in buildSrc plugins?
  2. How can a jar file (class path/configuration in case of more complex dependencies?) expose itself as the impl of that interface, so that the build can call it?
  3. Would I be able to get all benefits of Gradle, like:
    3.1. Only recompilation when required
    3.2. Re"proprietaryZip"ping of all projects when the buildSrc plugin changes
    3.3. Re"proprietaryZip"ping of all projects when the implementation in :propietaryZip or it’s dependency :componentA changes
  4. How would Gradle Software Models help me here?

(Stefan Oehme) #2

Hey Anne,

your ProprietaryZip task would need to define a classpath input (a field of type FileCollection) from which it creates a UrlClassLoader and then loads up the implementations of your customization point. This can be done with Java’s ServiceLoader mechanism, nothing Gradle-specific needed.

In your plugin you can then set up a configuration which will serve as that classpath:

configurations {
  proprietaryZip
}
proprietaryZip.classpath = configurations.proprietaryZip

and use it in projects B to Z:

dependencies {
  proprietaryZip project(':proprietaryZip')
}