Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

execute gradle shadowjar task twice in same build file

I am trying to create two 'fatJars' using ShadowJar plugin as part of the same build file. I am trying to run the shadowJar task twice inside the build by declaring two tasks of ShadowJar type

So far, I have defined two tasks like so:

task shadowjar_one (type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar)
task shadowjar_two (type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar)

and now trying to create my jars like so:

shadowjar_one {
    mergeServiceFiles()
    exclude 'somefile.txt'

    archiveName = 'jar1.jar'

    appendManifest {
         attributes 'Main-Class': 'some.package.someClass'
    }
}

shadowjar_two {
    mergeServiceFiles()
    exclude 'someOtherfile.txt'

    archiveName = 'jar2.jar'

    appendManifest {
         attributes 'Main-Class': 'some.package.someOtherClass'
    }
}

The problem I am facing is that the jars are created, but they do not contain any of the other dependencies (packages, files etc) from 'other' jars. The jars only contain the META-INF and current project's package directories.

Any idea what could be the issue?

Note: I am expecting two slightly different jar files to be produced. Both must have the same project codebase with differences in the Main-Class attribute of manifest (and a couple of other small differences)

Many Thanks!

like image 407
John Fitch Avatar asked Aug 14 '14 13:08

John Fitch


3 Answers

The author gave a very good solution (in that it is both short and working) here:

https://github.com/johnrengelman/shadow/issues/108

I'm actually using a tweak to that solution, appearing at the bottom of that page (I've added remarks to explain it a little):

task bootstrapNodeJar(type: ShadowJar) {
 group = "shadow" // Not a must have, but it's always good to have a group, you can chose whichever - this is the one shadowJar belongs to
 description = "Builds a Bitsquare bootstrap node executable jar" // Same as the above
 manifest.attributes 'Main-Class': 'io.bitsquare.app.cli.BootstrapNodeMain' // The main attraction! Be sure to update this line
 classifier = 'bootstrapNode' // General jar task property - see more about it in the Gradle manual
 from(project.convention.getPlugin(JavaPluginConvention).sourceSets.main.output) // Leave as is
 configurations = [project.configurations.runtime] // Same as the above
 exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA') // This one is actually really important!

 // Here you can add other Jar properties like destinationDir, for example
}
like image 64
r02 Avatar answered Nov 18 '22 23:11

r02


Shadow plugin author here - I was just made aware of this question here. What you are encountering is the fact that the Shadow plugin creates and configures a shadowJar task using a set of defined conventions for that task.

When you are creating your own tasks using that type, you'll need to manually define a number of those configuration options since there is no way for the plugin to know what your intent is with those tasks.

You can reference the configuration that is being applied to the built in task here: https://github.com/johnrengelman/shadow/blob/master/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy#L38-L63

like image 28
John Engelman Avatar answered Nov 19 '22 00:11

John Engelman


A workaround that I've used is to have a single shadowJar task, but pass parameters. In your case, something like:

shadowJar {
  mergeServiceFiles()
  exclude System.properties.getProperty('exclude')
  archiveName = System.properties.getProperty('archiveName')
  appendManifest {
    attributes 'Main-Class': System.properties.getProperty('mainClass')
  }
}

Then, when starting your application:

gradlew shadowJar -Dexclude=... -DarchiveName=... -DmainClass=...
like image 4
Sergio Agostinho Avatar answered Nov 19 '22 00:11

Sergio Agostinho