Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--jvm tries to find Java executable system-wide. #11500

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ca2be99
--jvm tries to find Java executable system-wide.
Akirathan Nov 6, 2024
19b0c3d
Remove outdated GraalVMComponentUpdater and related functionality fro…
Akirathan Nov 7, 2024
b91121f
runtime-version-manager does not depend on akka-http
Akirathan Nov 7, 2024
d2e8994
Extract GraalVersionManager from RuntimeVersionManager
Akirathan Nov 7, 2024
b38928b
engine-runner depends on runtime-version-manager
Akirathan Nov 7, 2024
b9792ab
JavaFinder uses GraalVersionManager to find the java executable
Akirathan Nov 7, 2024
6b54fcc
Generate javaVersion into version-output
Akirathan Nov 7, 2024
7149cf3
GraalVMVersion is comparable
Akirathan Nov 7, 2024
d6bf5a7
Add some tests to SemVer parsing
Akirathan Nov 7, 2024
1455b02
JavaFinder tries to find newer runtime than the one used for building
Akirathan Nov 7, 2024
586fc73
Fix version-output versions mismatch
Akirathan Nov 7, 2024
dd357ca
Update docs
Akirathan Nov 7, 2024
25d8110
runtimeSearchPath does not have to be a directory
Akirathan Nov 8, 2024
c356a0c
Fix some build failures in tests
Akirathan Nov 8, 2024
ec38e0b
docs
Akirathan Nov 8, 2024
b89db13
Merge branch 'develop' into wip/akirathan/11274-jvm-cmdlineopt-ni
Akirathan Nov 13, 2024
fd52bbf
Make JavaFinder Windows friendly
Akirathan Nov 13, 2024
46022f2
GraalVersionManager is final
Akirathan Nov 13, 2024
ea3af5f
Add test for --jvm arg
Akirathan Nov 13, 2024
df1e2ec
Log found JDK
Akirathan Nov 14, 2024
ed31ffc
Add timeout to waiting for subprocess
Akirathan Nov 14, 2024
9fb23d7
Update licenses - akka-http was removed from launcher
Akirathan Nov 14, 2024
45b7889
When testing --jvm in CI, don't override ENSO_DATA_DIRECTORY env var
Akirathan Nov 14, 2024
f14333d
Run --jvm test only on Linux
Akirathan Nov 14, 2024
184c245
On Windows, java.exe is tried to be found on PATH
Akirathan Nov 14, 2024
fb25d57
Revert "Run --jvm test only on Linux"
Akirathan Nov 14, 2024
049b991
Reapply "Run --jvm test only on Linux"
Akirathan Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions engine/runner/src/main/java/org/enso/runner/JavaFinder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.enso.runner;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import org.enso.distribution.DistributionManager;
import org.enso.distribution.Environment;

