What Is The Current Path In A Gradle Multi-Module Project? - gradle

I have a multi-module project that ends up outputting a directory called logs at the root of each module - including the root project.
I have extended the clean task like this but it only deletes the logs dir in the root project and not in the sub-modules.
allprojects {
clean {
delete 'logs'
}
}
I thought that this meant "add the clean task to all the projects and delete the logs dir in each project".
It seems like even though the delete is being called in each sub-module, it is using the root directory as the relative path to find the logs dir.
However, if I change it to the following it deletes the directory in each module.
allprojects {
clean {
delete file('./logs')
}
}
This looks functionally identical to me since if the path of each clean task is relative to the root then file('./logs') should also be relative to the root.
However, the file object seems to be relative to the module dir and not the root.
Why does the file object resolve correctly but the string passed to the clean task does not?
How are paths resolved for each module when running a multi-module project?
Is there a better way to do this than using a file object?

Could not replicate - gradle 6.7 / jdk 11
Dir structure
.
|____a
| |____b
| |____c
common delete task
allprojects {
apply plugin: 'java'
task deleteLogs(type: Delete) {
delete 'logs'
}
clean {
delete 'logs'
}
task printcd {
println 'project : ' + project.name
println 'rootDir : ' + project.rootDir
println 'prjDir : ' + project.projectDir
println '-------------'
println 'file : ' + file('logs').absolutePath
println 'file ./ : ' + file('./logs').absolutePath
println '-------------'
print 'deletePath : '
project.tasks.getByName('deleteLogs').targetFiles.each {file -> println file.absolutePath }
println '-------------'
print 'clean : '
project.tasks.getByName('clean').targetFiles.each {file -> print file.absolutePath + " , " }
println ''
println '============='
}
repositories {
mavenCentral()
}
}
output
-bash$ gradle printcd
> Configure project :
project : a
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a
-------------
file : /Users/xyz/a/logs
file ./ : /Users/xyz/a/logs
-------------
deletePath : /Users/xyz/a/logs
-------------
clean : /Users/xyz/a/build , /Users/xyz/a/logs ,
=============
project : b
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a/b
-------------
file : /Users/xyz/a/b/logs
file ./ : /Users/xyz/a/b/logs
-------------
deletePath : /Users/xyz/a/b/logs
-------------
clean : /Users/xyz/a/b/build , /Users/xyz/a/b/logs ,
=============
project : c
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a/c
-------------
file : /Users/xyz/a/c/logs
file ./ : /Users/xyz/a/c/logs
-------------
deletePath : /Users/xyz/a/c/logs
-------------
clean : /Users/xyz/a/c/build , /Users/xyz/a/c/logs ,
=============
BUILD SUCCESSFUL in 578ms
-bash$ gradle --version
------------------------------------------------------------
Gradle 6.7
------------------------------------------------------------
JVM: 11.0.8 (Oracle Corporation 11.0.8+10-LTS)

Related

How to delete all "target" directories from gradle (after converting from maven)

I have a huge maven project, lot of people are using it. I'm currently working on converting it to gradle. One of the last steps will be that I merge the gradle files, and delete the pom.xml files. But I'd like to add a gradle task to clean the maven target directories (of all the sub-projects). In shell I would do something like:
find . -type d -name target -exec rm -rf "{}" \;
But I prefer this to be a gradle task. How do I add it? This is what I tried but it doesn't delete anything:
task cleanMaven(type: Delete) {
delete fileTree('.').matching { include '**/target/**' }
}
below will handle all modules of root project and prints true if a target dir existed and is deleted
allprojects {
task mvnClean {
doFirst {
def targetPath = project.projectDir.toString() + '/target'
println "target dir exists: ${Files.deleteIfExists(Paths.get(targetPath))}"
}
}
}
Based on #PrasadU's answer, but this also deletes all the contents of the target/ directories:
allprojects {
task mvnClean {
doFirst {
def targetPath = project.projectDir.toString() + '/target'
project.delete(files("${targetPath}"))
}
}
}

Gradle: find and build all projects in folder

I have a folder with a lot of projects inside it (too much to manually write build files for them)
The projects are mostly in a flat layout:
root
-project 1
-project 2
-project 3
-project 4
-project 5
( -project 5.1)
But can be nested as shown above, and I need to account for this.
Ideally the following should happen:
I can run user#user:/root gradle build and every project in the directory shoudl be built as long as it contains a gradle build file
if a build fails just continue with the next one
How can I make this possible ?
How about this one-liner (not tested):
find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && gradle build || true" \;
Or, more verbose:
dirs=($(find . -type d))
for dir in "${dirs[#]}"; do
cd "$dir"
gradle build || true
done
I came up with a working solution:
def flist = []
// change to you workspace name
new File('./Workspace').eachDir {
//blacklist any folders you want
if (it.name !='.gradle' && it.name != 'master' && it.name!= 'Build-All') {
flist << it.name
}
}
// build task objects
flist.each { folder ->
task "${folder}"(type: GradleBuild) {
buildFile = "./Workspace/"+ folder + "/build.gradle"
dir = './' + folder
tasks = ['build']
}
}
// create super task
task (all, dependsOn: flist) {
}
You need to invoke it as such in the root directory: gradle :all --continue this has the benefit that any failing project builds will not halt the other builds.
Another bonus is that gradle gives a neat report about all failing builds.

