How do I build a fat jar (bundle) with Bndtools in a Gradle project? - gradle

I am currently trying to create a bundle with bnd in a Gradle project.
The idea was to try getting the list of jar dependencies with Gradle and modify the jar task to add the libs inside the bundle.
Let's say, I would like to remove the includeresource.
-includeresource: lib/jsoup.jar=jsoup-1.14.3.jar
Bundle-ClassPath: ., lib/jsoup.jar
I tried some variations of:
jar {
duplicatesStrategy = 'EXCLUDE'
from {
configurations.runtimeClasspath.findAll {
it.name.endsWith('jar')
}.collect { println it.name; zipTree(it) }
}
}
I can see the name of the jar being printed, but not included inside the bundle, (I know zipTree would expand).
Suggestions from https://discuss.gradle.org/t/how-to-include-dependencies-in-jar/19571/16 do not seem to be valid for bnd, and I suspect bnd overrides the jar task somehow.
A suggestion as:
jar {
def libBuildDir = mkdir "${buildDir}/resources/main/lib"
copy {
from { configurations.jarLibs }
into { libBuildDir }
}
}
Would be perfect, but it does not seem to work for bundles.
Any ideas?

Related

Fat Jar expands dependencies with Gradle Kotlin DSL

I am trying to build a fat jar using the following in my Kotlin based gradle file.
val fatJar = task("fatJar", type = Jar::class) {
baseName = "safescape-lib-${project.name}"
// manifest Main-Class attribute is optional.
// (Used only to provide default main class for executable jar)
from(configurations.runtimeClasspath.map({ if (it.isDirectory) it else zipTree(it) }))
with(tasks["jar"] as CopySpec)
}
tasks {
"build" {
dependsOn(fatJar)
}
}
However, the fat jar has all the dependencies expanded out. I would like to have the jars included as is in a /lib directory but I cannot work out how to achieve this.
Can anyone give any pointers as to how I can achieve this?
Thanks
Well you are using zipTree in that map part of the spec, and it behaves according to the documentation: it unzips the files that are not a directory.
If you want the jars in /lib, replace your from with:
from(configurations.runtimeClasspath) {
into("lib")
}
In case anyone is using kotlin-multiplatform plugin, the configuration is a bit different. Here's a fatJar task configuration assuming JVM application with embedded JS frontend from JS module:
afterEvaluate {
tasks {
create("jar", Jar::class).apply {
dependsOn("jvmMainClasses", "jsJar")
group = "jar"
manifest {
attributes(
mapOf(
"Implementation-Title" to rootProject.name,
"Implementation-Version" to rootProject.version,
"Timestamp" to System.currentTimeMillis(),
"Main-Class" to mainClassName
)
)
}
val dependencies = configurations["jvmRuntimeClasspath"].filter { it.name.endsWith(".jar") } +
project.tasks["jvmJar"].outputs.files +
project.tasks["jsJar"].outputs.files
dependencies.forEach { from(zipTree(it)) }
into("/lib")
}
}
}

How to include all files from jar into war using Gradle

