63

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.

Roberto Leinardi
  • 10,641
  • 6
  • 65
  • 69

4 Answers4

70

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.

will
  • 4,799
  • 8
  • 54
  • 90
  • Literally at the top of your `build.gradle`? When I try that I get `only buildscript {} and other plugins {} script blocks are allowed before plugins {} blocks, no other statements are allowed`. – David Moles Oct 01 '19 at 22:29
  • 1
    Yes, correct-- After the plugins and buildscript and other mandatory bits that must come first. – will Oct 03 '19 at 02:04
  • It is not, it refers to the gradle daemon /Users/my.User/gradle-7.3/daemon/7.3 – htafoya Jan 02 '23 at 22:34
50

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.

Vampire
  • 35,631
  • 4
  • 76
  • 102
  • 22
    Hey thanks! That works like charm! And I just realise that I can get the path to the current project directory via `rootProject.projectDir`. But in my case your solution is easier and cleaner. – Roberto Leinardi Jan 13 '17 at 13:27
  • With Netbeans at least the `File('foo')` is NOT always the place the gradle.build file lives. I thought I had a bug until I discovered my foo was in the Netbeans `userDir` – will Mar 12 '17 at 11:29
  • @will you have it all lowercase, the "`file`"? – Vampire Mar 12 '17 at 17:14
  • @Vampire ... Thanks, yes I appreciate the distinction. However, I need the "`new File( 'Foo' )`" construct because I'm building around existing test scripts and programs in Java and Groovy that rely on the project directory being the '_current working directory_' at least when everything commences. Setting Java's `System.userDir` value is the standard JVM way to achieve that I believe. Always open to improvements /alternatives if they are more robust. – will Mar 13 '17 at 10:55
  • @will well that is a different use-case then OP requested. Assuming you use `Exec` or `JavaExec` to call your existing scripts and programs, you can also specify the working directory for those external processes individually to be the project directory. Your solution also only partly works if you have a multi-project build where the tools need different working directories according to the respective project. If you only have one project and your scripts and tools are evaluated in-line in the Gradle process, setting the `user.dir` probably is the best solution. – Vampire Mar 14 '17 at 12:54
  • Yes, I think so. The context is a Gradle build begun from Netbeans. Apparently this uses a socket to a Gradle daemon so it just tells the daemon what to run. There is apparently no `exec()` or `fork()` call. One may set Java parameters like `-Duser.dir`; but that means hard-coding a string to your (non source controlled) user profile settings (or something). – will Mar 14 '17 at 21:32
  • @will not really. You can set the JVM arguments with which the daemon should be started and only daemons that have these arguments set are reused, otherwise a new daemon is started. – Vampire Mar 15 '17 at 08:09
  • project.file(....) works for me thanks – Amaury Ricardo Oct 13 '21 at 03:02
  • how to reference the project object from a Kotlin object? – htafoya Jan 02 '23 at 22:55
  • The same? Or actually by now I'd usually use `layout.projectDirectory.file("foo")` – Vampire Apr 05 '23 at 18:20
12

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

Ali Abazari
  • 429
  • 4
  • 20
0

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/")
SANAT
  • 8,489
  • 55
  • 66
  • Not incorrect but it will only work for the example project, if the gradle script was run from other directory this will fail. – htafoya Jan 02 '23 at 22:29
  • @htafoya It is regarding the path you are providing, My production app code was not pointing to the correct location when using the M1 chip. So "app/src/" was not working. By using the above updated code I am able to point to the "app". So you need to provide the correct path when you are using the new File() in build.gradle. – SANAT Jan 03 '23 at 12:05