Use gradle to build a jarfile from other jarfiles - gradle

I have what should be a simple problem: I have a directory full of jarfiles, and I want to use gradle (v4.4.1) to combine the contents of these jarfiles into a single jarfile (i.e., when I do jar tf big-jar.jar, I want to see a bunch of classes, not a bunch of jars). I tried the following:
task bigJar(type: Jar) {
inputs.dir "$distLibsJar"
outputs.file "$distDir/big-jar.jar"
destinationDir = file("$distDir")
baseName = "big-jar"
from("$distLibsDir")
}
but this produces a jarfile with other jars as its contents rather than the contents of those other jars as the contents of the combined jar.
Any ideas? Thanks...

In this case best way to proceed is with a shadow jar. for this you can have this kind of configuration in build.gradle .posting some sample
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
zip64 true
//classifier "shadow" can be mentioned according to need
mergeServiceFiles()
artifacts {
shadow(tasks.shadowJar.archivePath) {
builtBy shadowJar
}
}
}
artifacts {
archives shadowJar
}
distZip {
dependsOn shadowJar
//appendix='software'
eachFile { file ->
String path = file.relativePath
file.setPath(path.substring(path.indexOf("/")+1,path.length()))
}
doLast{
//operation to perform
}
}
distributions {
main {
contents {
//from and to can be mentioned here
}
}
}
hope it helps

Related

Using a gradle task generate a properties file to be included in a jar before the jar task is executed

Before is a snippet of my build.gradle, it lists a series of tasks which should ideally be run in the following order:
createPropertiesFile
jar
obfuscate
deleteNonObfuscatedJar
deletePropertiesFile
I need createPropertiesFile to run before jar, as users are building the .jar using ./gradlew jar.
The problem I'm seeing at the moment is this error:
> Could not find method doFirst() for arguments [task ':createAuthenticationPropertiesFile']
on task ':jar' of type org.gradle.api.tasks.bundling.Jar.
I've also tried jar.dependsOn(project.tasks.createAuthenticationPropertiesFile) but I've seen that custom.properties is not included in the generated .jar when using jar.dependsOn
build.gradle:
nonObfuscatedJar = 'appNotObfuscated.jar'
task createPropertiesFile << {
def props = project.file('src/main/resources/custom.properties')
props << 'prop1=value1'
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveName = "$nonObfuscatedJar"
from sourceSets.main.output.classesDir
from configurations.compileOnly.asFileTree.files.collect { zipTree(it) }
include '**/*.class'
include '**/custom.properties'
manifest {
attributes 'Main-Class': 'com.bobbyrne01.App'
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "$libsDir/$nonObfuscatedJar"
outjars "$libsDir/app.jar"
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
}
task deleteNonObfuscatedJar (type: Delete) {
delete "$libsDir/$nonObfuscatedJar"
}
task deletePropertiesFile (type: Delete) {
delete project.file('src/main/resources/custom.properties')
}
jar.doFirst(project.tasks.createPropertiesFile)
jar.finalizedBy(project.tasks.obfuscate)
jar.finalizedBy(project.tasks.deleteNonObfuscatedJar)
jar.finalizedBy(project.tasks.deletePropertiesFile)
As a workaround, move the properties file creation to the start of the jar task:
jar {
// Create properties file
def props = project.file('src/main/resources/custom.properties')
props << 'prop1=value1'
// Build jar
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveName = "$nonObfuscatedJar"
from sourceSets.main.output.classesDir
from configurations.compileOnly.asFileTree.files.collect { zipTree(it) }
include '**/*.class'
include '**/custom.properties'
manifest {
attributes 'Main-Class': 'com.bobbyrne01.App'
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}

Gradle ShadowJar jar of jars without unzipping classes

I am trying to create a jar of jars without unzipping class files from each jar. Unfortunately shadowJar unzip's all jars and resulting jars contain directories instead of jars.
My build.gradle file is:
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile("ldapjdk:ldapjdk:1.0"){
transitive = false
}
compile("support:activemq-core:5.3.1"){
transitive = false
}
compile("support:concurrent:0.0"){
transitive = false
}
compile("dom4j:dom4j:${dom4j_version}"){
transitive = false
}
compile("commons-lang:commons-lang:${commons_lang_version}") {
transitive = false
}
}
task copyRuntimeLibs(type: Copy) {
from(project(':server').configurations.runtime)
include 'commons-lang2*'
include 'ldapjdk*'
include 'dom4j*'
include 'concurrent*'
}
task copyFiles(dependsOn: [copyRuntimeLibs])
task copyToLib( type: Copy ) {
into "$buildDir/lib"
from configurations.runtime
}
jar { dependsOn copyToLib }
shadowJar {
zip64 true
baseName = "service"
from("$buildDir/lib") {
include '**'
}
}
I've tried from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }. This also extracts classes, MANIFEST, etc.
Is there a way to not extract classes from each jar & instead make a jar of jars?
Thanks a lot.
You may want to see this GitHub issue.
https://github.com/johnrengelman/shadow/issues/111
It is actually not solved yet in the Shadow plugin, there some workarounds are shown there.

Gradle: Distributing Executable, Obfuscated Jar File

I'm trying to use gradle with proguard to obfuscate the code then generate a zip file to distribute. I'd like to use the distribution plugin, but it always includes the jar that is generated by the jar task. Is there some way to force the distribution plugin to omit the original (non-obfuscated) jar and only include the obfuscated jar? I can easily add the obfuscated jar in addition to the original, but I want to distribute the obfuscated jar instead of the original so the generated execution scripts run against the obfuscated version.
Here's my abridged build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "build/libs/${rootProject.name}.jar"
outjars "build/libs/${rootProject.name}-release.jar"
}
jar.finalizedBy(project.tasks.obfuscate)
distributions {
main {
contents {
from(obfuscate) {
into "lib"
}
from(jar) {
exclude "*.jar"
}
}
}
}
I've tried a number of things in the distributions block to try to exclude the original jar, but nothing seems to work.
Any ideas would be greatly appreciated.
This isn't the best solution, but I was able to work around the issue by renaming the jars at the end of the obfuscation step. Now, I name the original jar something like <JAR_NAME>-original.jar and I give the obfuscated jar the original jar's name. I still wish there was a better way to do it, but this seems to work.
Here is the updated, abridged build.gradle file:
import java.nio.file.Paths
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
def jarNameWithoutExtension = jar.archiveName.with { it.take(it.lastIndexOf(".")) }
def obfuscatedJarName = "${jarNameWithoutExtension}-release.jar"
def jarFileLocation = jar.archivePath.parent
def obfuscatedFilePath = Paths.get(jarFileLocation, obfuscatedJarName)
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars jar.archivePath
outjars obfuscatedFilePath.toString()
// Rename the original and obfuscated jars. We want the obfuscated jar to
// have the original jar's name so it will get included in the distributable
// package (generated by installDist / distZip / distTar / assembleDist).
doLast {
jar.archivePath.renameTo(Paths.get(jarFileLocation, "$jarNameWithoutExtension-original.jar").toFile())
obfuscatedFilePath.toFile().renameTo(jar.archivePath)
}
}
jar.finalizedBy(project.tasks.obfuscate)

