distTar only includes subproject jars on second execution, following a clean

I’m using Gradle 3.5 on a Mac. I have a multi-project build. Top level project has the base and distribution plugins applied. I want to create a tar file via the distTar task, to include some files from the top-level project (from a bespoke configuration language). It also needs to include jar files from two java sub-projects.

Basic setup in top-level build.gradle file:

allprojects {
    group 'wBCUtils'
    apply plugin: 'base'
    apply plugin: 'distribution'
}

project.subprojects { subproject ->
    subproject.tasks.withType(Jar) { jarTask ->
        distTar.dependsOn subproject:clean
        distTar.dependsOn jarTask

    }
}

distributions {
    main {
        baseName = 'wBC'
        contents {
            into('Lucent') {
                from 'Lucent'
                exclude "WBC/AAA2"
                exclude "WBC/AAAIPS"
            }

            project.subprojects.each { sub ->
                into("Lucent/WBC/AAA/lib") {
                    from "${sub.buildDir}/libs"
                }
            }
        }
    }
}

If I run a gradle:clean first, then when running gradle distTar I get:

$ gradle distTar
:distTar
:deprecated-plugins:clean UP-TO-DATE
:deprecated-plugins:compileJava
:deprecated-plugins:compileGroovy NO-SOURCE
:deprecated-plugins:processResources NO-SOURCE
:deprecated-plugins:classes
:deprecated-plugins:jar
:deprecated-plugins:distTar NO-SOURCE
:plugins:clean UP-TO-DATE
:plugins:compileJava
:plugins:compileGroovy NO-SOURCE
:plugins:processResources NO-SOURCE
:plugins:classes
:plugins:jar
:plugins:distTar NO-SOURCE

BUILD SUCCESSFUL

but the sub-project jar files are missing (the ojdbc6.jar file comes from the top-level project):

$ tar tvf build/distributions/wBC-1.1.0-SNAPSHOT.tar | grep jar
-rw-r--r--  0 0      0     1988051 22 Sep 14:35 wBC-1.1.0-SNAPSHOT/Lucent/WBC/AAA/lib/ojdbc6.jar

If however I run the command a second time:

 $ gradle distTar
:distTar
:deprecated-plugins:clean
:deprecated-plugins:compileJava
:deprecated-plugins:compileGroovy NO-SOURCE
:deprecated-plugins:processResources NO-SOURCE
:deprecated-plugins:classes
:deprecated-plugins:jar
:deprecated-plugins:distTar NO-SOURCE
:plugins:clean
:plugins:compileJava
:plugins:compileGroovy NO-SOURCE
:plugins:processResources NO-SOURCE
:plugins:classes
:plugins:jar
:plugins:distTar NO-SOURCE

BUILD SUCCESSFUL

The desired jar files are now there:

$ tar tvf build/distributions/wBC-1.1.0-SNAPSHOT.tar | grep jar
-rw-r--r--  0 0      0     1988051 22 Sep 14:35 wBC-1.1.0-SNAPSHOT/Lucent/WBC/AAA/lib/ojdbc6.jar
-rw-r--r--  0 0      0        6218 10 Oct 15:41 wBC-1.1.0-SNAPSHOT/Lucent/WBC/AAA/lib/wBCUtilsPreSOGEA-1.1.0-SNAPSHOT.jar
-rw-r--r--  0 0      0       14728 10 Oct 15:41 wBC-1.1.0-SNAPSHOT/Lucent/WBC/AAA/lib/wBCUtils-1.1.0-SNAPSHOT.jar

I assume something in my mental model is wrong. I assumed that even if I had run a gradle clean, given the distTar depends on the jar task of each subproject, that it would build the subproject jars first and then include them in the tar file, so I’m not sure what is happening.

I’ve tried various other ways, such as trying to call the jar task directly on the subprojects within the subproject.each construct e.g.

project.subprojects.each { sub ->
        into("Lucent/WBC/AAA/lib") {
            from sub.jar
        }
}

but that always fails with the message:

Could not get unknown property 'jar' for project ':deprecated-plugins' of type org.gradle.api.Project.

Any help appreciated!

Graeme.

Your solution to use the task directly is the correct approach. However, you need to defer your configuration until after the subprojects have been configured (each is iterating the sub projects before they have been configured and had the necessary plugins applied, therefore no jar task exists).

Something like the following should help:

project.subprojects.each { sub ->
    sub.afterEvaluate {
        into("Lucent/WBC/AAA/lib") {
            from sub.jar
        }
    }
}

EDIT: The solution below from @sterling is much better IMO.

I think the best way to do this would be to use project dependencies. You should avoid reaching into a project from other projects since it entangles them more.

Something like:

configurations {
   installedJars
}

dependencies {
   installedJars project(":abc")
   ...
   // or use a loop here of subprojects
}

distributions {
    main {
        baseName = 'wBC'
        contents {
            into('Lucent') {
                from 'Lucent'
                exclude "WBC/AAA2"
                exclude "WBC/AAAIPS"
            }
            into("Lucent/WBC/AAA/lib") {
                from configurations.installedJars
            }
        }
    }
}
1 Like

Thanks, that was the answer I was looking for. I added transitive=false to installedJars, as otherwise I also got the jars of transitive dependencies. I also added the dependencies via a loop.

configurations {
    installedJars {
        transitive = false
    }
}

dependencies {
    subprojects.each { sub ->
        installedJars sub
    }
}

I tried your suggested change, but for some reason it didn’t make a difference. As you suggested, I went with Sterling’s solution. Thanks for your help!