Gradle - How to execute something after a copy task completed the operation?

I have a task:
task myCopy(type: Copy) {
from 'from.txt'
into 'into.txt'
doLast {
//Read write 'into.txt'
}
}
It always print a FileNotFoundException, I find out that doLast block is executed before the copy operation has complete, so how can I read (or write) with into.file when my copy operation is completed?
Here you are not using Copy task in a proper way: the "into" property is the target directory where files will be copied, not the target file name.
When executing your script you should have a directory "input.txt" created at the root directory of your project, and the file "from.txt" copied into it , which is not what you expect, and I guess this is the cause for you FileNotFoundException .
If you want to copy/rename file, you should use the 'rename' method from CopyTask, described here : https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:rename(java.lang.String,%20java.lang.String)
Exemple:
task myCopy(type: Copy) {
from './source-file.txt'
into './output-dir'
rename ( 'source-file.txt', 'input.txt')
doLast{
println "Is file already copied when executing doLast ? ==> "+ project.file("./output-dir/input.txt").exists()
}
}
This should output:
$ gradle myCopy
> Task :myCopy
Is file already copied when executing doLast ? ==> true

How to make a Gradle project versioneye-friendly?

I have a Gradle project that I want to import to Versioneye to check if my dependencies are up to date, but it's a complex config file (with external variables etc.) and Versioneye does not manage to handle the dependencies properly.
I don't want to install the Versioneye gradle plugin.
How can I export the dependencies from my repo to Versioneye?
You can list all the dependencies gradle app:dependencies.
With a bit of string manipulation, you can export a "clean" dependencies file and manually upload it to Versioneye.
#!/bin/bash
OUT_DIR='versioneye'
OUT_FILE="${OUT_DIR}/build.gradle"
mkdir -p "${OUT_DIR}"
touch "${OUT_FILE}"
# copy your maven repositories closure below from build.gradle
tee "${OUT_FILE}" <<EOF >/dev/null
allprojects {
repositories {
maven {
url 'https://maven.google.com/maven-google-remote'
}
maven {
url "https://jitpack.io"
}
}
}
EOF
echo 'dependencies {' >> "${OUT_FILE}"
./gradlew app:dependencies | grep '^+---' | sed 's|+--- |compile "|' | sed 's| (\*)||g' | sed 's|$|"|' | sort -u >> "${OUT_FILE}"
echo '}' >> "${OUT_FILE}"
cat "${OUT_FILE}"
cd "${OUT_DIR}"
start .
cd -
echo 'Now, open versioneye.com and manually upload the genreated build.gradle file.'
This will generate a file that looks like this:
allprojects {
repositories {
maven {
url 'https://maven.google.com/maven-google-remote'
}
maven {
url "https://jitpack.io"
}
...
}
}
dependencies {
compile "com.android.support.test.espresso:espresso-contrib:2.2.2"
compile "com.android.support.test.espresso:espresso-core:2.2.2"
compile "com.android.support.test.espresso:espresso-intents:2.2.2"
compile "com.facebook.android:facebook-android-sdk:4.17.0"
compile "com.facebook.fresco:fresco:1.5.0"
compile "com.facebook.fresco:imagepipeline-okhttp3:1.5.0"
...
}
This file can be imported to Versioneye with a file upload and will be processed correctly.

How gradle interprets a command run at parent level

Let's say there are 3 sub projects: sub1, sub2, and sub3. They all have task uploadArchives. If we run gradle uploadArchives, how it is cascaded to sub projects?
Assume your project layout as bellow
gradle-tasks
|- sub1
|- sub2
|- sub3
settings.gradle as below:
include 'sub1', 'sub2', 'sub3'
rootProject.name = 'gradle-tasks'
And your build.gradle is like this:
allprojects {
task uploadArchives {
doLast { task ->
println "I'm $task.project.name"
}
}
}
Then when you execute ./gradlew uploadArchives in root, you will have
$ ./gradlew uploadArchives
> Task :uploadArchives
I'm gradle-tasks
> Task :sub1:uploadArchives
I'm sub1
> Task :sub2:uploadArchives
I'm sub2
> Task :sub3:uploadArchives
I'm sub3
Ref: https://docs.gradle.org/current/userguide/multi_project_builds.html

Resources