/** Utility class that tries to find installed JDK on the system. */
final class JavaFinder {
private JavaFinder() {}

/**
* Tries to find {@code java} executable on the system. If a system-wide JDK is not found, tries
* to find it in the {@link DistributionManager distribution} runtimes.
*
* @return null if cannot be found. Otherwise, returns the absolute path to the executable, or
* simply {@code java} if it is on the {@code PATH}.
*/
static String findJavaExecutable() {
var javaHome = System.getenv("JAVA_HOME");
if (javaHome != null) {
var java = new File(javaHome, "bin/java").getAbsoluteFile();
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
if (java.exists()) {
return java.getAbsolutePath();
}
}
if (isJavaOnPath()) {
return "java";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that work on Windows?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't expect it to work on windows. This is a fallback that is currently only usable for devs and not anyone else. For all the other use-cases, the java exe should be found in the installed distribution runtimes.

}
var javaInRuntime = findJavaExecutableInDistributionRuntimes();
if (javaInRuntime != null) {
return javaInRuntime.toAbsolutePath().toString();
}
return null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the precedence should actually look into distribution first and only afterwards use system JVM.

The whole purpose of ensoup was to manage JVMs related to the engine versions, so that the engine is run with the right compatible JVM and not a random version that may be incompatible with it (I guess it used to be more important before Truffle 'got unchained').

I think ideally we should first to run the JVM version required by the engine if it's found in the distribution. Then we can fallback to using the logic of searching JAVA_HOME and Path.

Ideally I'd also check the JVM version and log a warning if the version required by engine does not match the version that has been found.

Copy link
Member

@radeusgd radeusgd Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JVMs related to the engine versions

This version is stored in the engine's manifest - see for example built-distribution/enso-engine-0.0.0-dev-windows-amd64/enso-0.0.0-dev/manifest.yaml.

It contains fields: graal-vm-version and graal-java-version.
You can see lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/Manifest.scala for the logic of loading the manifest and extracting the GraalVMVersion from it.

We have a GraalCEReleaseProvider which translates this GraalVMVersion into a strategy for downloading it from GitHub - but you probably don't need this.

The function graalDirectoryForVersion in RuntimeVersionManager takes GraalVMVersion and gives you back the directory name under which this JVM version will be sitting in the $ENSO_DATA_DIRECTORY/runtime (installed by ensoup).

I guess you could factor out the Manifest and graalDirectoryForVersion utilities to a common package and you could use it to figure out the JVM version tied to the engine.


Btw. the manifest also contains a jvm-options field. I'd be very happy if we could keep the (sometimes changing) options in a single place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if you want to check if the JVM version is correct you need to call java --version and somehow parse its output and compare with graal-java-version.

e.g. I get

openjdk 21.0.2 2024-01-16
OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

I guess I want to extract the second word from the first line. At least for now that seems to work. But we can update the logic whenever the version format of expected JVM changes - unexpected format just means it's not the JVM we expect :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly better way than parsing output of java -version is to run a small program on the JVM:

public static void main(String... args) {
  System.out.prinltn(System.getProperty("java.vm.version"));
  // etc.
}

and just read the output line by line without the need to parse words.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool - that indeed sounds better, I didn't think of that


private static Path findJavaExecutableInDistributionRuntimes() {
var env = new Environment() {};
var dm = new DistributionManager(env);
var paths = dm.paths();
var files = paths.runtimes().toFile().listFiles();
if (files != null) {
for (var d : files) {
var java = new File(new File(d, "bin"), "java").getAbsoluteFile();
if (java.exists()) {
return java.toPath();
}
}
}
return null;
}

private static boolean isJavaOnPath() {
try {
ProcessBuilder processBuilder = new ProcessBuilder("java", "-h");
Process process = processBuilder.start();
int exitCode = process.waitFor();
return exitCode == 0;
} catch (IOException | InterruptedException e) {
return false;
}
}
}
19 changes: 5 additions & 14 deletions engine/runner/src/main/java/org/enso/runner/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -1337,22 +1337,13 @@ private void launch(String[] args) throws IOException, InterruptedException, URI
println(JVM_OPTION + " option has no effect - already running in JVM " + current);
} else {
var commandAndArgs = new ArrayList<String>();
JVM_FOUND:
if (jvm == null) {
var env = new Environment() {};
var dm = new DistributionManager(env);
var paths = dm.paths();
var files = paths.runtimes().toFile().listFiles();
if (files != null) {
for (var d : files) {
var java = new File(new File(d, "bin"), "java").getAbsoluteFile();
if (java.exists()) {
commandAndArgs.add(java.getPath());
break JVM_FOUND;
}
}
var javaExe = JavaFinder.findJavaExecutable();
if (javaExe == null) {
println("Cannot find java executable");
throw exitFail();
}
commandAndArgs.add("java");
commandAndArgs.add(javaExe);
} else {
commandAndArgs.add(new File(new File(new File(jvm), "bin"), "java").getAbsolutePath());
}
Expand Down
Loading