mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 17:41:53 +03:00
--jvm tries to find Java executable system-wide. (#11500)
Fixes `--jvm` option, given to the native image. This was failing on my machine, because when given `--jvm` option, the runner was trying to find the `java` executable from the distribution manager's runtime (on my system located in `~/.local/share/enso/runtime`) and it used the first runtime found. But the first runtime on my system is JDK 17. The `--jvm` option now tries to: - Find a JDK from the distribution manager that has the same version as the JDK used for building the engine. - If there is not an exact version match, it tries to find a runtime from distribution manager that is *newer*. - If none, fallback to system-wide search - System-wide search tries to find `java` from `$JAVA_HOME` and from `$PATH`. But this is just a fallback. # Important Notes - Added test to Engine CI jobs that pass `--jvm` argument to a native image of engine-runner -ea3af5ffbc
- `runtime-version-manager` sbt project migrated to a JPMS module - `engine-runner` now depends on `runtime-version-manager`. - Removed unnecessary stuff in `runtime-version-manager` dealing with outdated `gu` Graal Updater utility. - Extracted [GraalVersionManager](1455b025cb/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java
) from [RuntimeVersionManager](d2e8994700/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala
)
This commit is contained in:
parent
d5f0e9ed8c
commit
9a49a02e3f
29
build.sbt
29
build.sbt
@ -721,6 +721,7 @@ lazy val componentModulesPaths =
|
|||||||
(`runtime-instrument-runtime-server` / Compile / exportedModuleBin).value,
|
(`runtime-instrument-runtime-server` / Compile / exportedModuleBin).value,
|
||||||
(`runtime-language-arrow` / Compile / exportedModuleBin).value,
|
(`runtime-language-arrow` / Compile / exportedModuleBin).value,
|
||||||
(`runtime-language-epb` / Compile / exportedModuleBin).value,
|
(`runtime-language-epb` / Compile / exportedModuleBin).value,
|
||||||
|
(`runtime-version-manager` / Compile / exportedModuleBin).value,
|
||||||
(`persistance` / Compile / exportedModuleBin).value,
|
(`persistance` / Compile / exportedModuleBin).value,
|
||||||
(`cli` / Compile / exportedModuleBin).value,
|
(`cli` / Compile / exportedModuleBin).value,
|
||||||
(`json-rpc-server` / Compile / exportedModuleBin).value,
|
(`json-rpc-server` / Compile / exportedModuleBin).value,
|
||||||
@ -1613,7 +1614,8 @@ lazy val `version-output` = (project in file("lib/scala/version-output"))
|
|||||||
defaultDevEnsoVersion = defaultDevEnsoVersion,
|
defaultDevEnsoVersion = defaultDevEnsoVersion,
|
||||||
ensoVersion = ensoVersion,
|
ensoVersion = ensoVersion,
|
||||||
scalacVersion = scalacVersion,
|
scalacVersion = scalacVersion,
|
||||||
graalVersion = graalVersion,
|
graalVersion = graalMavenPackagesVersion,
|
||||||
|
javaVersion = graalVersion,
|
||||||
currentEdition = currentEdition
|
currentEdition = currentEdition
|
||||||
)
|
)
|
||||||
}.taskValue
|
}.taskValue
|
||||||
@ -3525,6 +3527,7 @@ lazy val `engine-runner` = project
|
|||||||
(`pkg` / Compile / exportedModule).value,
|
(`pkg` / Compile / exportedModule).value,
|
||||||
(`engine-runner-common` / Compile / exportedModule).value,
|
(`engine-runner-common` / Compile / exportedModule).value,
|
||||||
(`runtime-parser` / Compile / exportedModule).value,
|
(`runtime-parser` / Compile / exportedModule).value,
|
||||||
|
(`runtime-version-manager` / Compile / exportedModule).value,
|
||||||
(`version-output` / Compile / exportedModule).value,
|
(`version-output` / Compile / exportedModule).value,
|
||||||
(`engine-common` / Compile / exportedModule).value,
|
(`engine-common` / Compile / exportedModule).value,
|
||||||
(`polyglot-api` / Compile / exportedModule).value,
|
(`polyglot-api` / Compile / exportedModule).value,
|
||||||
@ -3700,6 +3703,7 @@ lazy val `engine-runner` = project
|
|||||||
.dependsOn(`distribution-manager`)
|
.dependsOn(`distribution-manager`)
|
||||||
.dependsOn(`edition-updater`)
|
.dependsOn(`edition-updater`)
|
||||||
.dependsOn(`runtime-parser`)
|
.dependsOn(`runtime-parser`)
|
||||||
|
.dependsOn(`runtime-version-manager`)
|
||||||
.dependsOn(`logging-service`)
|
.dependsOn(`logging-service`)
|
||||||
.dependsOn(`logging-service-logback` % Runtime)
|
.dependsOn(`logging-service-logback` % Runtime)
|
||||||
.dependsOn(`engine-runner-common`)
|
.dependsOn(`engine-runner-common`)
|
||||||
@ -4337,15 +4341,34 @@ lazy val `connected-lock-manager-server` = project
|
|||||||
|
|
||||||
lazy val `runtime-version-manager` = project
|
lazy val `runtime-version-manager` = project
|
||||||
.in(file("lib/scala/runtime-version-manager"))
|
.in(file("lib/scala/runtime-version-manager"))
|
||||||
|
.enablePlugins(JPMSPlugin)
|
||||||
.configs(Test)
|
.configs(Test)
|
||||||
.settings(
|
.settings(
|
||||||
frgaalJavaCompilerSetting,
|
frgaalJavaCompilerSetting,
|
||||||
|
scalaModuleDependencySetting,
|
||||||
|
mixedJavaScalaProjectSetting,
|
||||||
resolvers += Resolver.bintrayRepo("gn0s1s", "releases"),
|
resolvers += Resolver.bintrayRepo("gn0s1s", "releases"),
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
|
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
|
||||||
"org.apache.commons" % "commons-compress" % commonsCompressVersion,
|
"org.apache.commons" % "commons-compress" % commonsCompressVersion,
|
||||||
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
|
"org.scalatest" %% "scalatest" % scalatestVersion % Test
|
||||||
akkaHttp
|
),
|
||||||
|
Compile / moduleDependencies ++= Seq(
|
||||||
|
"org.apache.commons" % "commons-compress" % commonsCompressVersion,
|
||||||
|
"org.slf4j" % "slf4j-api" % slf4jVersion
|
||||||
|
),
|
||||||
|
Compile / internalModuleDependencies := Seq(
|
||||||
|
(`cli` / Compile / exportedModule).value,
|
||||||
|
(`distribution-manager` / Compile / exportedModule).value,
|
||||||
|
(`downloader` / Compile / exportedModule).value,
|
||||||
|
(`editions` / Compile / exportedModule).value,
|
||||||
|
(`edition-updater` / Compile / exportedModule).value,
|
||||||
|
(`logging-utils` / Compile / exportedModule).value,
|
||||||
|
(`pkg` / Compile / exportedModule).value,
|
||||||
|
(`semver` / Compile / exportedModule).value,
|
||||||
|
(`scala-libs-wrapper` / Compile / exportedModule).value,
|
||||||
|
(`scala-yaml` / Compile / exportedModule).value,
|
||||||
|
(`version-output` / Compile / exportedModule).value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.dependsOn(pkg)
|
.dependsOn(pkg)
|
||||||
|
@ -664,6 +664,7 @@ pub async fn runner_sanity_test(
|
|||||||
.bin
|
.bin
|
||||||
.join("enso")
|
.join("enso")
|
||||||
.with_executable_extension();
|
.with_executable_extension();
|
||||||
|
|
||||||
let test_base = Command::new(&enso)
|
let test_base = Command::new(&enso)
|
||||||
.args(["--run", repo_root.test.join("Base_Tests").as_str()])
|
.args(["--run", repo_root.test.join("Base_Tests").as_str()])
|
||||||
.set_env(ENSO_DATA_DIRECTORY, engine_package)?
|
.set_env(ENSO_DATA_DIRECTORY, engine_package)?
|
||||||
@ -686,7 +687,25 @@ pub async fn runner_sanity_test(
|
|||||||
.run_ok()
|
.run_ok()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
test_base.and(test_internal_base).and(test_geo)
|
let all_cmds = test_base.and(test_internal_base).and(test_geo);
|
||||||
|
|
||||||
|
// The following test does not actually run anything, it just checks if the engine
|
||||||
|
// can accept `--jvm` argument and evaluates something.
|
||||||
|
if TARGET_OS != OS::Windows {
|
||||||
|
let test_jvm_arg = Command::new(&enso)
|
||||||
|
.args([
|
||||||
|
"--jvm",
|
||||||
|
"--run",
|
||||||
|
repo_root.test.join("Base_Tests").as_str(),
|
||||||
|
"__NON_EXISTING_TEST__",
|
||||||
|
])
|
||||||
|
.set_env(ENSO_DATA_DIRECTORY, engine_package)?
|
||||||
|
.run_ok()
|
||||||
|
.await;
|
||||||
|
all_cmds.and(test_jvm_arg)
|
||||||
|
} else {
|
||||||
|
all_cmds
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -36,21 +36,6 @@ The license file can be found at `licenses/APACHE2.0`.
|
|||||||
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-actor_2.13-2.6.20`.
|
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-actor_2.13-2.6.20`.
|
||||||
|
|
||||||
|
|
||||||
'akka-http-core_2.13', licensed under the Apache-2.0, is distributed with the launcher.
|
|
||||||
The license file can be found at `licenses/APACHE2.0`.
|
|
||||||
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-http-core_2.13-10.2.10`.
|
|
||||||
|
|
||||||
|
|
||||||
'akka-http_2.13', licensed under the Apache-2.0, is distributed with the launcher.
|
|
||||||
The license file can be found at `licenses/APACHE2.0`.
|
|
||||||
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-http_2.13-10.2.10`.
|
|
||||||
|
|
||||||
|
|
||||||
'akka-parsing_2.13', licensed under the Apache-2.0, is distributed with the launcher.
|
|
||||||
The license file can be found at `licenses/APACHE2.0`.
|
|
||||||
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-parsing_2.13-10.2.10`.
|
|
||||||
|
|
||||||
|
|
||||||
'akka-slf4j_2.13', licensed under the Apache-2.0, is distributed with the launcher.
|
'akka-slf4j_2.13', licensed under the Apache-2.0, is distributed with the launcher.
|
||||||
The license file can be found at `licenses/APACHE2.0`.
|
The license file can be found at `licenses/APACHE2.0`.
|
||||||
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-slf4j_2.13-2.6.20`.
|
Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-slf4j_2.13-2.6.20`.
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
Copyright (C) 2008-2017 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
|
||||||
|
|
||||||
Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev
|
|
||||||
|
|
||||||
Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
|
|
||||||
Copyright 2011 Mark Harrah, Eugene Yokota
|
|
||||||
|
|
||||||
Copyright 2014 Twitter, Inc.
|
|
||||||
|
|
||||||
Copyright 2015 Heiko Seeberger
|
|
@ -1 +0,0 @@
|
|||||||
Copyright (C) 2009-2020 Lightbend Inc. <http://www.lightbend.com>
|
|
@ -1,7 +0,0 @@
|
|||||||
Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev
|
|
||||||
|
|
||||||
Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
|
|
||||||
Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
|
|
||||||
|
|
||||||
Copyright (c) 2011-13 Miles Sabin
|
|
@ -39,10 +39,6 @@ object DefaultManagers {
|
|||||||
lazy val temporaryDirectoryManager =
|
lazy val temporaryDirectoryManager =
|
||||||
TemporaryDirectoryManager(distributionManager, defaultResourceManager)
|
TemporaryDirectoryManager(distributionManager, defaultResourceManager)
|
||||||
|
|
||||||
/** Default [[RuntimeComponentConfiguration]]. */
|
|
||||||
lazy val componentConfig: RuntimeComponentConfiguration =
|
|
||||||
new GraalVMComponentConfiguration
|
|
||||||
|
|
||||||
/** Creates a [[RuntimeVersionManager]] that uses the default distribution. */
|
/** Creates a [[RuntimeVersionManager]] that uses the default distribution. */
|
||||||
def runtimeVersionManager(
|
def runtimeVersionManager(
|
||||||
globalCLIOptions: GlobalCLIOptions,
|
globalCLIOptions: GlobalCLIOptions,
|
||||||
@ -55,12 +51,11 @@ object DefaultManagers {
|
|||||||
alwaysInstallMissing
|
alwaysInstallMissing
|
||||||
),
|
),
|
||||||
distributionManager,
|
distributionManager,
|
||||||
|
new GraalVersionManager(distributionManager, LauncherEnvironment),
|
||||||
temporaryDirectoryManager,
|
temporaryDirectoryManager,
|
||||||
defaultResourceManager,
|
defaultResourceManager,
|
||||||
EngineRepository.defaultEngineReleaseProvider,
|
EngineRepository.defaultEngineReleaseProvider,
|
||||||
GraalCEReleaseProvider.default,
|
GraalCEReleaseProvider.default,
|
||||||
componentConfig,
|
|
||||||
RuntimeComponentUpdaterFactory.Default,
|
|
||||||
InstallerKind.Launcher
|
InstallerKind.Launcher
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ module org.enso.runner {
|
|||||||
requires org.enso.logging.config;
|
requires org.enso.logging.config;
|
||||||
requires org.enso.logging.utils;
|
requires org.enso.logging.utils;
|
||||||
requires org.enso.runtime.parser;
|
requires org.enso.runtime.parser;
|
||||||
|
requires org.enso.runtime.version.manager;
|
||||||
requires org.enso.runner.common;
|
requires org.enso.runner.common;
|
||||||
requires org.enso.pkg;
|
requires org.enso.pkg;
|
||||||
requires org.enso.polyglot.api;
|
requires org.enso.polyglot.api;
|
||||||
|
110
engine/runner/src/main/java/org/enso/runner/JavaFinder.java
Normal file
110
engine/runner/src/main/java/org/enso/runner/JavaFinder.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package org.enso.runner;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.enso.distribution.DistributionManager;
|
||||||
|
import org.enso.distribution.Environment;
|
||||||
|
import org.enso.runtimeversionmanager.components.GraalRuntime;
|
||||||
|
import org.enso.runtimeversionmanager.components.GraalVMVersion;
|
||||||
|
import org.enso.runtimeversionmanager.components.GraalVersionManager;
|
||||||
|
import org.enso.version.BuildVersion;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/** Utility class that tries to find installed JDK on the system. */
|
||||||
|
final class JavaFinder {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(JavaFinder.class);
|
||||||
|
|
||||||
|
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 javaInRuntime = findJavaExecutableInDistributionRuntimes();
|
||||||
|
if (javaInRuntime != null) {
|
||||||
|
return javaInRuntime.toAbsolutePath().toString();
|
||||||
|
}
|
||||||
|
logger.warn("No appropriate JDK found in the distribution runtimes. Trying system-wide JDK.");
|
||||||
|
var javaHome = System.getenv("JAVA_HOME");
|
||||||
|
if (javaHome != null) {
|
||||||
|
var binDir = Path.of(javaHome).resolve("bin");
|
||||||
|
Path javaExe;
|
||||||
|
if (isOnWindows()) {
|
||||||
|
javaExe = binDir.resolve("java.exe");
|
||||||
|
} else {
|
||||||
|
javaExe = binDir.resolve("java");
|
||||||
|
}
|
||||||
|
if (javaExe.toFile().exists()) {
|
||||||
|
logger.warn("Found JDK in JAVA_HOME: {}", javaHome);
|
||||||
|
return javaExe.toAbsolutePath().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.warn("No JDK found in JAVA_HOME. Trying java on PATH.");
|
||||||
|
if (isJavaOnPath()) {
|
||||||
|
var javaExe = isOnWindows() ? "java.exe" : "java";
|
||||||
|
logger.warn("Falling back to java on PATH: {}", javaExe);
|
||||||
|
return javaExe;
|
||||||
|
}
|
||||||
|
logger.warn("No JDK found on PATH. Cannot start the runtime.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isOnWindows() {
|
||||||
|
return System.getProperty("os.name").equals("windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find {@code java} executable in the distribution runtime with the same version that
|
||||||
|
* was used for building, or a newer one.
|
||||||
|
*
|
||||||
|
* @return null if not found.
|
||||||
|
*/
|
||||||
|
private static Path findJavaExecutableInDistributionRuntimes() {
|
||||||
|
var env = new Environment() {};
|
||||||
|
var distributionManager = new DistributionManager(env);
|
||||||
|
var graalVersionManager = new GraalVersionManager(distributionManager, env);
|
||||||
|
var versionUsedForBuild =
|
||||||
|
new GraalVMVersion(BuildVersion.graalVersion(), BuildVersion.javaVersion());
|
||||||
|
var runtimeWithExactVersionMatch = graalVersionManager.findGraalRuntime(versionUsedForBuild);
|
||||||
|
if (runtimeWithExactVersionMatch != null) {
|
||||||
|
return runtimeWithExactVersionMatch.javaExecutable();
|
||||||
|
}
|
||||||
|
// Try to find newer runtime (JDK).
|
||||||
|
var newerRuntime =
|
||||||
|
graalVersionManager.getAllRuntimes().stream()
|
||||||
|
.sorted(Comparator.comparing(GraalRuntime::version))
|
||||||
|
.filter(runtime -> runtime.version().compareTo(versionUsedForBuild) > 0)
|
||||||
|
.findFirst();
|
||||||
|
if (newerRuntime.isPresent()) {
|
||||||
|
logger.warn(
|
||||||
|
"Found newer JDK [{}] than the one used for build [{}]",
|
||||||
|
newerRuntime.get().version(),
|
||||||
|
versionUsedForBuild);
|
||||||
|
return newerRuntime.get().javaExecutable();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isJavaOnPath() {
|
||||||
|
try {
|
||||||
|
ProcessBuilder processBuilder;
|
||||||
|
if (isOnWindows()) {
|
||||||
|
processBuilder = new ProcessBuilder("java.exe", "-h");
|
||||||
|
} else {
|
||||||
|
processBuilder = new ProcessBuilder("java", "-h");
|
||||||
|
}
|
||||||
|
Process process = processBuilder.start();
|
||||||
|
boolean exitSucc = process.waitFor(5L, TimeUnit.SECONDS);
|
||||||
|
return exitSucc;
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1339,22 +1339,13 @@ public class Main {
|
|||||||
println(JVM_OPTION + " option has no effect - already running in JVM " + current);
|
println(JVM_OPTION + " option has no effect - already running in JVM " + current);
|
||||||
} else {
|
} else {
|
||||||
var commandAndArgs = new ArrayList<String>();
|
var commandAndArgs = new ArrayList<String>();
|
||||||
JVM_FOUND:
|
|
||||||
if (jvm == null) {
|
if (jvm == null) {
|
||||||
var env = new Environment() {};
|
var javaExe = JavaFinder.findJavaExecutable();
|
||||||
var dm = new DistributionManager(env);
|
if (javaExe == null) {
|
||||||
var paths = dm.paths();
|
println("Cannot find java executable");
|
||||||
var files = paths.runtimes().toFile().listFiles();
|
throw exitFail();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
commandAndArgs.add("java");
|
commandAndArgs.add(javaExe);
|
||||||
} else {
|
} else {
|
||||||
commandAndArgs.add(new File(new File(new File(jvm), "bin"), "java").getAbsolutePath());
|
commandAndArgs.add(new File(new File(new File(jvm), "bin"), "java").getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,6 @@ object DefaultDistributionConfiguration
|
|||||||
lazy val temporaryDirectoryManager =
|
lazy val temporaryDirectoryManager =
|
||||||
TemporaryDirectoryManager(distributionManager, resourceManager)
|
TemporaryDirectoryManager(distributionManager, resourceManager)
|
||||||
|
|
||||||
lazy val componentConfiguration: RuntimeComponentConfiguration =
|
|
||||||
new GraalVMComponentConfiguration
|
|
||||||
|
|
||||||
lazy val runtimeComponentUpdaterFactory: RuntimeComponentUpdaterFactory =
|
|
||||||
RuntimeComponentUpdaterFactory.Default
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
def engineReleaseProvider: ReleaseProvider[EngineRelease] =
|
def engineReleaseProvider: ReleaseProvider[EngineRelease] =
|
||||||
EngineRepository.defaultEngineReleaseProvider
|
EngineRepository.defaultEngineReleaseProvider
|
||||||
@ -67,15 +61,15 @@ object DefaultDistributionConfiguration
|
|||||||
userInterface: RuntimeVersionManagementUserInterface
|
userInterface: RuntimeVersionManagementUserInterface
|
||||||
): RuntimeVersionManager =
|
): RuntimeVersionManager =
|
||||||
new RuntimeVersionManager(
|
new RuntimeVersionManager(
|
||||||
environment = this.environment,
|
environment = this.environment,
|
||||||
userInterface = userInterface,
|
userInterface = userInterface,
|
||||||
distributionManager = distributionManager,
|
distributionManager = distributionManager,
|
||||||
|
graalVersionManager =
|
||||||
|
new GraalVersionManager(distributionManager, environment),
|
||||||
temporaryDirectoryManager = temporaryDirectoryManager,
|
temporaryDirectoryManager = temporaryDirectoryManager,
|
||||||
resourceManager = resourceManager,
|
resourceManager = resourceManager,
|
||||||
engineReleaseProvider = engineReleaseProvider,
|
engineReleaseProvider = engineReleaseProvider,
|
||||||
runtimeReleaseProvider = GraalCEReleaseProvider.default,
|
runtimeReleaseProvider = GraalCEReleaseProvider.default,
|
||||||
componentConfig = componentConfiguration,
|
|
||||||
componentUpdaterFactory = runtimeComponentUpdaterFactory,
|
|
||||||
installerKind = InstallerKind.ProjectManager
|
installerKind = InstallerKind.ProjectManager
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import org.enso.editions.updater.EditionManager
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import org.enso.projectmanager.versionmanagement.DistributionConfiguration
|
import org.enso.projectmanager.versionmanagement.DistributionConfiguration
|
||||||
import org.enso.runtimeversionmanager.components.{
|
import org.enso.runtimeversionmanager.components.{
|
||||||
GraalVMComponentConfiguration,
|
GraalVersionManager,
|
||||||
InstallerKind,
|
InstallerKind,
|
||||||
RuntimeVersionManagementUserInterface,
|
RuntimeVersionManagementUserInterface,
|
||||||
RuntimeVersionManager
|
RuntimeVersionManager
|
||||||
@ -28,7 +28,6 @@ import org.enso.runtimeversionmanager.releases.{
|
|||||||
import org.enso.runtimeversionmanager.runner.{JVMSettings, JavaCommand}
|
import org.enso.runtimeversionmanager.runner.{JVMSettings, JavaCommand}
|
||||||
import org.enso.runtimeversionmanager.test.{
|
import org.enso.runtimeversionmanager.test.{
|
||||||
FakeEnvironment,
|
FakeEnvironment,
|
||||||
NoopComponentUpdaterFactory,
|
|
||||||
TestLocalLockManager
|
TestLocalLockManager
|
||||||
}
|
}
|
||||||
import org.enso.testkit.HasTestDirectory
|
import org.enso.testkit.HasTestDirectory
|
||||||
@ -60,6 +59,9 @@ class TestDistributionConfiguration(
|
|||||||
|
|
||||||
lazy val distributionManager = new DistributionManager(environment)
|
lazy val distributionManager = new DistributionManager(environment)
|
||||||
|
|
||||||
|
lazy val graalVersionManager =
|
||||||
|
new GraalVersionManager(distributionManager, environment)
|
||||||
|
|
||||||
lazy val lockManager = new TestLocalLockManager
|
lazy val lockManager = new TestLocalLockManager
|
||||||
|
|
||||||
lazy val resourceManager = new ResourceManager(lockManager)
|
lazy val resourceManager = new ResourceManager(lockManager)
|
||||||
@ -69,10 +71,6 @@ class TestDistributionConfiguration(
|
|||||||
lazy val temporaryDirectoryManager =
|
lazy val temporaryDirectoryManager =
|
||||||
TemporaryDirectoryManager(distributionManager, resourceManager)
|
TemporaryDirectoryManager(distributionManager, resourceManager)
|
||||||
|
|
||||||
lazy val componentConfig = new GraalVMComponentConfiguration
|
|
||||||
|
|
||||||
lazy val componentUpdaterFactory = NoopComponentUpdaterFactory
|
|
||||||
|
|
||||||
override def makeRuntimeVersionManager(
|
override def makeRuntimeVersionManager(
|
||||||
userInterface: RuntimeVersionManagementUserInterface
|
userInterface: RuntimeVersionManagementUserInterface
|
||||||
): RuntimeVersionManager = new RuntimeVersionManager(
|
): RuntimeVersionManager = new RuntimeVersionManager(
|
||||||
@ -80,11 +78,10 @@ class TestDistributionConfiguration(
|
|||||||
userInterface = userInterface,
|
userInterface = userInterface,
|
||||||
distributionManager = distributionManager,
|
distributionManager = distributionManager,
|
||||||
temporaryDirectoryManager = temporaryDirectoryManager,
|
temporaryDirectoryManager = temporaryDirectoryManager,
|
||||||
|
graalVersionManager = graalVersionManager,
|
||||||
resourceManager = resourceManager,
|
resourceManager = resourceManager,
|
||||||
engineReleaseProvider = engineReleaseProvider,
|
engineReleaseProvider = engineReleaseProvider,
|
||||||
runtimeReleaseProvider = runtimeReleaseProvider,
|
runtimeReleaseProvider = runtimeReleaseProvider,
|
||||||
componentConfig = componentConfig,
|
|
||||||
componentUpdaterFactory = componentUpdaterFactory,
|
|
||||||
installerKind = InstallerKind.ProjectManager
|
installerKind = InstallerKind.ProjectManager
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.test
|
|
||||||
|
|
||||||
import org.enso.runtimeversionmanager.components.{
|
|
||||||
GraalVMComponent,
|
|
||||||
RuntimeComponentUpdater
|
|
||||||
}
|
|
||||||
|
|
||||||
import scala.util.Try
|
|
||||||
|
|
||||||
/** Test component updater that does not do anything. */
|
|
||||||
object NoopComponentUpdater extends RuntimeComponentUpdater {
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
override def list(): Try[Seq[GraalVMComponent]] =
|
|
||||||
Try(Seq())
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
override def install(components: Seq[GraalVMComponent]): Try[Unit] =
|
|
||||||
Try(())
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.test
|
|
||||||
|
|
||||||
import org.enso.runtimeversionmanager.components.{
|
|
||||||
GraalRuntime,
|
|
||||||
RuntimeComponentUpdater,
|
|
||||||
RuntimeComponentUpdaterFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Test factory creating a noop updater. */
|
|
||||||
object NoopComponentUpdaterFactory extends RuntimeComponentUpdaterFactory {
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
override def build(runtime: GraalRuntime): RuntimeComponentUpdater =
|
|
||||||
NoopComponentUpdater
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ import org.enso.distribution.{
|
|||||||
}
|
}
|
||||||
import org.enso.pkg.{Config, PackageManager}
|
import org.enso.pkg.{Config, PackageManager}
|
||||||
import org.enso.runtimeversionmanager.components.{
|
import org.enso.runtimeversionmanager.components.{
|
||||||
GraalVMComponentConfiguration,
|
GraalVersionManager,
|
||||||
InstallerKind,
|
InstallerKind,
|
||||||
RuntimeVersionManagementUserInterface,
|
RuntimeVersionManagementUserInterface,
|
||||||
RuntimeVersionManager
|
RuntimeVersionManager
|
||||||
@ -51,22 +51,21 @@ class RuntimeVersionManagerTest
|
|||||||
): (DistributionManager, RuntimeVersionManager, Environment) = {
|
): (DistributionManager, RuntimeVersionManager, Environment) = {
|
||||||
val env = fakeInstalledEnvironment(environmentOverrides)
|
val env = fakeInstalledEnvironment(environmentOverrides)
|
||||||
val distributionManager = new PortableDistributionManager(env)
|
val distributionManager = new PortableDistributionManager(env)
|
||||||
|
val graalVersionManager = new GraalVersionManager(distributionManager, env)
|
||||||
|
|
||||||
val resourceManager = TestLocalResourceManager.create()
|
val resourceManager = TestLocalResourceManager.create()
|
||||||
val temporaryDirectoryManager =
|
val temporaryDirectoryManager =
|
||||||
TemporaryDirectoryManager(distributionManager, resourceManager)
|
TemporaryDirectoryManager(distributionManager, resourceManager)
|
||||||
val componentConfig = new GraalVMComponentConfiguration
|
|
||||||
|
|
||||||
val runtimeVersionManager = new RuntimeVersionManager(
|
val runtimeVersionManager = new RuntimeVersionManager(
|
||||||
env,
|
env,
|
||||||
userInterface,
|
userInterface,
|
||||||
distributionManager,
|
distributionManager,
|
||||||
|
graalVersionManager,
|
||||||
temporaryDirectoryManager,
|
temporaryDirectoryManager,
|
||||||
resourceManager,
|
resourceManager,
|
||||||
engineProvider,
|
engineProvider,
|
||||||
runtimeProvider,
|
runtimeProvider,
|
||||||
componentConfig,
|
|
||||||
NoopComponentUpdaterFactory,
|
|
||||||
installerKind
|
installerKind
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ import org.enso.distribution.{
|
|||||||
TemporaryDirectoryManager
|
TemporaryDirectoryManager
|
||||||
}
|
}
|
||||||
import org.enso.runtimeversionmanager.components.{
|
import org.enso.runtimeversionmanager.components.{
|
||||||
GraalVMComponentConfiguration,
|
|
||||||
GraalVMVersion,
|
GraalVMVersion,
|
||||||
|
GraalVersionManager,
|
||||||
InstallerKind,
|
InstallerKind,
|
||||||
Manifest,
|
Manifest,
|
||||||
RuntimeVersionManager
|
RuntimeVersionManager
|
||||||
@ -140,19 +140,18 @@ class ConcurrencyTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val graalVersionManager = new GraalVersionManager(distributionManager, env)
|
||||||
val temporaryDirectoryManager =
|
val temporaryDirectoryManager =
|
||||||
TemporaryDirectoryManager(distributionManager, resourceManager)
|
TemporaryDirectoryManager(distributionManager, resourceManager)
|
||||||
val componentConfig = new GraalVMComponentConfiguration
|
|
||||||
val componentsManager = new RuntimeVersionManager(
|
val componentsManager = new RuntimeVersionManager(
|
||||||
env,
|
env,
|
||||||
TestRuntimeVersionManagementUserInterface.default,
|
TestRuntimeVersionManagementUserInterface.default,
|
||||||
distributionManager,
|
distributionManager,
|
||||||
|
graalVersionManager,
|
||||||
temporaryDirectoryManager,
|
temporaryDirectoryManager,
|
||||||
resourceManager,
|
resourceManager,
|
||||||
engineProvider,
|
engineProvider,
|
||||||
runtimeProvider,
|
runtimeProvider,
|
||||||
componentConfig,
|
|
||||||
NoopComponentUpdaterFactory,
|
|
||||||
InstallerKind.Launcher
|
InstallerKind.Launcher
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
module org.enso.runtime.version.manager {
|
||||||
|
requires scala.library;
|
||||||
|
requires org.apache.commons.compress;
|
||||||
|
requires org.slf4j;
|
||||||
|
requires org.enso.cli;
|
||||||
|
requires org.enso.distribution;
|
||||||
|
requires org.enso.downloader;
|
||||||
|
requires org.enso.editions;
|
||||||
|
requires org.enso.editions.updater;
|
||||||
|
requires org.enso.logging.utils;
|
||||||
|
requires org.enso.pkg;
|
||||||
|
requires org.enso.semver;
|
||||||
|
requires org.enso.scala.yaml;
|
||||||
|
// For com.typesafe.scalalogging.Logger
|
||||||
|
requires org.enso.scala.wrapper;
|
||||||
|
requires org.enso.version.output;
|
||||||
|
|
||||||
|
exports org.enso.runtimeversionmanager;
|
||||||
|
exports org.enso.runtimeversionmanager.cli;
|
||||||
|
exports org.enso.runtimeversionmanager.components;
|
||||||
|
exports org.enso.runtimeversionmanager.runner;
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
package org.enso.runtimeversionmanager.components;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.enso.distribution.DistributionManager;
|
||||||
|
import org.enso.distribution.Environment;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import scala.jdk.javaapi.CollectionConverters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class that finds installed managed runtimes (Graal JDK) from {@link DistributionManager}.
|
||||||
|
*/
|
||||||
|
public final class GraalVersionManager {
|
||||||
|
private final DistributionManager distributionManager;
|
||||||
|
private final Environment environment;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GraalVersionManager.class);
|
||||||
|
|
||||||
|
public GraalVersionManager(DistributionManager distributionManager, Environment environment) {
|
||||||
|
this.distributionManager = distributionManager;
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all locally installed runtimes.
|
||||||
|
*
|
||||||
|
* @return Possibly empty list. Not null.
|
||||||
|
*/
|
||||||
|
public List<GraalRuntime> getAllRuntimes() {
|
||||||
|
var foundRuntimes = new ArrayList<GraalRuntime>();
|
||||||
|
for (var runtimeSearchPath :
|
||||||
|
CollectionConverters.asJava(distributionManager.paths().runtimeSearchPaths())) {
|
||||||
|
if (runtimeSearchPath.toFile().isDirectory()) {
|
||||||
|
var subdirs = runtimeSearchPath.toFile().listFiles();
|
||||||
|
assert subdirs != null;
|
||||||
|
for (var subdir : subdirs) {
|
||||||
|
var parsedVersion = parseGraalRuntimeVersionString(subdir.getName());
|
||||||
|
if (parsedVersion != null) {
|
||||||
|
var foundRuntime = new GraalRuntime(parsedVersion, subdir.toPath());
|
||||||
|
foundRuntime.ensureValid();
|
||||||
|
foundRuntimes.add(foundRuntime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn("Runtime search path `{}` is not a directory", runtimeSearchPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundRuntimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find a GraalVM runtime for the provided engine.
|
||||||
|
*
|
||||||
|
* <p>Returns null if the runtime is missing.
|
||||||
|
*/
|
||||||
|
public GraalRuntime findGraalRuntime(Engine engine) {
|
||||||
|
return findGraalRuntime(engine.manifest().runtimeVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an installed GraalVM runtime with the given {@code version}.
|
||||||
|
*
|
||||||
|
* <p>Returns null if that version is not installed.
|
||||||
|
*/
|
||||||
|
public GraalRuntime findGraalRuntime(GraalVMVersion version) {
|
||||||
|
var explicitPathOpt = environment.getEnvPath("ENSO_JVM_PATH");
|
||||||
|
if (explicitPathOpt.isDefined()) {
|
||||||
|
var runtime = new GraalRuntime(version, explicitPathOpt.get());
|
||||||
|
runtime.ensureValid();
|
||||||
|
logger.debug("Found GraalVM runtime [{}]", runtime);
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
var pathOpt = findGraalRuntimeOnSearchPath(version);
|
||||||
|
if (pathOpt != null) {
|
||||||
|
GraalRuntime runtime;
|
||||||
|
try {
|
||||||
|
runtime = loadGraalRuntime(pathOpt);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new UnrecognizedComponentError(
|
||||||
|
"The runtime "
|
||||||
|
+ version
|
||||||
|
+ "is already installed, but cannot be "
|
||||||
|
+ "loaded due to "
|
||||||
|
+ e.getMessage()
|
||||||
|
+ "."
|
||||||
|
+ "Until the launcher gets an auto-repair "
|
||||||
|
+ "feature, please try reinstalling the runtime by "
|
||||||
|
+ "uninstalling all engines that use it and installing them "
|
||||||
|
+ "again, or manually removing `"
|
||||||
|
+ pathOpt
|
||||||
|
+ "`",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
logger.debug("Found GraalVM runtime [{}]", runtime);
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
logger.debug("GraalVM runtime [{}] not found", version);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraalRuntime loadGraalRuntime(Path path) throws UnrecognizedComponentError {
|
||||||
|
logger.debug("Loading Graal runtime [{}]", path);
|
||||||
|
var name = path.getFileName().toString();
|
||||||
|
var version = parseGraalRuntimeVersionString(name);
|
||||||
|
if (version == null) {
|
||||||
|
throw new UnrecognizedComponentError("Invalid runtime component name `" + name + "`", null);
|
||||||
|
}
|
||||||
|
var runtime = new GraalRuntime(version, path);
|
||||||
|
runtime.ensureValid();
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path findGraalRuntimeOnSearchPath(GraalVMVersion version) {
|
||||||
|
var name = graalRuntimeNameForVersion(version);
|
||||||
|
for (var runtimeSearchPath :
|
||||||
|
CollectionConverters.asJava(distributionManager.paths().runtimeSearchPaths())) {
|
||||||
|
var path = runtimeSearchPath.resolve(name);
|
||||||
|
if (path.toFile().exists()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GraalVMVersion parseGraalRuntimeVersionString(String name) {
|
||||||
|
var pattern = Pattern.compile("graalvm-ce-java(.+)-(.+)");
|
||||||
|
var matcher = pattern.matcher(name);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return new GraalVMVersion(matcher.group(2), matcher.group(1));
|
||||||
|
}
|
||||||
|
logger.warn("Unrecognized runtime name `{}`", name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String graalRuntimeNameForVersion(GraalVMVersion version) {
|
||||||
|
return "graalvm-ce-java" + version.javaVersion() + "-" + version.graalVersion();
|
||||||
|
}
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager;
|
|
@ -1,6 +1,5 @@
|
|||||||
package org.enso.runtimeversionmanager.cli
|
package org.enso.runtimeversionmanager.cli
|
||||||
|
|
||||||
import akka.http.scaladsl.model.{IllegalUriException, Uri}
|
|
||||||
import org.enso.cli.arguments.{Argument, OptsParseError}
|
import org.enso.cli.arguments.{Argument, OptsParseError}
|
||||||
import org.enso.logger.LoggerUtils
|
import org.enso.logger.LoggerUtils
|
||||||
|
|
||||||
@ -9,14 +8,6 @@ import java.net.URISyntaxException
|
|||||||
import org.slf4j.event.Level
|
import org.slf4j.event.Level
|
||||||
|
|
||||||
object Arguments {
|
object Arguments {
|
||||||
implicit val uriAkkaArgument: Argument[Uri] = (string: String) =>
|
|
||||||
try {
|
|
||||||
Right(Uri(string))
|
|
||||||
} catch {
|
|
||||||
case error: IllegalUriException =>
|
|
||||||
Left(OptsParseError(s"`$string` is not a valid Uri: $error."))
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit val uriArgument: Argument[URI] = (string: String) =>
|
implicit val uriArgument: Argument[URI] = (string: String) =>
|
||||||
try {
|
try {
|
||||||
Right(URI.create(string))
|
Right(URI.create(string))
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
/** A component of the GraalVM distribution. */
|
|
||||||
case class GraalVMComponent(id: String)
|
|
||||||
|
|
||||||
object GraalVMComponent {
|
|
||||||
|
|
||||||
val js: GraalVMComponent = GraalVMComponent("js")
|
|
||||||
val python: GraalVMComponent = GraalVMComponent("python")
|
|
||||||
val R: GraalVMComponent = GraalVMComponent("R")
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import org.enso.cli.OS
|
|
||||||
|
|
||||||
/** Component configuration of the GraalVM distribution. */
|
|
||||||
class GraalVMComponentConfiguration extends RuntimeComponentConfiguration {
|
|
||||||
|
|
||||||
import GraalVMComponentConfiguration._
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
override def getRequiredComponents(
|
|
||||||
version: GraalVMVersion,
|
|
||||||
os: OS
|
|
||||||
): Seq[GraalVMComponent] = {
|
|
||||||
val optPythonComponent =
|
|
||||||
if (os.hasPythonSupport) Seq(GraalVMComponent.python) else Seq()
|
|
||||||
val optRComponent =
|
|
||||||
if (os.hasRSupport) Seq(GraalVMComponent.R) else Seq()
|
|
||||||
if (version.isUnchained) {
|
|
||||||
Seq()
|
|
||||||
} else {
|
|
||||||
version.graalVersion match {
|
|
||||||
case GraalVersions.Major(v) if v >= 23 =>
|
|
||||||
// Since 23.0.0, R is not bundled in the Graal release anymore.
|
|
||||||
Seq(GraalVMComponent.js) ++ optPythonComponent
|
|
||||||
case GraalVersions.Major(v) if v >= 22 =>
|
|
||||||
Seq(GraalVMComponent.js) ++ optRComponent ++ optPythonComponent
|
|
||||||
case GraalVersions.Major(v)
|
|
||||||
if v > 20 && os.hasSulongSupport && os.hasRSupport =>
|
|
||||||
Seq(GraalVMComponent.R) ++ optPythonComponent
|
|
||||||
case _ =>
|
|
||||||
Seq()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
object GraalVMComponentConfiguration {
|
|
||||||
|
|
||||||
/** OS extensions. */
|
|
||||||
implicit private class OSExtensions(os: OS) {
|
|
||||||
|
|
||||||
/** Check if the provided OS supports Sulong runtime.
|
|
||||||
*
|
|
||||||
* Sulong is a Graal sub-project, providing an engine for running
|
|
||||||
* LLVM bitcode on GraalVM.
|
|
||||||
*
|
|
||||||
* @return `true` if the OS supports Sulong runtime and `false` otherwise
|
|
||||||
*/
|
|
||||||
def hasSulongSupport: Boolean =
|
|
||||||
os match {
|
|
||||||
case OS.Linux => true
|
|
||||||
case OS.MacOS => true
|
|
||||||
case OS.Windows => false
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the provided OS supports Python.
|
|
||||||
* Python is currently not supported in any form on Windows.
|
|
||||||
*
|
|
||||||
* @return `true` if the OS supports Python runtime
|
|
||||||
*/
|
|
||||||
def hasPythonSupport: Boolean =
|
|
||||||
os match {
|
|
||||||
case OS.Windows => false
|
|
||||||
case _ => true
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the provided OS supports FastR.
|
|
||||||
* FastR is currently not supported in any form on Windows.
|
|
||||||
*
|
|
||||||
* @return `true` if the OS supports FastR GraalVM component.
|
|
||||||
*/
|
|
||||||
def hasRSupport: Boolean =
|
|
||||||
os match {
|
|
||||||
case OS.Windows => false
|
|
||||||
case _ => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private object GraalVersions {
|
|
||||||
|
|
||||||
/** Get the major Graal version number. */
|
|
||||||
object Major {
|
|
||||||
def unapply(version: String): Option[Int] = {
|
|
||||||
version.takeWhile(_ != '.').toIntOption
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import java.nio.file.Path
|
|
||||||
import com.typesafe.scalalogging.Logger
|
|
||||||
|
|
||||||
import scala.sys.process._
|
|
||||||
import scala.util.{Failure, Success, Try}
|
|
||||||
|
|
||||||
/** Module that manages components of the GraalVM distribution.
|
|
||||||
*
|
|
||||||
* @param runtime the GraalVM runtime
|
|
||||||
*/
|
|
||||||
class GraalVMComponentUpdater(runtime: GraalRuntime)
|
|
||||||
extends RuntimeComponentUpdater {
|
|
||||||
|
|
||||||
import GraalVMComponentUpdater._
|
|
||||||
|
|
||||||
private val logger = Logger[GraalVMComponentUpdater]
|
|
||||||
private val gu = runtime.findExecutable("gu")
|
|
||||||
|
|
||||||
/** Path to the GraalVM's updater.
|
|
||||||
*
|
|
||||||
* @return path that will be executed to call the updater
|
|
||||||
*/
|
|
||||||
protected def updaterExec: Path = gu
|
|
||||||
|
|
||||||
/** List the installed GraalVM components.
|
|
||||||
*
|
|
||||||
* @return the list of installed GraalVM components
|
|
||||||
*/
|
|
||||||
override def list(): Try[Seq[GraalVMComponent]] = {
|
|
||||||
val command = Seq("list", "-v")
|
|
||||||
|
|
||||||
logger.trace("{} {}", gu, Properties(gu))
|
|
||||||
logger.debug(
|
|
||||||
"Executing: JAVA_HOME={} GRAALVM_HOME={} {} {}",
|
|
||||||
runtime.javaHome,
|
|
||||||
runtime.javaHome,
|
|
||||||
gu,
|
|
||||||
command.mkString(" ")
|
|
||||||
)
|
|
||||||
|
|
||||||
val executor = new ExponentialBackoffRetry(5, logger) {
|
|
||||||
override def cmd: String = "list"
|
|
||||||
override def executeProcess(
|
|
||||||
logger: ProcessLogger
|
|
||||||
): Try[LazyList[String]] = {
|
|
||||||
val process = Process(
|
|
||||||
updaterExec.toAbsolutePath.toString +: command,
|
|
||||||
Some(runtime.javaHome.toFile),
|
|
||||||
("JAVA_HOME", runtime.javaHome),
|
|
||||||
("GRAALVM_HOME", runtime.javaHome)
|
|
||||||
)
|
|
||||||
Try(process.lazyLines(logger))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
executor
|
|
||||||
.execute()
|
|
||||||
.map(stdout => if (stdout.isEmpty) Seq() else ListOut.parse(stdout))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Install the provided GraalVM components.
|
|
||||||
*
|
|
||||||
* @param components the list of components to install
|
|
||||||
*/
|
|
||||||
override def install(components: Seq[GraalVMComponent]): Try[Unit] = {
|
|
||||||
if (components.nonEmpty) {
|
|
||||||
val command = "install" +: components.map(_.id)
|
|
||||||
logger.trace("{} {}", gu, Properties(gu))
|
|
||||||
logger.debug(
|
|
||||||
"Executing: JAVA_HOME={} GRRAALVM_HOME={} {} {}",
|
|
||||||
runtime.javaHome,
|
|
||||||
runtime.javaHome,
|
|
||||||
gu,
|
|
||||||
command.mkString(" ")
|
|
||||||
)
|
|
||||||
val executor = new ExponentialBackoffRetry(5, logger) {
|
|
||||||
override def cmd: String = "install"
|
|
||||||
override def executeProcess(
|
|
||||||
logger: ProcessLogger
|
|
||||||
): Try[LazyList[String]] = {
|
|
||||||
val process = Process(
|
|
||||||
updaterExec.toAbsolutePath.toString +: command,
|
|
||||||
Some(runtime.path.toFile),
|
|
||||||
("JAVA_HOME", runtime.javaHome),
|
|
||||||
("GRAALVM_HOME", runtime.javaHome)
|
|
||||||
)
|
|
||||||
Try(process.lazyLines(logger))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
executor.execute().map { stdout =>
|
|
||||||
stdout.foreach(logger.trace(_))
|
|
||||||
()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Success(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
object GraalVMComponentUpdater {
|
|
||||||
|
|
||||||
abstract class ProcessWithRetries(maxRetries: Int, logger: Logger) {
|
|
||||||
def executeProcess(logger: ProcessLogger): Try[LazyList[String]]
|
|
||||||
|
|
||||||
def cmd: String
|
|
||||||
|
|
||||||
def execute(): Try[List[String]] = execute(0)
|
|
||||||
|
|
||||||
protected def retryWait(retry: Int): Long
|
|
||||||
|
|
||||||
private def execute(retry: Int): Try[List[String]] = {
|
|
||||||
val errors = scala.collection.mutable.ListBuffer[String]()
|
|
||||||
val processLogger = ProcessLogger(err => errors.addOne(err))
|
|
||||||
executeProcess(processLogger) match {
|
|
||||||
case Success(stdout) =>
|
|
||||||
Try(stdout.toList).recoverWith({
|
|
||||||
case _ if retry < maxRetries =>
|
|
||||||
try {
|
|
||||||
Thread.sleep(retryWait(retry))
|
|
||||||
} catch {
|
|
||||||
case _: InterruptedException =>
|
|
||||||
}
|
|
||||||
execute(retry + 1)
|
|
||||||
})
|
|
||||||
case Failure(exception) if retry < maxRetries =>
|
|
||||||
logger.warn("{} failed: {}. Retrying...", cmd, exception.getMessage)
|
|
||||||
try {
|
|
||||||
Thread.sleep(retryWait(retry))
|
|
||||||
} catch {
|
|
||||||
case _: InterruptedException =>
|
|
||||||
}
|
|
||||||
execute(retry + 1)
|
|
||||||
case Failure(exception) =>
|
|
||||||
errors.foreach(logger.trace("[stderr] {}", _))
|
|
||||||
Failure(exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class ExponentialBackoffRetry(maxRetries: Int, logger: Logger)
|
|
||||||
extends ProcessWithRetries(maxRetries, logger) {
|
|
||||||
override def retryWait(retry: Int): Long = {
|
|
||||||
200 * 2.toLong ^ retry
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit private def pathToString(path: Path): String =
|
|
||||||
path.toAbsolutePath.toString
|
|
||||||
|
|
||||||
/** Debug file properties. */
|
|
||||||
private case class Properties(path: Path) {
|
|
||||||
|
|
||||||
private val file = path.toFile
|
|
||||||
|
|
||||||
override def toString: String =
|
|
||||||
s"{ exists=${file.exists()}, " +
|
|
||||||
s"executable=${file.canExecute} " +
|
|
||||||
"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parser for the `gu list -v` command output. */
|
|
||||||
object ListOut {
|
|
||||||
|
|
||||||
private val ID: String = "ID"
|
|
||||||
private val separator: Char = ':'
|
|
||||||
|
|
||||||
/** Extract the GraalVM components from the gu output.
|
|
||||||
*
|
|
||||||
* @param lines the gu output
|
|
||||||
* @return the list of GraalVM components.
|
|
||||||
*/
|
|
||||||
def parse(lines: Seq[String]): Seq[GraalVMComponent] =
|
|
||||||
lines
|
|
||||||
.filter(_.startsWith(ID))
|
|
||||||
.map(_.dropWhile(_ != separator).drop(1).trim)
|
|
||||||
.map(GraalVMComponent(_))
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,7 +11,8 @@ import org.enso.semver.SemVer
|
|||||||
* Can be specified either as a single integer or as a
|
* Can be specified either as a single integer or as a
|
||||||
* semantic version
|
* semantic version
|
||||||
*/
|
*/
|
||||||
case class GraalVMVersion(graalVersion: String, javaVersion: String) {
|
case class GraalVMVersion(graalVersion: String, javaVersion: String)
|
||||||
|
extends Comparable[GraalVMVersion] {
|
||||||
require(GraalVMVersion.isCorrectVersionFormat(graalVersion))
|
require(GraalVMVersion.isCorrectVersionFormat(graalVersion))
|
||||||
require(GraalVMVersion.isCorrectVersionFormat(javaVersion))
|
require(GraalVMVersion.isCorrectVersionFormat(javaVersion))
|
||||||
|
|
||||||
@ -29,15 +30,35 @@ case class GraalVMVersion(graalVersion: String, javaVersion: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The GraalVM distribution policy changed a lot since GraalVM 23.1.0 for JDK 21.
|
override def compareTo(other: GraalVMVersion): Int = {
|
||||||
* Most of the components for the newest GraalVM distributions are distributed as
|
val javaSemVer = SemVer.parse(javaVersion)
|
||||||
* artifacts from the Maven central. This mens there is no longer `gu` tool.
|
val otherJavaSemVer = SemVer.parse(other.javaVersion)
|
||||||
*
|
if (javaSemVer.isSuccess && otherJavaSemVer.isSuccess) {
|
||||||
* @see https://medium.com/graalvm/truffle-unchained-13887b77b62c
|
val comp = javaSemVer.get.compareTo(otherJavaSemVer.get)
|
||||||
* @return true if this version is associated with Truffle unchained.
|
if (comp != 0) {
|
||||||
*/
|
return comp
|
||||||
def isUnchained: Boolean = {
|
}
|
||||||
javaMajorVersion >= 21 && graalMajorVersion >= 23
|
}
|
||||||
|
|
||||||
|
val graalSemVer = SemVer.parse(graalVersion)
|
||||||
|
val otherGraalSemVer = SemVer.parse(other.graalVersion)
|
||||||
|
if (graalSemVer.isSuccess && otherGraalSemVer.isSuccess) {
|
||||||
|
val comp = graalSemVer.get.compareTo(otherGraalSemVer.get)
|
||||||
|
if (comp != 0) {
|
||||||
|
return comp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val javaMajorComp = javaMajorVersion.compareTo(other.javaMajorVersion)
|
||||||
|
if (javaMajorComp != 0) {
|
||||||
|
return javaMajorComp
|
||||||
|
}
|
||||||
|
val graalMajorComp = graalMajorVersion.compareTo(other.graalMajorVersion)
|
||||||
|
if (graalMajorComp != 0) {
|
||||||
|
return graalMajorComp
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import org.enso.cli.OS
|
|
||||||
|
|
||||||
/** Provides configuration of the runtime components. */
|
|
||||||
trait RuntimeComponentConfiguration {
|
|
||||||
|
|
||||||
/** Return the list of components required for the provided version of
|
|
||||||
* the runtime installed on the provided OS.
|
|
||||||
*
|
|
||||||
* @param version the runtime version
|
|
||||||
* @param os the operating system
|
|
||||||
* @return the list of required components
|
|
||||||
*/
|
|
||||||
def getRequiredComponents(
|
|
||||||
version: GraalVMVersion,
|
|
||||||
os: OS
|
|
||||||
): Seq[GraalVMComponent]
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import scala.util.Try
|
|
||||||
|
|
||||||
/** Module that manages components of the runtime distribution. */
|
|
||||||
trait RuntimeComponentUpdater {
|
|
||||||
|
|
||||||
/** List the installed runtime components.
|
|
||||||
*
|
|
||||||
* @return the list of installed runtime components
|
|
||||||
*/
|
|
||||||
def list(): Try[Seq[GraalVMComponent]]
|
|
||||||
|
|
||||||
/** Install the provided runtime components.
|
|
||||||
*
|
|
||||||
* @param components the list of components to install
|
|
||||||
*/
|
|
||||||
def install(components: Seq[GraalVMComponent]): Try[Unit]
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
/** The factory that creates a runtime component updater. */
|
|
||||||
trait RuntimeComponentUpdaterFactory {
|
|
||||||
|
|
||||||
/** Create a runtime component updater.
|
|
||||||
*
|
|
||||||
* @param runtime the GraalVM runtime
|
|
||||||
* @return new instance of the runtime component updater
|
|
||||||
*/
|
|
||||||
def build(runtime: GraalRuntime): RuntimeComponentUpdater
|
|
||||||
}
|
|
||||||
|
|
||||||
object RuntimeComponentUpdaterFactory {
|
|
||||||
|
|
||||||
/** The default runtime component updater factory creating an instance of
|
|
||||||
* [[GraalVMComponentUpdater]].
|
|
||||||
*/
|
|
||||||
object Default extends RuntimeComponentUpdaterFactory {
|
|
||||||
|
|
||||||
/** @inheritdoc */
|
|
||||||
override def build(runtime: GraalRuntime): RuntimeComponentUpdater = {
|
|
||||||
if (runtime.version.isUnchained) {
|
|
||||||
new UnchainedGraalVMComponentUpdater()
|
|
||||||
} else {
|
|
||||||
new GraalVMComponentUpdater(runtime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ package org.enso.runtimeversionmanager.components
|
|||||||
import java.nio.file.{Files, Path, StandardOpenOption}
|
import java.nio.file.{Files, Path, StandardOpenOption}
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.enso.semver.SemVer
|
import org.enso.semver.SemVer
|
||||||
import org.enso.cli.OS
|
|
||||||
import org.enso.distribution.{
|
import org.enso.distribution.{
|
||||||
DistributionManager,
|
DistributionManager,
|
||||||
Environment,
|
Environment,
|
||||||
@ -13,7 +12,6 @@ import org.enso.distribution.{
|
|||||||
import org.enso.distribution.locking.{LockType, ResourceManager}
|
import org.enso.distribution.locking.{LockType, ResourceManager}
|
||||||
import org.enso.runtimeversionmanager.CurrentVersion
|
import org.enso.runtimeversionmanager.CurrentVersion
|
||||||
import org.enso.distribution.FileSystem.PathSyntax
|
import org.enso.distribution.FileSystem.PathSyntax
|
||||||
import org.enso.logger.masking.MaskedPath
|
|
||||||
import org.enso.downloader.archive.Archive
|
import org.enso.downloader.archive.Archive
|
||||||
import org.enso.runtimeversionmanager.locking.Resources
|
import org.enso.runtimeversionmanager.locking.Resources
|
||||||
import org.enso.runtimeversionmanager.releases.ReleaseProvider
|
import org.enso.runtimeversionmanager.releases.ReleaseProvider
|
||||||
@ -32,79 +30,36 @@ import scala.util.{Failure, Success, Try, Using}
|
|||||||
* @param userInterface a [[RuntimeVersionManagementUserInterface]] instance
|
* @param userInterface a [[RuntimeVersionManagementUserInterface]] instance
|
||||||
* that specifies how to handle user interactions
|
* that specifies how to handle user interactions
|
||||||
* (displaying progress and handling corner cases)
|
* (displaying progress and handling corner cases)
|
||||||
* @param distributionManager the [[DistributionManager]] to use
|
|
||||||
* @param engineReleaseProvider the provider of engine releases
|
* @param engineReleaseProvider the provider of engine releases
|
||||||
* @param runtimeReleaseProvider the provider of runtime releases
|
* @param runtimeReleaseProvider the provider of runtime releases
|
||||||
* @param componentConfig the runtime component configuration
|
|
||||||
* @param componentUpdaterFactory the runtime component updater factory
|
|
||||||
*/
|
*/
|
||||||
class RuntimeVersionManager(
|
class RuntimeVersionManager(
|
||||||
environment: Environment,
|
environment: Environment,
|
||||||
userInterface: RuntimeVersionManagementUserInterface,
|
userInterface: RuntimeVersionManagementUserInterface,
|
||||||
distributionManager: DistributionManager,
|
distributionManager: DistributionManager,
|
||||||
|
graalVersionManager: GraalVersionManager,
|
||||||
temporaryDirectoryManager: TemporaryDirectoryManager,
|
temporaryDirectoryManager: TemporaryDirectoryManager,
|
||||||
resourceManager: ResourceManager,
|
resourceManager: ResourceManager,
|
||||||
engineReleaseProvider: ReleaseProvider[EngineRelease],
|
engineReleaseProvider: ReleaseProvider[EngineRelease],
|
||||||
runtimeReleaseProvider: GraalVMRuntimeReleaseProvider,
|
runtimeReleaseProvider: GraalVMRuntimeReleaseProvider,
|
||||||
componentConfig: RuntimeComponentConfiguration,
|
|
||||||
componentUpdaterFactory: RuntimeComponentUpdaterFactory,
|
|
||||||
implicit private val installerKind: InstallerKind
|
implicit private val installerKind: InstallerKind
|
||||||
) {
|
) {
|
||||||
private val logger = Logger[RuntimeVersionManager]
|
private val logger = Logger[RuntimeVersionManager]
|
||||||
private val os = OS.operatingSystem
|
|
||||||
|
|
||||||
/** Tries to find a GraalVM runtime for the provided engine.
|
/** Tries to find a GraalVM runtime for the provided engine.
|
||||||
*
|
*
|
||||||
* Returns None if the runtime is missing.
|
* Returns None if the runtime is missing.
|
||||||
*/
|
*/
|
||||||
def findGraalRuntime(engine: Engine): Option[GraalRuntime] =
|
def findGraalRuntime(engine: Engine): Option[GraalRuntime] = {
|
||||||
findGraalRuntime(engine.manifest.runtimeVersion)
|
Option(graalVersionManager.findGraalRuntime(engine))
|
||||||
|
}
|
||||||
|
|
||||||
/** Finds an installed GraalVM runtime with the given `version`.
|
/** Finds an installed GraalVM runtime with the given `version`.
|
||||||
*
|
*
|
||||||
* Returns None if that version is not installed.
|
* Returns None if that version is not installed.
|
||||||
*/
|
*/
|
||||||
def findGraalRuntime(version: GraalVMVersion): Option[GraalRuntime] = {
|
def findGraalRuntime(version: GraalVMVersion): Option[GraalRuntime] = {
|
||||||
val explicitPathOpt = this.environment.getEnvPath("ENSO_JVM_PATH")
|
Option(graalVersionManager.findGraalRuntime(version));
|
||||||
val graalRuntimeOpt = explicitPathOpt
|
|
||||||
.map(path => {
|
|
||||||
val runtime = GraalRuntime(version, path)
|
|
||||||
runtime.ensureValid()
|
|
||||||
runtime
|
|
||||||
})
|
|
||||||
.orElse {
|
|
||||||
val pathOpt = findGraalRuntimeOnSearchPath(version)
|
|
||||||
pathOpt.map { path =>
|
|
||||||
// TODO [RW] for now an exception is thrown if the installation is
|
|
||||||
// corrupted, in #1052 offer to repair the broken installation
|
|
||||||
loadGraalRuntime(path).recoverWith { case e: Exception =>
|
|
||||||
Failure(
|
|
||||||
UnrecognizedComponentError(
|
|
||||||
s"The runtime $version is already installed, but cannot be " +
|
|
||||||
s"loaded due to $e. Until the launcher gets an auto-repair " +
|
|
||||||
s"feature, please try reinstalling the runtime by " +
|
|
||||||
s"uninstalling all engines that use it and installing them " +
|
|
||||||
s"again, or manually removing `$path`",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}.get
|
|
||||||
}
|
|
||||||
}
|
|
||||||
graalRuntimeOpt match {
|
|
||||||
case Some(graalRuntime) =>
|
|
||||||
logger.debug("Found GraalVM runtime [{}]", graalRuntime)
|
|
||||||
case None =>
|
|
||||||
logger.debug("GraalVM runtime [{}] not found", version)
|
|
||||||
}
|
|
||||||
graalRuntimeOpt
|
|
||||||
}
|
|
||||||
|
|
||||||
private def findGraalRuntimeOnSearchPath(
|
|
||||||
version: GraalVMVersion
|
|
||||||
): Option[Path] = {
|
|
||||||
val name = graalRuntimeNameForVersion(version)
|
|
||||||
firstExisting(distributionManager.paths.runtimeSearchPaths.map(_ / name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Executes the provided action with a requested engine version.
|
/** Executes the provided action with a requested engine version.
|
||||||
@ -635,70 +590,13 @@ class RuntimeVersionManager(
|
|||||||
private def engineNameForVersion(version: SemVer): String =
|
private def engineNameForVersion(version: SemVer): String =
|
||||||
version.toString
|
version.toString
|
||||||
|
|
||||||
/** Returns name of the directory containing the runtime of that version.
|
|
||||||
*/
|
|
||||||
private def graalRuntimeNameForVersion(version: GraalVMVersion): String = {
|
|
||||||
s"graalvm-ce-java${version.javaVersion}-${version.graalVersion}"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Loads the GraalVM runtime definition.
|
/** Loads the GraalVM runtime definition.
|
||||||
*/
|
*/
|
||||||
private def loadGraalRuntime(path: Path): Try[GraalRuntime] = {
|
private def loadGraalRuntime(path: Path): Try[GraalRuntime] = {
|
||||||
logger.debug("Loading Graal runtime [{}]", path)
|
try {
|
||||||
val name = path.getFileName.toString
|
Success(graalVersionManager.loadGraalRuntime(path))
|
||||||
for {
|
} catch {
|
||||||
version <- parseGraalRuntimeVersionString(name)
|
case e: UnrecognizedComponentError => Failure(e)
|
||||||
.toRight(
|
|
||||||
UnrecognizedComponentError(s"Invalid runtime component name `$name`.")
|
|
||||||
)
|
|
||||||
.toTry
|
|
||||||
runtime = GraalRuntime(version, path)
|
|
||||||
_ <- runtime.ensureValid()
|
|
||||||
_ <- installRequiredRuntimeComponents(runtime).recover {
|
|
||||||
case NonFatal(error) =>
|
|
||||||
val msg = translateError(error)
|
|
||||||
logger.warn(
|
|
||||||
"Failed to install required components on the existing [{}]. " +
|
|
||||||
"Some language features may be unavailable. {}",
|
|
||||||
runtime,
|
|
||||||
msg
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} yield runtime
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Provide human-readable error messages for OS-specific failures
|
|
||||||
* @param cause exception thrown when executing the process
|
|
||||||
* @return human-readable error message
|
|
||||||
*/
|
|
||||||
private def translateError(cause: Throwable): String = {
|
|
||||||
val msg = cause.getMessage
|
|
||||||
OS.operatingSystem match {
|
|
||||||
case OS.Linux => msg
|
|
||||||
case OS.MacOS => msg
|
|
||||||
case OS.Windows =>
|
|
||||||
if (msg.contains("-1073741515")) {
|
|
||||||
"Required Microsoft Visual C++ installation is missing"
|
|
||||||
} else {
|
|
||||||
msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the runtime version from its name.
|
|
||||||
*/
|
|
||||||
private def parseGraalRuntimeVersionString(
|
|
||||||
name: String
|
|
||||||
): Option[GraalVMVersion] = {
|
|
||||||
val regex = """graalvm-ce-java(.+)-(.+)""".r
|
|
||||||
name match {
|
|
||||||
case regex(javaVersionString, graalVersionString) =>
|
|
||||||
Some(GraalVMVersion(graalVersionString, javaVersionString))
|
|
||||||
case _ =>
|
|
||||||
logger.warn(
|
|
||||||
s"Unrecognized runtime name `$name`"
|
|
||||||
)
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,26 +698,16 @@ class RuntimeVersionManager(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug("Loading temporary runtime [{}]", runtimeTemporaryPath)
|
logger.debug("Loading temporary runtime [{}]", runtimeTemporaryPath)
|
||||||
val temporaryRuntime =
|
|
||||||
loadGraalRuntime(runtimeTemporaryPath).recoverWith { error =>
|
loadGraalRuntime(runtimeTemporaryPath).recoverWith { error =>
|
||||||
Failure(
|
Failure(
|
||||||
InstallationError(
|
InstallationError(
|
||||||
"Cannot load the installed runtime. The package may have " +
|
"Cannot load the installed runtime. The package may have " +
|
||||||
"been corrupted. Reverting installation",
|
"been corrupted. Reverting installation",
|
||||||
error
|
error
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}.get
|
)
|
||||||
logger.debug("Installing GraalVM components to [{}]", temporaryRuntime)
|
}
|
||||||
installRequiredRuntimeComponents(temporaryRuntime).recoverWith {
|
|
||||||
error =>
|
|
||||||
Failure(
|
|
||||||
InstallationError(
|
|
||||||
"fatal: Cannot install the required runtime components",
|
|
||||||
error
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}.get
|
|
||||||
|
|
||||||
val runtimePath =
|
val runtimePath =
|
||||||
distributionManager.paths.runtimes / runtimeDirectoryName
|
distributionManager.paths.runtimes / runtimeDirectoryName
|
||||||
@ -849,32 +737,6 @@ class RuntimeVersionManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Install components required for the specified runtime on the specified OS.
|
|
||||||
*
|
|
||||||
* @param runtime the GraalVM runtime
|
|
||||||
*/
|
|
||||||
private def installRequiredRuntimeComponents(
|
|
||||||
runtime: GraalRuntime
|
|
||||||
): Try[Unit] = {
|
|
||||||
logger.debug("Installing GraalVM components [{}, {}]", runtime, os)
|
|
||||||
val cu = componentUpdaterFactory.build(runtime)
|
|
||||||
val requiredComponents =
|
|
||||||
componentConfig.getRequiredComponents(runtime.version, os)
|
|
||||||
|
|
||||||
if (requiredComponents.isEmpty) Success(())
|
|
||||||
else {
|
|
||||||
for {
|
|
||||||
installedComponents <- cu.list()
|
|
||||||
_ = logger.debug(
|
|
||||||
"Available GraalVM components: [{}]",
|
|
||||||
installedComponents
|
|
||||||
)
|
|
||||||
missingComponents = requiredComponents.diff(installedComponents)
|
|
||||||
_ <- cu.install(missingComponents)
|
|
||||||
} yield ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def engineDirectoryNameForVersion(version: SemVer): Path =
|
private def engineDirectoryNameForVersion(version: SemVer): Path =
|
||||||
Path.of(version.toString())
|
Path.of(version.toString())
|
||||||
|
|
||||||
@ -931,33 +793,6 @@ class RuntimeVersionManager(
|
|||||||
FileSystem.removeDirectory(temporaryPath)
|
FileSystem.removeDirectory(temporaryPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logs on trace level all installed engines and runtimes.
|
|
||||||
*
|
|
||||||
* NOTE: Useful for debugging but should not be added to production code since it may
|
|
||||||
* cause unnecessary installations for different engine versions.
|
|
||||||
*/
|
|
||||||
def logAvailableComponentsForDebugging(): Unit = logger.whenTraceEnabled {
|
|
||||||
logger.trace("Discovering available components...")
|
|
||||||
val engines = for (engine <- listInstalledEngines()) yield {
|
|
||||||
val runtime = findGraalRuntime(engine)
|
|
||||||
val runtimeName = runtime
|
|
||||||
.map(_.toString)
|
|
||||||
.getOrElse("no runtime found")
|
|
||||||
val broken = if (engine.isMarkedBroken) " (broken)" else ""
|
|
||||||
s" - Enso ${engine.version}$broken [runtime: $runtimeName] " +
|
|
||||||
s"[location: ${MaskedPath(engine.path).applyMasking()}]"
|
|
||||||
}
|
|
||||||
|
|
||||||
val runtimes =
|
|
||||||
for (runtime <- listInstalledGraalRuntimes())
|
|
||||||
yield s" - $runtime [location: " +
|
|
||||||
s"${MaskedPath(runtime.path).applyMasking()}]"
|
|
||||||
|
|
||||||
logger.trace(
|
|
||||||
s"Installed engines (${engines.length}):\n${engines.mkString("\n")}\n\n" +
|
|
||||||
s"Installed runtimes (${runtimes.length}):\n${runtimes.mkString("\n")}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note [RuntimeVersionManager Concurrency Model]
|
/* Note [RuntimeVersionManager Concurrency Model]
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import scala.util.{Success, Try}
|
|
||||||
|
|
||||||
/** A dummy component updater for [[GraalVMVersion.isUnchained unchained]] GraalVM.
|
|
||||||
* There is no `gu` utility in unchained GraalVM, so this updater does not do anything.
|
|
||||||
* It only lists the components that are known to be included in the unchained GraalVM.
|
|
||||||
*/
|
|
||||||
class UnchainedGraalVMComponentUpdater extends RuntimeComponentUpdater {
|
|
||||||
|
|
||||||
/** There
|
|
||||||
*
|
|
||||||
* @return the list of installed runtime components
|
|
||||||
*/
|
|
||||||
override def list(): Try[Seq[GraalVMComponent]] = Success(Seq())
|
|
||||||
|
|
||||||
/** Install the provided runtime components.
|
|
||||||
*
|
|
||||||
* @param components the list of components to install
|
|
||||||
*/
|
|
||||||
override def install(components: Seq[GraalVMComponent]): Try[Unit] = {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Cannot install components in unchained GraalVM"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import org.enso.cli.OS
|
|
||||||
import org.scalatest.matchers.should.Matchers
|
|
||||||
import org.scalatest.wordspec.AnyWordSpec
|
|
||||||
|
|
||||||
class GraalVMComponentConfigurationSpec extends AnyWordSpec with Matchers {
|
|
||||||
|
|
||||||
"RuntimeComponentConfiguration" should {
|
|
||||||
|
|
||||||
"return required components" in {
|
|
||||||
val conf = new GraalVMComponentConfiguration
|
|
||||||
val required = Seq(GraalVMComponent.python, GraalVMComponent.R)
|
|
||||||
val requiredAbove22 = required ++ Seq(GraalVMComponent.js)
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("21.0.0.2", "11"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs required
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("21.0.0.2", "11"),
|
|
||||||
OS.MacOS
|
|
||||||
) should contain theSameElementsAs required
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("21.0.0.2", "11"),
|
|
||||||
OS.Windows
|
|
||||||
) should contain theSameElementsAs Seq()
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("22.0.0.0", "11"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs requiredAbove22
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("22.3.1", "17"),
|
|
||||||
OS.MacOS
|
|
||||||
) should contain theSameElementsAs requiredAbove22
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("22.3.1", "17"),
|
|
||||||
OS.Windows
|
|
||||||
) should contain theSameElementsAs Seq(
|
|
||||||
GraalVMComponent.js
|
|
||||||
)
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("22.3.1", "17"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs Seq(
|
|
||||||
GraalVMComponent.js,
|
|
||||||
GraalVMComponent.python,
|
|
||||||
GraalVMComponent.R
|
|
||||||
)
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("20.0.0.0", "11"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs Seq()
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("23.0.0", "17.0.7+7.1"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs Seq(
|
|
||||||
GraalVMComponent.js,
|
|
||||||
GraalVMComponent.python
|
|
||||||
)
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("23.0.0", "11"),
|
|
||||||
OS.Linux
|
|
||||||
) should contain theSameElementsAs Seq(
|
|
||||||
GraalVMComponent.js,
|
|
||||||
GraalVMComponent.python
|
|
||||||
)
|
|
||||||
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
GraalVMVersion("23.0.0", "17.0.7+7.1"),
|
|
||||||
OS.Windows
|
|
||||||
) should contain theSameElementsAs Seq(
|
|
||||||
GraalVMComponent.js
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
"return no required components for Truffle unchained" in {
|
|
||||||
val conf = new GraalVMComponentConfiguration
|
|
||||||
val versions = Seq(
|
|
||||||
GraalVMVersion("23.0.0", "21"),
|
|
||||||
GraalVMVersion("23.0.1", "21"),
|
|
||||||
GraalVMVersion("23.0.0", "21.0.1"),
|
|
||||||
GraalVMVersion("23.0.1", "21.0.1"),
|
|
||||||
GraalVMVersion("23.0.0", "21.0.1+5.1"),
|
|
||||||
GraalVMVersion("23.0.1", "21.0.1+5.1"),
|
|
||||||
GraalVMVersion("23.1.0", "21")
|
|
||||||
)
|
|
||||||
versions.forall(_.isUnchained) shouldBe true
|
|
||||||
versions.foreach(version => {
|
|
||||||
conf.getRequiredComponents(
|
|
||||||
version,
|
|
||||||
OS.Linux
|
|
||||||
) shouldBe empty
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
package org.enso.runtimeversionmanager.components
|
|
||||||
|
|
||||||
import org.scalatest.matchers.should.Matchers
|
|
||||||
import org.scalatest.wordspec.AnyWordSpec
|
|
||||||
|
|
||||||
class GraalVMComponentParserSpec extends AnyWordSpec with Matchers {
|
|
||||||
|
|
||||||
"RuntimeComponentUpdater" should {
|
|
||||||
|
|
||||||
"parse list output" in {
|
|
||||||
val listOut =
|
|
||||||
"""
|
|
||||||
|ID : js
|
|
||||||
|Name : Graal.js
|
|
||||||
|Version : 21.0.0.2
|
|
||||||
|GraalVM : n/a
|
|
||||||
|Stability: -
|
|
||||||
|Origin :
|
|
||||||
|
|
|
||||||
|ID : graalvm
|
|
||||||
|Name : GraalVM Core
|
|
||||||
|Version : 21.0.0.2
|
|
||||||
|GraalVM : n/a
|
|
||||||
|Stability: -
|
|
||||||
|Origin :
|
|
||||||
|
|
|
||||||
|ID : R
|
|
||||||
|Name : FastR
|
|
||||||
|Version : 21.0.0.2
|
|
||||||
|GraalVM : 21.0.0.2
|
|
||||||
|Stability: Experimental
|
|
||||||
|Origin : https://github.com/oracle/fastr/releases/download/vm-21.0.0.2/r-installable-java11-linux-amd64-21.0.0.2.jar
|
|
||||||
|
|
|
||||||
|ID : llvm-toolchain
|
|
||||||
|Name : LLVM.org toolchain
|
|
||||||
|Version : 21.0.0.2
|
|
||||||
|GraalVM : 21.0.0.2
|
|
||||||
|Stability: Supported
|
|
||||||
|Origin : https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/llvm-toolchain-installable-java11-linux-amd64-21.0.0.2.jar
|
|
||||||
|
|
|
||||||
|ID : native-image
|
|
||||||
|Name : Native Image
|
|
||||||
|Version : 21.0.0.2
|
|
||||||
|GraalVM : 21.0.0.2
|
|
||||||
|Stability: Early adopter
|
|
||||||
|Origin : https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/native-image-installable-svm-java11-linux-amd64-21.0.0.2.jar
|
|
||||||
|""".stripMargin
|
|
||||||
|
|
||||||
val expectedComponents =
|
|
||||||
Seq("js", "graalvm", "R", "llvm-toolchain", "native-image")
|
|
||||||
.map(GraalVMComponent(_))
|
|
||||||
val components =
|
|
||||||
GraalVMComponentUpdater.ListOut.parse(listOut.linesIterator.toSeq)
|
|
||||||
components shouldEqual expectedComponents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package org.enso.runtimeversionmanager.components
|
||||||
|
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
import org.scalatest.wordspec.AnyWordSpec
|
||||||
|
|
||||||
|
class GraalVMVersionSpec extends AnyWordSpec with Matchers {
|
||||||
|
|
||||||
|
"GraalVM Version" should {
|
||||||
|
"greater JDK version is considered newer" in {
|
||||||
|
val graalVersion = "24.0.0"
|
||||||
|
val ver1 = GraalVMVersion(graalVersion, "21.0.2")
|
||||||
|
val ver2 = GraalVMVersion(graalVersion, "17.0.7")
|
||||||
|
(ver1.compareTo(ver2) > 0) shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
|
"If JDK version is same (semver), greater Graal version is newer" in {
|
||||||
|
val jdkVersion = "21.0.2"
|
||||||
|
val ver1 = GraalVMVersion("24.0.2", jdkVersion)
|
||||||
|
val ver2 = GraalVMVersion("24.0.0", jdkVersion)
|
||||||
|
(ver1.compareTo(ver2) > 0) shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
|
"If JDK version is same (non semver), greater Graal version is newer" in {
|
||||||
|
val jdkVersion = "21"
|
||||||
|
val ver1 = GraalVMVersion("24.0.2", jdkVersion)
|
||||||
|
val ver2 = GraalVMVersion("24.0.0", jdkVersion)
|
||||||
|
(ver1.compareTo(ver2) > 0) shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
|
"be correctly ordered" in {
|
||||||
|
val ver1 = GraalVMVersion("24.0.0", "21.0.2")
|
||||||
|
val ver2 = GraalVMVersion("23.1.2", "21.0.2")
|
||||||
|
val ver3 = GraalVMVersion("23.1.0", "21.0.1")
|
||||||
|
val ver4 = GraalVMVersion("23.0.0", "17.0.7")
|
||||||
|
val lst = List(ver4, ver2, ver3, ver1)
|
||||||
|
val sortedList = lst.sortWith((ver1, ver2) => ver1.compareTo(ver2) < 0)
|
||||||
|
sortedList shouldEqual List(ver4, ver3, ver2, ver1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,8 @@ public class VersionsTest {
|
|||||||
assertTrue(SemVer.parse("0.1.1").isSuccess());
|
assertTrue(SemVer.parse("0.1.1").isSuccess());
|
||||||
assertTrue(SemVer.parse("9999.0.0").isSuccess());
|
assertTrue(SemVer.parse("9999.0.0").isSuccess());
|
||||||
assertTrue(SemVer.parse("0.1").isFailure());
|
assertTrue(SemVer.parse("0.1").isFailure());
|
||||||
|
assertTrue(SemVer.parse("21.0.2").isSuccess());
|
||||||
|
assertTrue(SemVer.parse("17.0.7").isSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -19,10 +19,23 @@ public class BuildVersion {
|
|||||||
return GeneratedVersion.scalacVersion();
|
return GeneratedVersion.scalacVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of GraalVM, more specifically, version of the GraalVM and Truffle libraries used to
|
||||||
|
* build the engine.
|
||||||
|
*/
|
||||||
public static String graalVersion() {
|
public static String graalVersion() {
|
||||||
return GeneratedVersion.graalVersion();
|
return GeneratedVersion.graalVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of Java (JDK) used to build the engine.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String javaVersion() {
|
||||||
|
return GeneratedVersion.javaVersion();
|
||||||
|
}
|
||||||
|
|
||||||
public static String currentEdition() {
|
public static String currentEdition() {
|
||||||
return GeneratedVersion.currentEdition();
|
return GeneratedVersion.currentEdition();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ object BuildInfo {
|
|||||||
* @param ensoVersion Enso version
|
* @param ensoVersion Enso version
|
||||||
* @param scalacVersion Scala compiler version used in the project
|
* @param scalacVersion Scala compiler version used in the project
|
||||||
* @param graalVersion GraalVM version used in the project
|
* @param graalVersion GraalVM version used in the project
|
||||||
|
* @param javaVersion Java language version used in the project.
|
||||||
* @param currentEdition name of the edition associated with the Enso
|
* @param currentEdition name of the edition associated with the Enso
|
||||||
* version; this should be removed once #1831 is
|
* version; this should be removed once #1831 is
|
||||||
* implemented
|
* implemented
|
||||||
@ -30,6 +31,7 @@ object BuildInfo {
|
|||||||
ensoVersion: String,
|
ensoVersion: String,
|
||||||
scalacVersion: String,
|
scalacVersion: String,
|
||||||
graalVersion: String,
|
graalVersion: String,
|
||||||
|
javaVersion: String,
|
||||||
currentEdition: String
|
currentEdition: String
|
||||||
): Seq[File] = {
|
): Seq[File] = {
|
||||||
val gitInfo = getGitInformation(log).getOrElse(fallbackGitInformation)
|
val gitInfo = getGitInformation(log).getOrElse(fallbackGitInformation)
|
||||||
@ -58,6 +60,10 @@ object BuildInfo {
|
|||||||
| return "${graalVersion}";
|
| return "${graalVersion}";
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
|
| static String javaVersion() {
|
||||||
|
| return "${javaVersion}";
|
||||||
|
| }
|
||||||
|
|
|
||||||
| static String currentEdition() {
|
| static String currentEdition() {
|
||||||
| return "${currentEdition}";
|
| return "${currentEdition}";
|
||||||
| }
|
| }
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
Copyright (C) 2015-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2016-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2017-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2018-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2019-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2020-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2021-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright 2009-2020 Lightbend Inc. <http://www.lightbend.com>
|
|
@ -1,6 +0,0 @@
|
|||||||
Copyright (C) 2008-2017 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
|
||||||
Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev
|
|
||||||
Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright 2011 Mark Harrah, Eugene Yokota
|
|
||||||
Copyright 2014 Twitter, Inc.
|
|
||||||
Copyright 2015 Heiko Seeberger
|
|
@ -1,6 +0,0 @@
|
|||||||
Copyright (C) 2009-2020 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2015-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2017-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2018-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (C) 2020-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
@ -1 +0,0 @@
|
|||||||
Copyright (C) 2009-2020 Lightbend Inc. <http://www.lightbend.com>
|
|
@ -1,2 +0,0 @@
|
|||||||
Copyright (C) 2019-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (c) 2013-14 Miles Sabin
|
|
@ -1,4 +0,0 @@
|
|||||||
Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev
|
|
||||||
Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
|
||||||
Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
|
|
||||||
Copyright (c) 2011-13 Miles Sabin
|
|
@ -1,3 +1,3 @@
|
|||||||
5BE1C47CDA76AF7E6C42089993BEA2B8DB544C1752AE5D8055BF2B4E713B20EA
|
BBB2B5E440C388A022983CB2C0B9B4BA68D04B97FC07E4C8E142952448437BE0
|
||||||
E92B79099FF706DC1F50287D428322268954285BD62F19B0A70456E3356AE1D1
|
CA8B1BB2992E828BA958FD6CFC0076B213170FCD454406131407ED0340EC7F2F
|
||||||
0
|
0
|
||||||
|
Loading…
Reference in New Issue
Block a user