Slackbot
02/01/2024, 3:08 PMGerd Aschemann
02/01/2024, 3:11 PMuser.dir
?
Is this a known problem?Chris Lee
02/01/2024, 3:23 PMfile("dummy.txt")
to allow Gradle to handle the creation of the file, to avoid situations like this.Gerd Aschemann
02/01/2024, 3:24 PMGerd Aschemann
02/01/2024, 3:25 PMit’s recommended to useThanks, this seems to work better 🙂to allow Gradle to handle the creation of the file, to avoid situations like this.file("dummy.txt")
Chris Lee
02/01/2024, 3:25 PMNever useunless passed tonew File(relative path)
orfile()
orfiles()
or other methods being defined in terms offrom()
orfile()
. Otherwise this creates a path relative to the current working directory (CWD). Gradle can make no guarantees about the location of the CWD, which means builds that rely on it may break at any time.files()
Vampire
02/01/2024, 11:06 PMFile
constructor with a relative path is majorly wrong thing to do in 99% of the cases where you are tempted to do it.
The virtually only situation where it is appropriate is, if the relative path is a path that was given by the user on the commandline when calling your program, as then it is usually the right thing to be relative to the current working directory.
The working directory often is the project directory, but not always as you have seen. Sometimes it is the daemon directory. Sometimes it even changes. Sometimes it is the installation directory of the IDE. ....
All situations I observed already, with various versions of Gradle and Java.Vampire
02/01/2024, 11:10 PM|
|-> app.bat / app
|-> lib
||-> app.jar
|-> conf
||-> conf/config
And then try to read new File("conf/config")
in your application.
This works exactly then when the user calls the start script from that root folder.
But if the user is for example one directory up and calls app/app.bat
, this breaks already.
Instead you need to determine the installation directory in the start script and give it to the application somehow, then resolve the path relative to that.Gerd Aschemann
02/02/2024, 5:15 AMfile
problem yesterday started with some strange behaviour when testing my build with different Java versions. In the beginning I was not even aware that the first occurrence of the exception was due to my switch from Java 8 to 11 (or, in fact by switching the JDK from 8 to 11 by SDKman for another project). Things which worked some days ago, caused problems on my machine while still working on GitHub. Then I debugged into Gradle. The error message by no way led me to a problem with my file access implementation. Hence, I could not figure by myself that there is some special recommendation for Gradle how to do it. I didn’t get an idea how to search the docs or other sources about it. Now that I have understood the problem, its easy to figure the respective descriptions.
I am not blaming Gradle: as a developer I could not imagine a way to detect the problem and make its cause transparent. Except, perhaps, for heavy sandboxing like Jenkins does with its Groovy DSL - but I wouldn’t want this for other reasons.
Thanks for helping me climb the (still steep) learning curve.Vampire
02/03/2024, 3:46 AMGerd Aschemann
02/03/2024, 8:21 AMabsolutePath
implementation goes back to the user.dir
System property, at least I thought this. Now I learned that the JVM caches user.dir
in jdk.internal.util.StaticProperty
which seems also to be OK as there is no Java API to make the (Posix) chdir
system call. So, all of this is no problem: You cannot change the process start directory and all files with relative path are relative to this initial directory.
I have no idea why the JVM runs with the Daemon home as user.dir
in some JVMs? I have not traced it down. And I do not know wether this happens with other JVM-based languages or frameworks as well.
However, I personally consider it an error. As a Unix/Posix user I expect to have a child process inherit the current directory from it’s parent. So when I spawn gradle
(or gradlew
) from my Shell, it should run with the very same current directory. This is called consistent behaviour of an API (in this context the Posix process API contract). If the JVM (or Gradle) changes the directory, it violates this contract. Perhaps the JVM never promised to keep the Posix process API contract and can change to arbitrary directories before executing some (user) code. I do not know. If it does, it is at least somehow unexpected.
A quick search does not reveal any explicit specification for the JVM behaviour. Nevertheless, Java APIs like ProcessBuilder at least promise to start sub processes in the (original) working directory of the process. This has not changed between Java 8 and Java 11.
Nevertheless, I can see a different user.dir
in the Gradle daemon process in JDK 8 and JDK 11. So, the question remains where this comes from (and if it is a good thing, assuming that users expect consistent behaviour of software)?Vampire
02/03/2024, 9:47 AMVampire
02/03/2024, 9:54 AMGerd Aschemann
02/05/2024, 6:21 AMnew File
constructor calls should be raised (and that it’s not so easy)