How to collect javadoc jars into a zip file

For a multi-project Gradle project, foo, bar and baz. I'm trying to create a task which creates a zip file with both libraries and javadoc, i.e. foo.jar, AND foo-javadoc.jar..
./build.gradle
./settings.gradle
./foo/build.gradle
./bar/build.gradle
./baz/build.gradle
settings.gradle
include ":foo"
include ":bar"
include ":baz"
Top level build
allprojects {
apply plugin: 'java'
task generateJavadoc (type : Javadoc) {
source = sourceSets.main.allJava
classpath = sourceSets.main.compileClasspath
failOnError = false
}
task javadocJar(type: Jar, dependsOn: generateJavadoc) {
classifier = 'javadoc'
from generateJavadoc.destinationDir
}
artifacts {
archives javadocJar
}
}
task buildZip(type: Zip, dependsOn: build) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from (project(':foo').configurations.runtime) {
into 'jars'
}
from (project (':foo').configurations.archives.all) {
into 'jars'
}
}
When I invoke this with gradle clean buildZip a zip file is created, but without the any -javadoc JARs I was expecting... The JavaDoc jars are generated into the project build directories, e.g. foo/build/lib/foo-javadoc.jar I've tried multiple combinations of from project (':foo').artifacts etc.
This is possible using the following. Note javadocJar is the name of the task defined in the allprojects block
from (rootProject.allprojects.javadocJar.outputs) {
into 'javadoc'
}

How to include custom artifact in distribution in gradle

I'd like to know how to include a custom build artifact in the distribution zip built with gradle in a canonical way. I've managed to do it by referring to the path of the artifact directly, but I'm guessing there's some better way to achieve this:
task sourcesJar(type: Jar, dependsOn: tasks.classes) {
classifier 'sources'
from sourceSets.main.allSource
}
tasks.distZip.shouldRunAfter tasks.sourcesJar
tasks.distTar.shouldRunAfter tasks.sourcesJar
artifacts {
archives sourcesJar
}
distributions {
main {
contents {
from { "${libsDir}/${project.name}-${version}-sources.jar" }
}
}
}
How can I refer to the name of my sources artifact based on its definition, or alternatively is there an even better way to include built artifacts in the distributions?
It might be e.g.:
apply plugin: 'java'
apply plugin: 'distribution'
task sourcesJar(type: Jar, dependsOn: tasks.classes) {
classifier 'sources'
from sourceSets.main.allSource
}
tasks.distZip.shouldRunAfter tasks.sourcesJar
tasks.distTar.shouldRunAfter tasks.sourcesJar
artifacts {
archives sourcesJar
}
distributions {
main {
contents {
from { tasks.sourcesJar.archivePath }
}
}
}
You can also just refer to the jar task directly like so:
distributions {
main {
contents {
from { sourcesJar }
}
}
}

Resources