Gradle multi project distribution
Asked Answered
A

5

21

I'm trying to make a dist of a multi project build. The root project looks something like this:

apply plugin: 'distribution'
version 1.0
distributions {
    main {
        baseName = 'someName'
        contents {
            from 'nodes' 
        into 'nodes'
        }
    }
}

It just copies a folder with some files to the dist.

I now want each subproject to inject its stuff into the dist. I want to add each subprojects jar, any dependecies, and possibly some other files etc...

I have no idea how to inject from the subproject to the root. Should I even do something like that? What i mean is something like this:

subprojects {
   apply java...
   ...

   // pseudocode
   jack into the root project dist plugin
   put my produced jars and dependencies in a folder with my name
   ...
}

Does anyone have any examples, or just point me in the right direction?

thanks!

Agamete answered 17/7, 2013 at 20:35 Comment(0)
B
14

I was looking for the same thing. With some peeking at the API docs and Gradle' own build files, I came to the following:

apply plugin: 'distribution'

distributions {
    main {
        contents {
            into('bin') {
                from { project(':subproject1').startScripts.outputs.files }
                from { project(':subproject2').startScripts.outputs.files }
                fileMode = 0755
            }
            into('lib') {
                def libs = []
                libs << project(':subproject1').configurations.runtime - project(':runner').configurations.runtime
                libs << project(':subproject2').configurations.runtime
                from libs
                from project(':subproject1').jar
                from project(':subproject2').jar
            }
        }
    }
}

The contents {} closure is a CopySpec, knowing that makes using the distribution plugin way simpler :)

Check out Gradle' own subprojects/distributions/distributions.gradle file for some great examples of using the CopySpec.

This works.

  • The substraction is to remove duplicated jars.
  • The ".jar" lines are to add the jar of that project as the configurations.runtime only seem to contain the dependenceis.

Sadly, currently I've no clue on how to scale this to more than two projects in a clean way. Atleast we're one step closer :)

Benita answered 21/9, 2013 at 17:55 Comment(0)
F
7

I found a solution that has been working well for me. The key is that you add a separate subproject for creating the dist. This subproject is sibling to the other subprojects. That is, do not try to script the distribution in your top-level build.gradle file.

Let's call the new subproject dist. The first thing to do is to add it to your top-level settings.gradle file in your multi-project root:

include "subproject1", "subproject2", "subproject3", ....... , "dist"

Your dist project must at minimum include:

  • build.gradle - to be detailed below
  • src/main/dist/at_least_one_dummy_file.txt - the distribution plugin always requires a src/main/$distribution.name directory. Having a non-empty one with a distribution.name of main tricks the plugin into following all the transitive dependencies of all the main sourcesets of all the sibling projects.

Next, the build.gradle file for the dist project:

/* Hook in all sibling project jars and their transitive dependencies */
apply plugin: 'java'
dependencies {
    compile project(':subproject1')
    compile project(':subproject2')
    compile project(':subproject3')
    . . . 
}

/* Distribution */
apply plugin: 'java-library-distribution'
distributions {
    main {
        baseName = "your-top-level-project-name"
        contents {
            exclude "dist-${version}.jar"
            . . . 
        }
    }
}

Then run gradle distZip. The ZIP file in dist/build/distributions will have a lib subdirectory with every single JAR you want: the sibling project JARs and their transitive dependencies.

Because of the trickery we used, the distribution plugin will make an empty JAR called dist-${version}.jar. For cosmetic reasons, I remove it with the exclude call above, but it is harmless. You could also use a second exclude call to remove the at_least_one_dummy_file.txt if there really is no content under src/main/dist that you want to include. If you do not want add any artifacts and/or remove the ones mentioned here, then you don't even need a contents section at all.

I also have found ways of selectively including different artifacts based on whether this is a "dev" or "prod" distribution, a la Maven profiles. If you want me to add that, please post in comments and I will.

Flocculent answered 16/5, 2014 at 17:29 Comment(0)
V
3

I actually made it work by combining the approaches from both, pvdissel and sparc_spread.

In my root project I created a directory src/main/dist where I put exactly one file called .gitkeep.

The build.gradle file of my root project looks as follows:

apply plugin: 'java-library-distribution'

allprojects {
    ....
}

dependencies {
    // let root project depend on all subprojects that have the
    // application plugin enabled
    project.subprojects.each { p ->
        p.plugins.withType(ApplicationPlugin) {
            compile p
        }
    }
}

distributions {
    main {
        contents {
            // exclude unnecessary files from archive
            exclude ".gitkeep"
            exclude "cs3d-toolbox-${version}.jar"

            // add start scripts of all plugins that have the
            // application plugin enabled to the archive
            project.subprojects.each { p ->
                p.plugins.withType(ApplicationPlugin) {
                    into('bin') {
                        from { p.startScripts.outputs.files }
                        fileMode = 0755
                    }
                }
            }
        }
    }
}

Works quite well for me. Tested with Gradle 2.0.

Vide answered 25/7, 2014 at 15:21 Comment(0)
F
1

This is the setup I'm using in a project with multiple libraries to create a "release" archive:

apply plugin: 'distribution'

distributions {
  main {
    baseName = libVersion
    contents {
      project.subprojects.each { sub ->
        into('lib') {
          from sub.jar
        }
        into('src') {
          from sub.sourcesJar
        }
        into('doc') {
          from sub.javadocJar
        }
      }
    }
  }
}

Using distZip task creates an archive with all libraries with their files separated into three folders (lib contains the actual jars, src contains jars with sources and doc contains - you guessed it - Javadoc jars).

Francoise answered 30/4, 2016 at 13:58 Comment(0)
R
0

Simple as that.

distributions {
    main {
        contents {
            into('lib') {
                from subprojects*.jar
                from subprojects*.configurations.runtimeClasspath
            }
            into('doc') {
                from subprojects*.javadocJar
            }
        }
    }
}
Rato answered 30/1, 2021 at 23:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.