I was trying plugins:
io.freefair.war-overlay - but it just overlay one war to another,
waroverlay - it has appropriate option "includeWarJars true" but it
does't works for me.
Currently I'm trying write script:
dependencies {
/* jar, his files I would like to include in war */
compile project(':my_jar_1')
}
war {
/* Step 1. Copy all from my_jar_1 into WEB-INF/classes */
into('WEB-INF/classes') {
from configurations.compile
.filter { it.name.startsWith("my_jar_1") }
.collect { zipTree(it).matching { exclude 'META-INF/**/*.*' }}
}
/* Step 2. Deleting jar from war WEB-INF/lib. I got stuck here. It println, but doesn't delete jar */
doLast {
zipTree('build/libs/war_1-0.0.0.war').files.each {
if (it.path.endsWith('.jar')) {
delete it
println 'DELETED ' + it.path
}
}
}
}
Could somebody tell me how to make it work?
Or maybe smb know more elegant solution?
Also I was trying to declare my own configuration
configurations { overlay }
dependencies {
overlay project(':my_jar_1')
}
war {
into('WEB-INF/classes') {
from configurations.overlay
...
But it shows error
FAILURE: Build failed with an exception.
What went wrong: Failed to capture snapshot of input files for task 'war' property 'rootSpec$1$1' during up-to-date check.
Failed to create MD5 hash for file '/home/user/projects/OveralJarToWar/my_jar_1/build/libs/my_jar_1-1.0-SNAPSHOT.jar'.
The content of WEB-INF/lib and WEB-INF/classes is configured by single property classpath of war task. According to documentation:
Any JAR or ZIP files in this classpath are included in the WEB-INF/lib directory. Any directories in this classpath are included in the WEB-INF/classes directory
So, in your case, the classpath should be modified as follow
war {
def myJar = project(':my_jar_1').jar.outputs
def myClassesAndResources = project(':my_jar_1').sourceSets.main.output
classpath = classpath - myJar + myClassesAndResources
}

Gradle compileKotlin includeRuntime not adding runtime to jar

I have a Kotlin Gradle project, and I would like to include Kotlin's runtime and stdlib in the jar file. I'm currently using this, but it's not including the runtime or stdlib when I build the project using the build.gradle configuration.
compileKotlin {
kotlinOptions {
includeRuntime = true
noStdlib = false
}
}
This is the Gradle code I'm using to include the runtime/stdlib in the jar, but it isn't working like I expect it to. Here's the full build.gradle file for some context:
https://github.com/BenWoodworth/CrossPlatformGreeter/blob/bd1da79f36e70e3d88ed871bc35502ecc3a852fb/build.gradle#L35-L43
Kotlin's Gradle documentation seems to indicate that setting kotlinOptions.includeRuntime to true should include the Kotlin runtime in the resulting .jar.
https://kotlinlang.org/docs/reference/using-gradle.html#attributes-specific-for-kotlin
Edit:
This might be related. When I run compileKotlin, I'm getting a couple of warnings related to the runtime:
:compileKotlin
w: Classpath entry points to a non-existent location: <no_path>\lib\kotlin-runtime.jar
BUILD SUCCESSFUL
Here's an alternative I came up with. It'll add the Kotlin runtime and stdlib to the jar using the jar task.
jar {
from {
String[] include = [
"kotlin-runtime-${version_kotlin}.jar",
"kotlin-stdlib-${version_kotlin}.jar"
]
configurations.compile
.findAll { include.contains(it.name) }
.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Gradle Kotlin DSL:
tasks.withType<Jar> {
val include = setOf("kotlin-stdlib-1.4.0.jar")
configurations.runtimeClasspath.get()
.filter { it.name in include }
.map { zipTree(it) }
.also { from(it) }
}
Try this:
Build script
Unpack jar
Add kotlin runtime and rapack it
type gradle packJar to create jar with kotlin runtime in it
or
type gradle runJar to create and run the jar file
build Script

Gradle copy build script dependency to folder

We are building one of our applications with gradle and part of the distribution I want to include an external jar which is not a run time dependency in a config folder. That jar is needed as part of the application install and it contains some custom ant tasks.
Our build script dependency looks like below:
buildscript {
...
dependencies {
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1'
classpath 'my-group:custom-tasks:1.2.3'
}
}
How would I access and copy the custom-task-1.2.3.jar into a certain folder so I can include it in my distribution? Something like below:
task copyCustomTasks {
doLast {
copy {
// This below is a make up to express what I want
from buildscript.dependencies
include 'custom-tasks*.jar'
into "$buildDir/config"
}
}
}
If this is not the gradle way of doing things please let me know what alternatives I have.
Thank you in advance for your help.
UPDATE
I solved my problem in a different way by creating an extra configuration. However I would still be interested to find out how you can access build script dependencies at run time. Thanks again for your inputs.
configurations {
install {
description = "application install classpath"
transitive = true
}
}
...
dependencies {
...
install('my-group:custom-tasks:1.2.3')
...
}
...
task copyInstallDeps {
doLast {
copy {
from configurations.install
into "$buildDir/config"
}
}
}
You're quite close:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.guava:guava:18.0'
}
}
task copyLibs(type: Copy) {
from buildscript.configurations.classpath
into 'lib'
}

How to include jars from libs folder to another jar?

I have Gradle JAR (Main) project. I have other commons-io jars (dependent) that I would like to package them with the Main JAR. I tried below, but when I decompile Main JAR, I see all the dependent JARS inside libs folder with .jar extension.
jar {
from("$projectDir") {
include 'libs/**'
}
}
What I want is the class files from all the dependent JARs into Main JAR. I am doing this because the Main JAR is going to be used by multiple projects. So that way, I do not have to include all the dependent JARs.
Thanks
As far as I know You cannot pack other jars into single jar just like that. What You need to do is to extract all the jars and pack the content into single file.
Following piece of code prepares such jar for declared dependencies
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.guava:guava:16.0.1'
compile 'com.google.inject:guice:3.0'
}
task fatJar(type: Jar, dependsOn: jar) {
baseName = project.name + '-fat'
deps = configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
from(deps) {
exclude 'META-INF/MANIFEST.MF'
}
}
use this.
into(libForderName){
from {
configurations.compile.collect {
it.isDirectory() ? it : it.getAbsoluteFile()
}
}
}

Resources