Gradle - paths in multi-project builds - gradle

I have a multi-project gradle project with following directory structure:
+ project_root
+ module1
+ src
build.gradle
+ module2
+ src
build.gradle
+ web
..
build.gradle
settings.gradle
In module1/build.gradle among other things I have specified:
compileKotlin2Js.kotlinOptions {
outputFile = "web/script.js"
}
It is a special Kotlin JS setting that specifies output file path of compiled JS file.
Now my problem is, that when I build the whole project (project_root/build.gradle) the file ends up in the right directory (project_root/web), but when I accidentally run build on the module alone the file is saved in module directory (project_root/module1/web).
How can I fix paths in my build scripts, so file output will be saved in exactly the same directory no matter which build script I run (without specifying full path, I want a relative path)?

I don't know what Gradle plugin requires the path parameter in your code example, but all regular (non-3rd-party) Gradle plugins evaluate path parameters via Project.files(Object...) to avoid different locations when calling Gradle from various working directories.
I would suggest to use the above method (or its single file version Project.file(Object)) as well. You can even omit the project part, because the build.gradle file gets executed in the project scope:
compileKotlin2Js.kotlinOptions {
outputFile = file('web/script.js')
}
This will always evaluate the path relative to the project directory of the project your build.gradle belongs to. To evaluate a file relative to the project directory of the root project, use rootProject.files(Object...), for a path relative to the project directory of a subproject or any project in the build, use project(':path:to:project').files(Object...).

Related

Gradle: Copy one specific file from main project directory into subproject/build/libs

Searching in vain for examples on this humble task, none worked, I need to learn how to use gradle to copy one specific file from the main directory of a gradle project (containing subprojects) and into the /build/libs folder of one of the subprojects. Structure is this:
mainProject folder
file.txt
Subproject folder
build folder
libs folder
(I want to copy file.txt here)
This copy process shall be in the build.gradle (for the Subproject) file. I am using Android Studio and the subproject is a pure java application.
Thanks for any help.
You need to implement a custom task of type Copy to copy the file to the target directory. To access the file in the root project, you may use the rootProject property of the subproject.
task copyFileFromRootProject(type: Copy) {
from "${rootProject.projectDir}/file.txt"
into 'build/libs'
}

Add local Gradle source module by absolute path

I want to add a subproject to my Gradle project. The project is located somewhere on my hard disk drive, for example:
/A/Path/to/a/ProjectA
/Another/Path/to/another/ProjectB
What I want to achieve is to use ProjectB as a source module within Project A. However, all my attempts to do this so far - either by adding include /Another/Path/to/another/ProjectB or by adding include ':ProjectB'; project(':ProjectB').projectDir = ... in settings.gradle - just failed. Apparently, Gradle is not able to find the project.
How can I add ProjectB as a dependency without moving it from it's location?
Using Gradle 3.4.1, the following works for me (full example here):
include 'app', 'common'
def MY_PATH = '/Users/johndoe/foo'
assert new File("$MY_PATH/random/path/common").exists()
project(':common').projectDir = new File("$MY_PATH/random/path/common")
Thanks for your responses.
Turns out I've made several mistakes:
Adding the project to the built was dependent on the value of an environment variable. I replaced that with a property within gradle.properties.
I tested this by running the settings.gradle usind IntelliJ. I mistakingly expected this to work, but it didn't
I did not add the project as a dependency to the build.gradle file of the parent project.
It works now. Thank you all again!

Gradle: getting the root project directory path when starting with a custom build file

