-
-
Notifications
You must be signed in to change notification settings - Fork 358
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
fix: lookup absolute path to maven executable #4298
Conversation
@slarse @MartinWitt Qodana tells what the error is, but I am not sure where to look at it. What is the source position of the error? Can we figure that out? |
There was an update to qodana, and we had a solution planed. I pushed the (hopefully) fix to your branch as a temporary solution. I hope to create a PR this weekend fixing this with a GitHub action created by @SirYwell |
Qodana doesn't like the return of null instead of throwing an exception. Returning null instead of a String seems wrong. Maybe add an exception instead of null? |
if (mvnHome == null) { | ||
throw new SpoonException("M2_HOME must be initialized to use this MavenLauncher constructor."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer needed because guessMavenHome
throws an exception if it does not return a string.
That shouldn't be the case because Opening this PR for review as I have tested this patch in Sorald on a Windows laptop. We would no longer need this workaround there. |
@I-Al-Istannen had the fix, and he is preparing a separate PR for this.
Returning null is a bad smell, either we return |
I agree that returning
Completely agree. Thanks for the fix! Do you plan to review it now or should we wait for @I-Al-Istannen to submit the PR and then I will incorporate that patch into this PR? |
for (String dirname : System.getenv("PATH").split(File.pathSeparator)) { | ||
File file = new File(dirname, executableName); | ||
if (file.isFile() && file.canExecute()) { | ||
return file.getAbsolutePath(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem right to me. "Maven home" is the path to the Maven install directory, not the path to the Maven executable. For example, on my system the executable is at /opt/maven/bin/mvn
, but Maven home is /opt/maven
.
The prior version of this script used the Maven executable to parse Maven home
from the output of mvn --version
. I would probably still do that, it's the most foolproof way of doing it.
Does this actually work for running the MavenLauncher
?
I would also advice extracting finding the executable into a separate method ('Path getExecutablePath(String name)`) or something like that, and throw the "can't find executable" exception from there instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@slarse Maven home
and Maven executable
are indeed different things. I tried to look up Maven home in PATH, but it did not exist, so I checked how the path to maven home is being used in the codebase. I found out that there were only two places.
- Used to generate a classpath file. I did not meticulously read the method definition, but it seems like it tries to build the classpath if it doesn't exist.
- Used to run checkstyle in this test, although it is ignored.
From these two usages, I felt that looking up the path to executable would suffice, and maven home is not actually needed.
Does this actually work for running the MavenLauncher?
Yes, it does, and this corroborated my patch.
I know it's public API, but I don't think this specific API would be used. One may directly use the MavenLauncher
if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to keep the intended behaviour. Pushed the changes for it.
@monperrus ping for reviews. |
@MartinWitt I am extracting your changes to the workflow in a separate PR. |
public void testGuessMavenHome() { | ||
// contract: it should correctly fetch path to maven home | ||
String pathToMavenHome = SpoonPom.guessMavenHome(); | ||
File mavenHome = new File(pathToMavenHome); | ||
assertTrue(mavenHome.exists()); | ||
assertTrue(mavenHome.isDirectory()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that I also removed using reflection to invoke guessMavenHome
.
@monperrus ping for merge. |
String executableName; | ||
if (System.getProperty("os.name").contains("Windows")) { | ||
executableName = "mvn.cmd"; | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work on Mac? You removed the Mac case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I tested it here.
- I get the absolute path to the maven executable as I have done in this PR.
- Execute
</absolute/path/to/maven> -version
.
// contract: it should correctly fetch path to maven home | ||
String pathToMavenHome = SpoonPom.guessMavenHome(); | ||
File mavenHome = new File(pathToMavenHome); | ||
assertTrue(mavenHome.exists()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add here a String explaining what failed? The error message of assertTrue
is kinda bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I throw a SpoonException
in guessMavenHome
(message: Couldn't find path to maven home.). We will never reach this line if the test fails.
Is this the correct way to write this test because it doesn't make sense to assertDoesNotThrow
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, assertTrue with message is a best practice, but in this case we can proceed.
Keeping trace of this in good first issue #4307
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been thinking to introduce the full range of Hamcrest matchers into Spoon, they truly bring some wonderful expressiveness to tests. The perfect matcher here would be aFileNamed()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely agree. Moreover, it would also help refactor our tests. We currently use Junit4, Junit5, and hamcrest. It's best to have just one library handling it all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hamcrest is just the matchers and assertThat
, it's not a testing framework. So, it would be Junit5 + Hamcrest matchers.
Thanks a lot @algomaster99 for the solution and @slarse @MartinWitt for the review. |
Fixes #4290
Initially, it fetched "maven home" which is the path to the installation directory of maven. I, instead, try to look up the absolute path of the maven executable. I saw that the path was used to build class path and we can directly use the executable there.
I shall open this PR for review once I test the patch in sorald on a Windows machine.