We have an old playframework 1.2.x version where we copy all the jars to project/lib so playframework can consume them. We would LOVE to copy all the source jars as well so that when runnig play eclipsify, we can view all the third party source. Is there a way to do this with gradle?
and I mean all the source jars that were downloaded when I ran gradle eclipse as I saw them download the cache locations. We have gradle eclipse calling play eclipsify for us on the one project as well so we can 100% just use gradle.
thanks,
Dean
this is not that straight forward as expected. The following snippet copies the source jars for all dependencies (runtime + compile) of a java project into a specific folder:
task copySourceJars(type:Copy){
def deps = configurations.runtime.incoming.dependencies.collect{ dependency ->
dependency.artifact { artifact ->
artifact.name = dependency.name
artifact.type = 'source'
artifact.extension = 'jar'
artifact.classifier = 'sources'
}
dependency
}
from(configurations.detachedConfiguration(deps as Dependency[]).resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL))
into('sourceLibs')
}
The reason we use a lenientConfiguration here is, that we don't want to fail if a source artifact cannot be resolved. There might be a more elegant way, but I havn't looked deeper into that.
hope it helps,
René
Rene answer will download sources jars of direct dependencies, not sources jars of all transitives dependencies.
Here is a task that will do the trick:
task copySourceJars( type: Copy ) {
def sources = configurations.runtime.resolvedConfiguration.resolvedArtifacts.collect { artifact ->
project.dependencies.create( [
group: artifact.moduleVersion.id.group,
name: artifact.moduleVersion.id.name,
version: artifact.moduleVersion.id.version,
classifier: 'sources'
] )
}
from configurations.detachedConfiguration( sources as Dependency[] )
.resolvedConfiguration.lenientConfiguration.getFiles( Specs.SATISFIES_ALL )
into file( 'some-directory/' )
}
One can then do the very same for javadocs jars by changing the classifier to javadoc.
Here eskatos solution translated in Kotlin DSL:
tasks {
"copySourceJars"(Copy::class) {
val sources = configurations.runtime.resolvedConfiguration.resolvedArtifacts.map {
with(it.moduleVersion.id) {
dependencies.create(group, name, version, classifier = "sources")
}
}
from(
configurations.detachedConfiguration(*sources.toTypedArray())
.resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)
)
into(File("some-directory"))
}
}
Related
First of all, sorry for my poor english.
Goal
I want create multi project containing some custom libraries as subproject with gradle.
For centralized dependency version control, using buildSrc and setting versions (spring-boot, detekt, ktlint etc.)
my-core-project(root)
+buildSrc
+-src/main/kotlin
+--int-test-convention.gradle.kts
+--library-convention.gradle.kts
+library-A
+-src
+--main/kotlin
+--test/kotlin
+-build.gradle.kts
+library-B
+-src
+--main/kotlin
+--test/kotlin
+-build.gradle.kts
+build.gradle.kts
+setting.gradle.kts
buildSrc contains common tasks for libraries(integration test, detekt, etc.)
library-A and library-B are custom libraries based on spring boot.
There is no application module or any main method.
my goal is using method of library-A and/or library-B with another separated project with adding my-core-project to dependency.
Problem
./gradlew build created 3 jar files
my-core-project
+build/libs
+-my-core-project.jar
+library-A
+-build/libs
+--library-A.jar
+library-B
+-build/libs
+--library-B.jar
copied 3 jar files to libs directory under project which actually using these library,
tried adding dependency created jar
with implementation(files("libs/library-A.jar")), class and methods are resolved well.
but with implementation(files("libs/my-core-project.jar")),
class and methods are not unresolved.
when check my-core-project.jar, recognized that any information of sub projects contained.
Here is my setting.gradle.kts and build.gradle.kts of root directory.
# setting.gradle.kts
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "my-core-project"
include(
"library-A",
"library-B"
)
# build.gradle.kts
plugins {
id("java-library")
id("io.spring.dependency-management")
}
group = "com.demo"
version = "0.0.1-SNAPSHOT"
dependencies {
api(project(":library-A"))
api(project(":library-B"))
}
repositories {
mavenCentral()
}
Tried things
In my opinion, my-core-project.jar should be fatJar(uberJar),
so i added FatJar task like this
val fatJar = task("fatJar", type = Jar::class) {
archiveBaseName.set("${project.name}-fat")
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
with(tasks.jar.get() as CopySpec)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks {
"build" {
dependsOn(fatJar)
}
}
but cannot resolve class and method,
additionally occurs version conflict with other dependency of projects using this package, due to library-A created as fatJar too.
Question
Is there a simple way packaging/bundling sub-modules into one jar file?
if there are tasks like this already in gradle, prefer to use that.
Modifying fatJar task like "add jar of submodules, not contained dependencies" can solve this problem?(even couldn't try completely newbie to gradle and kts.)
if so, can you show me how to modify task?
tried shadowJar already. that solved version-conflict problem with relocate option. but still couldn't resolve package in library-A
If structure has problem, is there a good practice/example for "bundle of library"?
thanks for reading.
TL;DR
If someone faced this problem, try set archive name shorter than current one.
For someone who faced same problem, sharing some informations.
as result, resolved this problem.(maybe even not problem)
current shadowJar configure is as following
tasks.named<ShadowJar>("shadowJar").configure {
archiveBaseName.set("shorten-name")
archiveClassifier.set("")
exclude("**/*.kotlin_metadata")
exclude("**/*.kotlin_builtins")
}
exclude kotlin_metadata, kotlin_builtins
set shorten name(original project name was 30 long characters)
I have no idea but shorten jar file name has no problem.
Interesting one is, upload in artifactory package with original(long) name worked well.
I don't know Gradle declaring dependency with files has length constraints.
implementation(files("path/to/package"))
And now it works well with original name with local jar package file.
Im sure this is amazingly simple but its been a long day and the Gradle docs frustrate me at the best of times (I have looked).
I want to include a folder (libs) inside a predefinined artifact (bundleRelease).
This happens to be on android (aar build) and inside a maven-publish block like
...
releaseJar(MavenPublication) {
...
artifact bundleRelease
}
...
using gradle 2.3.
Thanks for any help here :)
EDIT: answered here Include /libs/ folder in aar
Depends on what you want for the syntax but if you want the jar files in the root of the aar
android {
...
sourceSets {
main {
resources.includes = [ '**/libs/*.jar' ]
}
}
If you want the entire folder included then I think this should be what you want
android {
...
sourceSets {
main {
resources.includes = [ 'pathTo/libs' ]
}
}
All that said you probably don't want to package the libs with the aar because if you publish to somewhere like jcenter or mavenCentral then the maven artifact when uploaded will create a pom file that will note its dependencies and gradle will transparently import them for your lib.
As part of our build process we analyse our source code with SonarQube.
One problem with this is that we use Lombok annotations and SonarQube is not handling this very well -- our code needs to be 'delombok'ed.
Delomboked source removed the annotations and replaces the source file with the final code used by the compiler.
This can be done in gradle (see here).
Well, in part. Typically an Ant task can be used to delombok source. Code sample below:-
task delombok {
// delombok task may depend on other projects already being compiled
dependsOn configurations.compile.getTaskDependencyFromProjectDependency(true, "compileJava")
// Set up incremental build, must be made in the configuration phase (not doLast)
inputs.files file(srcJava)
outputs.dir file(srcDelomboked)
doLast {
FileCollection collection = files(configurations.compile)
FileCollection sumTree = collection + fileTree(dir: 'bin')
ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.DelombokTask', classpath: configurations.compile.asPath)
ant.delombok(from:srcJava, to:srcDelomboked, classpath: sumTree.asPath)
}
}
The problem I have with this is that I believe I would need a pre-configured ant system (I've yet to get this working).
Another approach would be to use a Maven lombok:delombok plugin (see here). However I don't know how to do this and if this would also require a pre-configured environment.
I'm not sure which is the best approach. An approach that does not require a pre-configured build system and can work fully from gradle/gradlew would be preferrable.
The ultimate aim would to have a 'delombok' project task which would essentially perform the following:
java -jar lombok.jar delombok src -d src-delomboked
edit
So i've pretty much got this to work with roughly this snippet:-
dependencies {
compile 'org.projectlombok:lombok:1.14.2'
}
task delombok {
description 'Delomboks the entire source code tree'
def srcDelomboked = 'build/src-delomboked'
def srcJava = 'src'
inputs.files file( srcJava )
outputs.dir file( srcDelomboked )
doLast {
def collection = files( configurations.compile + configurations.testCompile )
def sumTree = collection + fileTree( dir: 'bin' )
ant.taskdef( name: 'delombok', classname: 'lombok.delombok.ant.DelombokTask',
classpath: configurations.compile.asPath +
configurations.testCompile.asPath )
ant.delombok( from:srcJava, to:srcDelomboked, classpath: sumTree.asPath )
// Replace current src directory with delomboked source
copy {
from srcDelomboked
into srcJava
}
}
}
This first bit ensures that the lombok jar is available to gradle for
using the delombok ant task.
Then we configure the source files to
use.
Next we setup gradle to use the ant task.
Finally the copy task replaces the entire source tree with the delomboked version of the code. Obviously this could be removed to suit your needs.
I think the easiest way to delombok sources with gradle is:
task delombok {
description 'Delomboks the source code'
ant.taskdef(classname: 'lombok.delombok.ant.Tasks$Delombok', classpath: configurations.compile.asPath, name: 'delombok')
ant.mkdir(dir: 'build/src-delomboked')
ant.delombok(verbose: 'true', encoding: 'UTF-8', to: 'build/src-delomboked', from: 'src/main/java')
}
Using an Ant task is fine. No "Ant preconfiguration" should be necessary. Alternatively, you could use a JavaExec task to call delombok as in your last snippet. (JavaExec doesn't currently support the -jar option, so you'd have to name the main class.) Using a Maven plugin from Gradle isn't possible (except for executing Maven with an Exec task).
https://github.com/franzbecker/gradle-lombok
buildscript {
repositories {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath 'io.franzbecker:gradle-lombok:1.6'
}
}
apply plugin: 'java'
apply plugin: 'io.franzbecker.gradle-lombok'
UPD: at the moment I quite enough IntelliJ IDEA 2016.3 + Lombok plugin
and the contents build.gradle:
dependencies {
compileOnly 'org.projectlombok:lombok:+'
}
I have a custom compile task.
task compileSpeedTest(type: JavaCompile) {
classpath = files('build')
source = fileTree('src/test/java/speed')
destinationDir = file('bin')
}
Gradle doesn't try to download dependencies before its execution.
I cannot find anywhere a task name which does it to add it on list dependsOn.
Downloading java dependencies is possible, if you actually really need to download them into a folder.
Example:
apply plugin: 'java'
dependencies {
runtime group: 'com.netflix.exhibitor', name: 'exhibitor-standalone', version: '1.5.2'
runtime group: 'org.apache.zookeeper', name: 'zookeeper', version: '3.4.6'
}
repositories { mavenCentral() }
task getDeps(type: Copy) {
from sourceSets.main.runtimeClasspath
into 'runtime/'
}
Download the dependencies (and their dependencies) into the folder runtime when you execute gradle getDeps.
For Intellij go to View > Tool Windows > Gradle > Refresh All Projects (the blue circular arrows at the top of the Gradle window.
A slightly lighter task that doesn't unnecessarily copy files to a dir:
task downloadDependencies(type: Exec) {
configurations.testRuntime.files
commandLine 'echo', 'Downloaded all dependencies'
}
Updated for kotlin & gradle 6.2.0, with buildscript dependency resolution added:
fun Configuration.isDeprecated() = this is DeprecatableConfiguration && resolutionAlternatives != null
fun ConfigurationContainer.resolveAll() = this
.filter { it.isCanBeResolved && !it.isDeprecated() }
.forEach { it.resolve() }
tasks.register("downloadDependencies") {
doLast {
configurations.resolveAll()
buildscript.configurations.resolveAll()
}
}
I have found this answer https://stackoverflow.com/a/47107135/3067148 also very helpful:
gradle dependencies will list the dependencies and download them as a
side-effect.
This version builds on Robert Elliot's, but I'm not 100% sure of its efficacy.
// There are a few dependencies added by one of the Scala plugins that this cannot reach.
task downloadDependencies {
description "Pre-downloads *most* dependencies"
doLast {
configurations.getAsMap().each { name, config ->
println "Retrieving dependencies for $name"
try {
config.files
} catch (e) {
project.logger.info e.message // some cannot be resolved, silentlyish skip them
}
}
}
}
I tried putting it into configuration instead of action (by removing doLast) and it broke zinc. I worked around it, but the end result was the same with or without. So, I left it as an explicit state. It seems to work enough to reduce the dependencies that have to be downloaded later, but not eliminate them in my case. I think one of the Scala plugins adds dependencies later.
You should try this one :
task getDeps(type: Copy) {
from configurations.runtime
into 'runtime/'
}
I was was looking for it some time ago when working on a project in which we had to download all dependencies into current working directory at some point in our provisioning script. I guess you're trying to achieve something similar.
Building on top of Robert Elliot's answer. For whatever reason, if one is interested in downloading the dependencies to Gradle cache then copying to a local repository like maven's (by default ~/.m2/repository):
task downloadDependencies(type: Exec) {
configurations.implementation.files + configurations.runtimeOnly.files
finalizedBy "cacheToMavenLocal"
commandLine "echo", "Downloaded all dependencies and copied to mavenLocal"
}
task cacheToMavenLocal(type: Copy) {
from new File(gradle.gradleUserHomeDir, "caches/modules-2/files-2.1")
into repositories.mavenLocal().url
eachFile {
List<String> parts = it.path.split("/")
it.path = [parts[0].replace(".","/"), parts[1], parts[2], parts[4]].join("/")
}
includeEmptyDirs false
}
The task cacheToMavenLocal was copied and adapted from #Adrodoc55's answer on Gradle forum.
It is hard to figure out exactly what you are trying to do from the question. I'll take a guess and say that you want to add an extra compile task in addition to those provided out of the box by the java plugin.
The easiest way to do this is probably to specify a new sourceSet called 'speedTest'. This will generate a configuration called 'speedTest' which you can use to specify your dependencies within a dependencies block. It will also generate a task called compileSpeedTestJava for you.
For an example, take a look at defining new source sets in the Java plugin documentation
In general it seems that you have some incorrect assumptions about how dependency management works with Gradle. I would echo the advice of the others to read the 'Dependency Management' chapters of the user guide again :)
There is no task to download dependencies; they are downloaded on demand. To learn how to manage dependencies with Gradle, see "Chapter 8. Dependency Management Basics" in the Gradle User Guide.
Currently, our gradle setup is geared to publish to certain maven repositories when a build is done. For a particular customer, I need to zip up the jars, license files, pom.xml, and ivy.xml files, and send it all in a zip. To do this, I just need to define an alternate location to publish it to. All the documentation on the gradle site seems aimed at writing one set of publishing rules, not an alternative set.
I was hoping to simply write a different task which would focus on building this customer-specific zip file. So far, I have it collecting all the jars (which includes source and runnable code) along with the license and notice file. But I haven't cracked the nut on defining a local ivy repository and a local maven repository that is only part of this alt task.
task alt {
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' }
subprojects.each{project ->
if (project.hasProperty('sourceJar')) {
evaluationDependsOn(project.name)
}
}
File altDir = mkdir("$buildDir/alt")
subprojects.each { project ->
if (project.hasProperty('sourceJar')) {
// Extra the module name from the path of the sub-project
String submodule = project.projectDir.absolutePath.split(File.separator).last()
File subfolder = mkdir(altDir.absolutePath + "/${project.group}/${group}.${submodule}/$version")
project.tasks.withType(Jar).each {archiveTask ->
copy {
from archiveTask.archivePath
from("$rootDir") {
include 'license.txt'
include 'notice.txt'
}
into subfolder
}
}
}
}
}
Here's the gradle docs that tells you how to generate the pom. Also if you are looking to install that file to your local repository you could use the mechanism described in this blog entry . Essentially all you have to do
configure(install.repositories.mavenInstaller) {
pom.project {
version '1.0'
artifactId 'your.artifact.id'
groupId 'your.group.id'
}
}
It doesn't look like it possible at the moment to generate the ivy.xml through gradle, but once you have your pom file you could use ivy itself to generate the ivy file described here.
Section 64.5 of http://www.gradle.org/docs/current/userguide/publishing_ivy.html covers "Generating the Ivy module descriptor file without publishing".
The documentation is a little broken (eg inconsistent naming conventions). The following works for me:
apply plugin: 'ivy-publish'
publishing {
publications {
aoeu(IvyPublication)
}
}
This will generate a target generateDescriptorFileForAoeuPublication.