The structure of my Gradle project is the following:
Project
├── app
└── build.gradle
├── foo
└── bar.txt
·
·
·
└── build.gradle
Normally to get the absolute path of the foo folder I can just simply do new File('foo').getAbsolutePath() in the root build.gradle file.
But this unfortunately doesn't work if you run the gradle script from outside the project directory, for example doing something like this:
$ trunk/gradlew -b trunk/build.gradle tasks
With the previous command gradle is looking for the foo directory in the parent of the Project, because I started the script from there.
Is there a way to get the absolute path of the Project where the build.gradle is, even if you start your script from another directory? Or is there any other way to get a reference of a directory in the same folder where the script is?
I've tried also with getClass().protectionDomain.codeSource.location.path but it is returning the path to the gradle cache directory.
I got past this problem by ensuring Java userDir was set to the project directory (i.e. project.projectDir) at the top of my build.gradle file, as follows:
System.setProperty( "user.dir", project.projectDir.toString() )
println " project dir: "+ System.getProperty("user.dir");
This can be checked by executing a separate (Groovy) code file such as:
println "User Dir: ${System.getProperty( 'user.dir' )}"
You can output the Gradle project values before and after using these statements.
println "Root project: ${project.rootProject}";
println " rootDir: ${project.rootDir}"
println " projectDir: ${project.projectDir}";
println " project dir: ${System.getProperty("user.dir")}";
If you have sub-projects, projectDir is not the same as rootDir.
This hasn't fixed my actual problem but it has ensured that I'm opening the correct file (relative to the location of build.gradle.
new File('foo') by definition (look at its JavaDoc) makes a path relative to the current working directory, so depends on where you call the app from. If you want a path relative to the project folder, use project.file('foo'), or as project is the default for resolving the method just file('foo') and you get the relative path resolved against the project directory, not the working directory. So use file('foo').absolutePath and you will be fine.
In the build.gradle file just use projectDir to get the absolute path of the build.gradle file. from there you can navigate your project's files. read this for more info:
https://www.tutorialspoint.com/gradle/gradle_build_script.htm
I was using new File() and path to get the source directory into the gradle file but in Macbook with M1 Chip it's not working, let me share the code for previous and new version:
Older code:
new File("app/src/")
Updated code:
new File(project.projectDir.getAbsolutePath() + "/src/")

How do I prevent Gradle from building a non-project directory?

In the Gradle samples (included with version 2.2.1) there is a java/multiproject project.
The settings.gradle file defines the following projects:
include "shared", "api", "services:webservice", "services:shared"
Note that services is not itself a project, merely a directory which contains the webservice and shared projects.
When I run the command gradle build from the root directory, I notice that after gradle successfully builds it creates inside the /services directory a /build directory containing /lib and a /tmp directories.
Inside of /services/build/lib is a jar: services-1.0.jar which contains very little; specifically just a META-INF/MANIFEST.MF file containing:
Manifest-Version: 1.0
provider: gradle
So what is causing Gradle to build a jar for this non-project? And how can I prevent this behavior in my similarly structured multiproject project?
/services isn't a project, I don't want to create anything inside /build folder at all. Yes I could just delete it, but I would like to avoid the unnecessary work of building this jar/running any tasks on this non-project in the first place.
To be honest I've no reasonable idea why gradle builds this folder. I guess that because it's a kind of a transient folder. However it can be excluded by adding the following piece of code to main build.gradle script:
project(':services').jar { onlyIf { false } }
Desired effect (services.jar elimination) can be also obtained with the following settings.gradle content:
include "shared", "api", "services/webservice", "services/shared"
File instead of project paths are included.
My guess would be that this is a combination of the next 2 gradle rules:
When you're including subprojects in the build.settings file using the include keyword according to Gradle Documentation here:
the inclusion of the path 'services:hotels:api' will result in
creating 3 projects: 'services', 'services:hotels' and
'services:hotels:api'.
In simple words, this means that the inclusion of services::webservice will also build the services project
The bulid.gradle file in your root that applies the 'java' plugin. According to Gradle Documentation here every configuration defined in the root.gradle takes effect for all sub projects. This means that it will also hold as the default configuration for the services project. As the 'java' plugin was applied a jar will be created, but as there is no src/main folder under the services directory nothing will be compiled and the jar will include only a META-INF/MANIFEST.MF file.

How to copy properties from a parent project in gradle

I'm trying to share one messages.properties (of each language) among multiple subprojects in gradle, one of which is a war and the rest are jars. My directory structure looks like this:
Top Level Project
+ Project War/
+ Project Jar/
+ Project Jar/
...
+ common/resources/properties files
+ build.gradle
I am trying to do something like this in the main project level build.gradle (which doesn't look to be working for me):
task copyProperties(type: Copy) {
description = 'Copies the messages.properties to individual projects.'
from relativePath('./common/resources')
into output.resourceDir
include '*.properties'
}
I'm calling this from a subproject's compileJava.dependsOn and I don't see any errors, but the copy doesn't happen.
You can inject a copy task like this into each sub-project. Instead of specifying the 'from' as a relative path, base it on $rootDir.
Each copy task should then be called as needed when building each sub-project.

Resources