How to exclude all but one specific jar from Gradle distZip task? - gradle

On line 192 of https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/java/org/gradle/api/plugins/ApplicationPlugin.java is:
libChildSpec.from(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
Since my project is using Spring Boot and it generates a standalone jar, how do I exclude all the other jars from the distZip task?

distributions {
main {
contents {
into('lib') {
project.configurations.runtimeClasspath.files.findAll { file ->
file.getName() != project.tasks.jar.outputs.files.singleFile.name
}.each { file ->
exclude file.name
}
}
}
}
}

Related

Use gradle to build a jarfile from other jarfiles

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

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")
}
}
}

Using Gradle to build a jar with dependencies with Kotlin-DSL

There is already an answer to the question: how to include all the dependencies in a jar file though it's for Groovy
I'm using gradle with kotlin-dsl and the code is not compatible. I tried to make it work using a few ways including:
tasks.withType<Jar> {
configurations["compileClasspath"].forEach { file: File ->
copy {
from(zipTree(file.absoluteFile))
}
}
}
Though this doesn't work. So how to include the dependencies using kotlin-dsl in gradle?
This will work:
tasks.withType<Jar>() {
configurations["compileClasspath"].forEach { file: File ->
from(zipTree(file.absoluteFile))
}
}
There's no need in copy { ... }, you should call from on the JAR task itself.
Note: Gradle does not allow changing the dependencies after they have been resolved. It means that the block above should be executed only after the dependencies { ... } are configured.
my case
withType<Jar> {
enabled = true
isZip64 = true
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveFileName.set("$project.jar")
from(sourceSets.main.get().output)
dependsOn(configurations.compileClasspath)
from({
configurations.compileClasspath.get().filter {
it.name.endsWith("jar")
}.map { zipTree(it) }
}) {
exclude("META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA")
}
}

Gradle sourceSet depends on another sourceSet

This Question is similar to Make one source set dependent on another
Besides the main SourceSet I also have a testenv SourceSet.
The code in the testenv SourceSet references the main code, therefor I need to add the main SourceSet to the testenvCompile configuration.
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main
}
This does not work, because you cannot directly add sourceSets as dependencies. The recommended way to do this is:
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main.output
}
But this does not work correctly with eclipse, because when I clean the gradle build folder, eclipse can't compile anymore, since it depends on the gradle build.
Also if I change main code I'd have to rebuild the project in gradle for the changes to take effect in eclipse.
How do I declare the dependencies correctly?
EDIT:
This
sourceSets {
testenv
}
dependencies {
testenvCompile files(sourceSets.testenv.java.srcDirs, sourceSets.testenv.resources.srcDirs)
}
works for the main source, but because I now reference the .java files I am missing generated classes from the Annotation-Processor :(
So after all this is the way to go:
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main.output
}
To make it work correctly with eclipse you have to manually exclude all sourceSet outputs from the eclipse classpath.
This is ugly, but it works for me:
Project proj = project
eclipse {
classpath {
file {
whenMerged { cp ->
project.logger.lifecycle "[eclipse] Excluding sourceSet outputs from eclipse dependencies for project '${project.path}'"
cp.entries.grep { it.kind == 'lib' }.each { entry ->
rootProject.allprojects { Project project ->
String buildDirPath = project.buildDir.path.replace('\\', '/') + '/'
String entryPath = entry.path
if (entryPath.startsWith(buildDirPath)) {
cp.entries.remove entry
if (project != proj) {
boolean projectContainsProjectDep = false
for (Configuration cfg : proj.configurations) {
boolean cfgContainsProjectDependency = cfg.allDependencies.withType(ProjectDependency).collect { it.dependencyProject }.contains(project)
if(cfgContainsProjectDependency) {
projectContainsProjectDep = true
break;
}
}
if (!projectContainsProjectDep) {
throw new GradleException("The project '${proj.path}' has a dependency to the outputs of project '${project.path}', but not to the project itself. This is not allowed because it will cause compilation in eclipse to behave differently than in gradle.")
}
}
}
}
}
}
}
}
}

How to keep Java code and Junit tests together building with Gradle

I have a project in which the main source and the test cases for that source are kept in the same package/directory. Each test class is the name of the class which it is testing with "Test" appended on the end. So if I have a Foo.java there will be a FooTest.java right next to it.
My question is, how do I build this project with Gradle? I'd still like to keep the class files separate, i.e. a folder for main classes and a folder for test classes.
This should do the trick:
sourceSets {
main {
java {
srcDirs = ["some/path"]
exclude "**/*Test.java"
}
}
test {
java {
srcDirs = ["some/path"]
include "**/*Test.java"
}
}
}
For reference, here is the code I used to try to get around the Eclipse plugin's classpath issue. Using this in combination with Peter's answer above seems to work.
// The following ensures that Eclipse uses only one src directory
eclipse {
classpath {
file {
//closure executed after .classpath content is loaded from existing file
//and after gradle build information is merged
whenMerged { classpath ->
classpath.entries.removeAll { entry -> entry.kind == 'src'}
def srcEntry = new org.gradle.plugins.ide.eclipse.model.SourceFolder('src', null)
srcEntry.dir = file("$projectDir/src")
classpath.entries.add( srcEntry )
}
}
}
}
this work for me:
eclipse {
classpath {
file {
withXml {
process(it.asNode())
}
}
}
}
def process(node) {
if (node.attribute('path') == 'src/test/java' || node.attribute('path') == 'src/test/resources')
node.attributes().put('output', "build/test-classes")
else
node.children().each {
process(it)
}}

Resources