Skip to content
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

Merged
merged 13 commits into from
Nov 25, 2021

Conversation

algomaster99
Copy link
Contributor

@algomaster99 algomaster99 commented Nov 19, 2021

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.

@algomaster99
Copy link
Contributor Author

algomaster99 commented Nov 19, 2021

@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?

@MartinWitt
Copy link
Collaborator

MartinWitt commented Nov 19, 2021

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

@MartinWitt
Copy link
Collaborator

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?

Comment on lines -567 to -569
if (mvnHome == null) {
throw new SpoonException("M2_HOME must be initialized to use this MavenLauncher constructor.");
}
Copy link
Contributor Author

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.

@algomaster99
Copy link
Contributor Author

@MartinWitt

Qodana doesn't like the return of null instead of throwing an exception.

That shouldn't be the case because null is returned by a lot of methods in Spoon. Moreover, severity level of "Return of null" in the job is "warning" so I don't think that the tests would fail because of returning null. Regardless, I threw an exception instead, but it didn't work.

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.

@algomaster99 algomaster99 marked this pull request as ready for review November 19, 2021 20:58
@MartinWitt
Copy link
Collaborator

MartinWitt commented Nov 19, 2021

@I-Al-Istannen had the fix, and he is preparing a separate PR for this.

That shouldn't be the case because null is returned by a lot of methods in Spoon. Moreover, severity level of "Return of null" in the job is "warning" so I don't think that the tests would fail because of returning null.

Returning null is a bad smell, either we return Optional or throw Exceptions. Yes, current spoon code returns a lot of nulls, but this isn't a perfect style. We should try to get away from it.

@algomaster99
Copy link
Contributor Author

Returning null is a bad smell, either we return Optional or throw Exceptions

I agree that returning null is a bad smell. However, we had PRs passing quality checks after qodana was configured even though return null existed in the codebase.

We should try to get away from it.

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();
Copy link
Collaborator

@slarse slarse Nov 20, 2021

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.

Copy link
Contributor Author

@algomaster99 algomaster99 Nov 22, 2021

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.

  1. 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.
  2. 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.

Copy link
Contributor Author

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.

@slarse slarse changed the title chore: lookup absolute path to maven executable fix: lookup absolute path to maven executable Nov 20, 2021
@algomaster99
Copy link
Contributor Author

@monperrus ping for reviews.

@algomaster99
Copy link
Contributor Author

@MartinWitt I am extracting your changes to the workflow in a separate PR.

@MartinWitt
Copy link
Collaborator

We have a PR already here, #4301. I thought @slarse is merging it after his comment.

Comment on lines +211 to +216
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());
Copy link
Contributor Author

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.

@algomaster99
Copy link
Contributor Author

@monperrus ping for merge.

@slarse
Copy link
Collaborator

slarse commented Nov 23, 2021

We have a PR already here, #4301. I thought @slarse is merging it after his comment.

Well, that was the idea. But I forgot and this week is a bit heavy.

Will be AWOL until the weekend, someone else tag in for this PR or I'll get to it on Saturday.

String executableName;
if (System.getProperty("os.name").contains("Windows")) {
executableName = "mvn.cmd";
} else {
Copy link
Collaborator

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?

Copy link
Contributor Author

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.

  1. I get the absolute path to the maven executable as I have done in this PR.
  2. 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());
Copy link
Collaborator

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.

Copy link
Contributor Author

@algomaster99 algomaster99 Nov 24, 2021

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?

Copy link
Collaborator

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

Copy link
Collaborator

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().

Copy link
Contributor Author

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.

Copy link
Collaborator

@slarse slarse Nov 25, 2021

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.

@monperrus
Copy link
Collaborator

Thanks a lot @algomaster99 for the solution and @slarse @MartinWitt for the review.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rewrite SpoonPom.guessMavenHome so that it correctly looks up the path to mvn executable
4 participants