How to download dependencies in gradle - gradle

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.

Related

Use build.finalizedBy on each subproject with Gradle kotlin

I want to run a specific task after EVERY build of my subprojects. I can go into each of my subprojects build.gradle.kts file and add the following
tasks.build {
finalizedBy("afterbuildtask")
}
However, this should be possible to do in my root project build.gradle.kts file right? I tried it by doing the following:
subprojects {
this.tasks.findByName("build")?.dependsOn("afterbuildtask")
}
But nothing happens. How can I achieve this?
You can't programatically execute tasks from other tasks in newer versions of Gradle.
Instead, you are supposed to declare task dependencies and Gradle will ensure they get executed in the correct order. But I think it's not what you want
Alternatively, you could move your logic into the doLast block in the build task. eg:
build {
doLast {
println("Copying...")
copy {
from 'source'
into 'target'
include '*.war'
}
println("completed!")
}
}
good coding! ¯_(ツ)_/¯

How can I generate an entire gradle subproject and have it as a dependency in another project?

So let's say I have the following settings.gradle:
include 'math-server'
project(':math-server').projectDir = file('math/server')
include 'math-client-gen'
project(':math-client-gen').projectDir = file('math/client')
include 'ai'
Now I'd like to not commit the any of the files in math-client-gen (including the build.gradle) since those are generated by a build job in math-server:
// math/server/build.gradle
task generateClient(type:Exec) {
workingDir '.'
inputs.dir('./app')
inputs.dir('.')
outputs.dir('../client')
commandLine './client-generator/generate.sh'
}
The generate.sh leverages the openapi client generator for kotlin.
Now the ai project relies on the math-client-gen:
// ai/build.gradle
dependencies {
compile project(':math-client-gen')
}
Now I have currently found two suboptimal ways to make this work.
Option 1 is to run ./gradlew :math-server:generateClient before I'm able to run ./gradlew :ai:build. This sucks, since you cannot build ai on its own anymore.
Option 2 is to commit the files, which of course also isn't the way it should be.
I'm sure there is a better way to do it with gradle, but I just didn't manage to find it yet. As a compromise, I'd be willing to commit the generated math-client-gen/build.gradle if it doesn't work without that.
What's the best solution to this problem?
Note: I also saw something like:
implementation files(layout.buildDirectory.dir('classes')) {
builtBy 'compile'
}
in the docs, that looks promising, but i'd like to have it for an entire subproject and not just some source files if possible.
// ai/build.gradle
afterEvaluate {
tasks.build.dependsOn(project(":math-client").tasks["generateClient"])
}
To automate your first option.
I ended up committing the build.gradle of the math-client-gen and have this line there:
// math/client/build.gradle
compileKotlin {
dependsOn ':math-server:buildMathClient'
}
This ensures that the client is always generated when this project is listed as a dependency somewhere.
Then you can simply add the math-client-gen as a dependency in other projects, no additional steps required:
// ai/build.gradle
dependencies {
compile project(':math-client-gen')
}

Gradle - Make existing android project a child of other project and run "gradlew tasks"

Part 1.
I have an existing Android project which is built with gradle.
settings.gradle looks like this:
include ':android', ':androidTest', ':androidTestApp'
build.gradle looks like this:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.4'
}
task customClean(dependsOn: [':android:clean', ':androidTest:clean', ':androidTestApp:clean']) {
}
allprojects {
repositories {
mavenCentral()
mavenLocal()
}
}
What I need to do is a create a project that is a parent of this android project and runs this android project tasks. I add to settings.gradle of new root project only include 'android-sdk:android'which is all I need for now. And everything works fine, I can run tasks of android project like this gradlew androidBuild:
task androidBuild(dependsOn: 'android-sdk:android:assemble') << {
group unitySdkGroupName
}
Problems arise when I run gradlew tasks on the new root projects. I get
Caused by: org.gradle.api.UnknownTaskException: Task with path ':android:clean' not found in project ':android-sdk'.
I know I can fix this by removing colons like this, but I want to somehow make tasks command work without changing android project if possible.
task customClean(dependsOn: ['android:clean', 'androidTest:clean', 'androidTestApp:clean']) {
}
Part 2.
When I add to settings.gradle of root project other nested projects
include 'android-sdk:androidTest'
include 'android-sdk:androidTestApp'
I get errors here in dependencies sections of child projects that are dependent on android module (this is androidTest module):
dependencies {
compile project(path: ":android")
compile 'com.google.android.gms:play-services:7.3.0'
}
and getting this when I refresh projects (again seems like relative paths issue):
Error:(30, 0) Project with path ':android' could not be found in project ':android-sdk:androidTest'.
So the question is - can I make gradlew tasks command work properly without modifying the underlying android project and how can it be done the most elegant way?
Unfortunately: no. Nested multiproject builds are not possible. I should add yet, but although intention to support them has been shown, there is absolutely no indication of when this feature can be expected.
See https://discuss.gradle.org/t/nested-multimodule-builds-with-a-flat-directory-layout/7509/13
I could not even find a feature request at https://discuss.gradle.org/c/bugs

Delombok using Gradle

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:+'
}

how to override a task making it depend on one of mine in gradle

I tried following the gradle manual with their example like this but copyJars is not run at all before the eclipse task. (the eclipse task comes from the eclipse plugin)
task('copyJars') {
ext.collection = files { genLibDir.listFiles() }
delete ext.collection
copy { from configurations.compile into genLibDir }
copy { from fixedLibDir into genLibDir }
}
eclipse.dependsOn = copyJars
task('setupAll', dependsOn: 'eclipse') {
description = 'Update jars from remote repositories and then fix eclipse classpath for stbldfiles project'
}
There are some problems with this build script:
eclipse doesn't refer to the task but to the equally named model object. (Don't you get an exception for eclipse.dependsOn?)
Task copyJars does its work in the configuration phase rather than the execution phase (i.e for every build, even if the task isn't executed)
To fix that, use tasks.eclipse.dependsOn(copyJars) and task copyJars << { ... }.
Another question is if there isn't a simpler way than copying things around with copyJars and fixing up the Eclipse class path after the fact, but I'd need more information to be able to tell.

Resources