This message was deleted.
# community-support
s
This message was deleted.
g
I guess, the Daemon process switches directory whens spawned and then caches this directory as
user.dir
? Is this a known problem?
c
it’s recommended to use
file("dummy.txt")
to allow Gradle to handle the creation of the file, to avoid situations like this.
g
Older versions seem to be consistent: They show the Daemon home as starting point . The behaviour has changed between 6.9.2 and 7.6.3 …
it’s recommended to use
file("dummy.txt")
to allow Gradle to handle the creation of the file, to avoid situations like this.
Thanks, this seems to work better 🙂
c
Good to hear! It’s buried somewhere in the docs:
Never use
new File(relative path)
unless passed to
file()
or
files()
or
from()
or other methods being defined in terms of
file()
or
files()
. 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.
🙂 1
v
Using the
File
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.
🙂 1
It is like when you are having an application with structure like
Copy code
|
|-> 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.
g
Thanks for the explanation, @Vampire. I am aware that Gradle is much like normal Groovy but not to any extent. I was not using Gradle frequently for about 10 years and forgot all of those details (and never have been an expert on Gradle before). Have to get back into it step by step. As a developer I am fully aware that you always have to consider your directory structure in the respective context for use cases like this. Thing for me is, like with Perl TIMTOWTDI: There is more than one way to do it. You find a lot of stuff on the Internet that describe certain scenarios and aspects for Gradle. But each concept requires a deep understanding of the underlying tool and its implementation. So its not just stupidly applying recipes. And, in some cases you cannot simply apply concepts from your developer background like opening a File as I would do it in Groovy or Java. Sometimes you only learn by running into the caveats and specialties of your tool by your own faults. Additionally things have changed over time, some truth from Gradle 1, 2. 3 has evolved to better practices with Gradle 6, 7, 8 … My journey into the
file
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.
v
I'm not sure whether your got what I tried to say. The file problematic is not Gradle specific and not Java version specific. It is the same problem on practically any program running on the JVM, be it written in Java, Groovy, Kotlin, Scala, or whatever, and independent of Gradle being involved in any way. That it surfaced for you in Gradle when using a different Java version is just a big coincidence.
g
If I am using File operations I usually consider in which directory my process currently is when using relative paths. As long as I do not change it, this is no problem (and I seldomly change it, except perhaps in Shell scripts where programming then is easier in some cases). The JVM
absolutePath
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)?
v
As you said the directory cannot change, it could never provide this behavior, even if it would stick to the posix contract or wanted to. Daemons are reused if they are sufficient, no matter from which directory you run which build. Without this, the daemon would be much less useful. It could be - but this is just a guess - that Gradle tries to change the current working dir of the daemon to fit the build by manipulating private state like it also tries to set environment variables as far as I remember. And maybe this worked with the old JVM you used, but not with the new one. But this was a bad idea from the start and as far as I know there are also discussions to just always have the daemon dir as working dir.
g
So I seem to have found a known bug 😉 What’s interesting to me are some of the comments, e.g., • Different behaviour of JDK 11 and beyond was already known • Warnings for
new File
constructor calls should be raised (and that it’s not so easy)