Unable to use gradle-plugin compiled in context of multi-module build for other sub-modules in the same project

Some preface for the problem:

I’m trying to experimentally port build system for my library from MAVEN to gradle. Library contains multiple projects:

  • API.jar
  • IMPL.jar
  • MAVEN plugin to custom-compile resource coming with applications using my lib. Compiler comes in IMPL.jar, plugin just invokes it at build time. IMPL jar is not aware about gradle and gradle plugin and internally uses commons-io:2.4
  • APP1 … APPN (web applications) - contain custom resources requiring compilation by plugin

I tried reproducing the same in gradle and got following problems:

  1. IMPL.jar uses ‘commons-io:2.4’ and during test time this conflicts with gradle’s commons-io, which is 1.4.
    I’ve already asked the question in more details here - http://stackoverflow.com/questions/33244177/nosuchmethoderror-under-test-run-with-gradle. Ok, i just turned off the unit test and came across problem #2

  2. I just see no sufficient way to refer plugin from another sub-module. Here is what i’ve done, hopefully there is some other way, because with these lines in build.gradle

    buildscript {
    repositories { flatDir dirs: “${rootProject.projectDir}/my-gradle-plugin/build/libs” }
    dependencies { classpath “my-test:my-gradle-plugin” }
    }

    apply plugin: ‘my-test’

i’m getting this error:

* What went wrong:
A problem occurred configuring project ':my-app'.
> Could not resolve all dependencies for configuration ':my-app:classpath'.
   > Could not find my-test:my-gradle-plugin:.
     Searched in the following locations:
         file:/C:/Temp/my-test/my-gradle-plugin/build/libs/my-gradle-plugin-.jar
         file:/C:/Temp/my-test/my-gradle-plugin/build/libs/my-gradle-plugin.jar
     Required by:
         my-test:my-app:unspecified

Problem does not appear if I build plugin beforehand, i.e. my-gradle-plugin.jar is available in ‘libs’ folder before I launch ‘gradle build’.

Note: i have to have plugin as separate module and be publishable to repository because it will be used in external builds too.

BTW, i have minimalist test project, but “Sorry, new users can not upload attachments.”

I’m new to Gradle and I ran into a similar problem recently. If I understand correctly, it’s the chicken-egg problem. The overall build has to understand all build.gradle files to run the build. But one of the applied plugins is not present at that time, which is expected to be created by the same build; so the chicken-egg case.

I would say - yes it is exactly it, “the chicken-egg problem”, unless gradle is able to deffer evaluation of model of sub-set of child projects using ‘local’ plugin until it is compiled. Unfortunately I was unable to find such possibility in gradle so far.

I’ve got solution for that problem:

  1. split whole project into 2 parts - (1) plugin and modules required to build plugin + (2) all other modules that require plugin to be built
  2. to avoid building these 2 parts each time separately - merge them via parent project, which calls children one after another

Here is the code for copy/paste. During execution of the root build.gradle all requested tasks are forwarded to children.

// This 'root' build script just forwards requested tasks
// into child 'core' and 'apps' builds.

def requestedTasks = gradle.startParameter.taskNames
def childTasksToRun = requestedTasks - ["run", "runLib", "runApps"]

task runLib(type: GradleBuild) {
    dir = 'core/'
    buildFile = 'core/build.gradle'
    tasks = childTasksToRun
    startParameter.excludedTaskNames = gradle.startParameter.excludedTaskNames
}

task runApps(type: GradleBuild) {
    dir = 'apps/'
    buildFile = 'apps/build.gradle'
    tasks = childTasksToRun
    startParameter.excludedTaskNames = gradle.startParameter.excludedTaskNames
}

task run {
    tasks.runLib.execute()
    tasks.runApps.execute()
}

// generate dummy tasks for each requested task
(gradle.startParameter.taskNames + gradle.startParameter.excludedTaskNames).each { name ->
    if( name != "run" ) {
        task "$name" {
            enabled = false
            finalizedBy run
        }
    }
}