Matthias
Matthias

Reputation: 12259

Collect files in build directory of parent project

I have a multi-module project in Gradle

root
-- ProjectA
-- ProjectB

Both ProjectA and ProjectB use the application plugin to create a zip in "ProjectA/build/distributions" and "ProjectB/build/distributions" respectively.

Now I want to copy the two zip files into "root/build/distributions".

I have tried various approaches, e.g. adding this in the build.gradle of the root project:

subprojects {
    task copyFiles(type: Copy) {
        includeEmptyDirs = true
        from "$buildDir/distributions"
        include '*.zip'
        into "$parent.buildDir/distributions"
    }
    copyFiles.dependsOn(build)
}

or just adding a task to the root project:

task copyFiles(type: Copy) {
    from "ProjectA/build/distributions"
    from "ProjectB/build/distributions"
    include "*.zip"
    into "$buildDir/distributions"
}

build.dependsOn(copyFiles)

However, in both cases, nothing happens. No file gets copied.

What am I doing wrong?

Upvotes: 0

Views: 1346

Answers (1)

Bjørn Vester
Bjørn Vester

Reputation: 7600

I can see two things you are doing wrong:

  1. You have relative paths to the subprojects. This is discouraged as it means you will always have to invoke Gradle from the root folder. And if a Gradle daemon was started from somehere else, it will fail. You could fix it by using the rootDir property (e.g. `from "$rootDir/ProjectA/...") but there is a better way...

  2. The other problem is that you have no dependencies from your copyFiles task in your root project to the required distZip tasks in the sub-projects. So if the distributions have not already been built previously, there are no guarantees that it will work (which it apparently doesn't).

To fix it, you can have a look at the question "Referencing the outputs of a task in another project in Gradle", which covers the more general use case of what you ask. There are currently two answers, both of which are good.

So in your case, you can probably do either this:

task copyFiles(type: Copy) {
    from tasks.getByPath(":ProjectA:distZip").outputs
    from tasks.getByPath(":ProjectB:distZip").outputs
    into "$buildDir/distributions"
}

or this:

task copyFiles(type: Copy) {
    subprojects {
        from(tasks.withType(Zip)) {
            include "*.zip"
        }
    }
    into "$buildDir/distributions"
}

Gradle will implicitly make the copy task depend on the other tasks automatically, so you don't need to do that yourself.

Also note that the currently accepted answer to the question I referenced is about configuration variants, and this is probably the most correct way to model the relationships (see here for more documentation on the topic). But I prefer the simplicity of the direct access to the tasks over the verbose and arguably more complex way to model it through configurations. Let's hope it gets simpler in a later release.

Upvotes: 1

Related Questions