Skip to content

Commit

Permalink
Install Required GraalVM Components (#1651)
Browse files Browse the repository at this point in the history
Project manager ensures that the required 
GraalVM components are installed.
  • Loading branch information
4e6 authored and iamrecursion committed Apr 7, 2021
1 parent d75b56d commit a94590d
Show file tree
Hide file tree
Showing 17 changed files with 501 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import org.enso.launcher.cli.{
GlobalCLIOptions
}
import org.enso.runtimeversionmanager.components.{
GraalVMComponentConfiguration,
InstallerKind,
RuntimeComponentConfiguration,
RuntimeComponentUpdaterFactory,
RuntimeVersionManager
}
import org.enso.runtimeversionmanager.distribution.{
Expand Down Expand Up @@ -43,6 +46,10 @@ object DefaultManagers {
lazy val temporaryDirectoryManager =
new TemporaryDirectoryManager(distributionManager, defaultResourceManager)

/** Default [[RuntimeComponentConfiguration]]. */
lazy val componentConfig: RuntimeComponentConfiguration =
new GraalVMComponentConfiguration

/** Creates a [[RuntimeVersionManager]] that uses the default distribution. */
def runtimeVersionManager(
globalCLIOptions: GlobalCLIOptions,
Expand All @@ -58,6 +65,8 @@ object DefaultManagers {
defaultResourceManager,
EngineRepository.defaultEngineReleaseProvider,
GraalCEReleaseProvider.default,
componentConfig,
RuntimeComponentUpdaterFactory.Default,
InstallerKind.Launcher
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package org.enso.projectmanager.versionmanagement
import com.typesafe.scalalogging.LazyLogging
import org.enso.runtimeversionmanager.Environment
import org.enso.runtimeversionmanager.components.{
GraalVMComponentConfiguration,
InstallerKind,
RuntimeComponentConfiguration,
RuntimeComponentUpdaterFactory,
RuntimeVersionManagementUserInterface,
RuntimeVersionManager
}
Expand Down Expand Up @@ -52,6 +55,12 @@ object DefaultDistributionConfiguration
lazy val temporaryDirectoryManager =
new TemporaryDirectoryManager(distributionManager, resourceManager)

lazy val componentConfiguration: RuntimeComponentConfiguration =
new GraalVMComponentConfiguration

lazy val runtimeComponentUpdaterFactory: RuntimeComponentUpdaterFactory =
RuntimeComponentUpdaterFactory.Default

/** @inheritdoc */
def engineReleaseProvider: ReleaseProvider[EngineRelease] =
EngineRepository.defaultEngineReleaseProvider
Expand All @@ -67,6 +76,8 @@ object DefaultDistributionConfiguration
resourceManager = resourceManager,
engineReleaseProvider = engineReleaseProvider,
runtimeReleaseProvider = GraalCEReleaseProvider.default,
componentConfig = componentConfiguration,
componentUpdaterFactory = runtimeComponentUpdaterFactory,
installerKind = InstallerKind.ProjectManager
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.nio.file.Path

import org.enso.projectmanager.versionmanagement.DistributionConfiguration
import org.enso.runtimeversionmanager.components.{
GraalVMComponentConfiguration,
InstallerKind,
RuntimeVersionManagementUserInterface,
RuntimeVersionManager
Expand All @@ -30,6 +31,7 @@ import org.enso.runtimeversionmanager.runner.{JVMSettings, JavaCommand}
import org.enso.runtimeversionmanager.test.{
FakeEnvironment,
HasTestDirectory,
NoopComponentUpdaterFactory,
TestLocalLockManager
}

Expand Down Expand Up @@ -67,6 +69,10 @@ class TestDistributionConfiguration(
lazy val temporaryDirectoryManager =
new TemporaryDirectoryManager(distributionManager, resourceManager)

lazy val componentConfig = new GraalVMComponentConfiguration

lazy val componentUpdaterFactory = NoopComponentUpdaterFactory

override def makeRuntimeVersionManager(
userInterface: RuntimeVersionManagementUserInterface
): RuntimeVersionManager = new RuntimeVersionManager(
Expand All @@ -76,6 +82,8 @@ class TestDistributionConfiguration(
resourceManager = resourceManager,
engineReleaseProvider = engineReleaseProvider,
runtimeReleaseProvider = runtimeReleaseProvider,
componentConfig = componentConfig,
componentUpdaterFactory = componentUpdaterFactory,
installerKind = InstallerKind.ProjectManager
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.enso.runtimeversionmanager.test

import org.enso.runtimeversionmanager.OS
import org.enso.runtimeversionmanager.components.{
GraalRuntime,
RuntimeComponentUpdater,
RuntimeComponentUpdaterFactory
}

/** Test factory creating a noop updater. */
object NoopComponentUpdaterFactory extends RuntimeComponentUpdaterFactory {

/** @inheritdoc */
override def build(runtime: GraalRuntime, os: OS): RuntimeComponentUpdater =
NoopComponentUpdater
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import nl.gn0s1s.bump.SemVer
import org.enso.pkg.{PackageManager, SemVerEnsoVersion}
import org.enso.runtimeversionmanager._
import org.enso.runtimeversionmanager.components.{
GraalVMComponentConfiguration,
InstallerKind,
RuntimeVersionManagementUserInterface,
RuntimeVersionManager
Expand Down Expand Up @@ -53,6 +54,7 @@ class RuntimeVersionManagerTest
val resourceManager = TestLocalResourceManager.create()
val temporaryDirectoryManager =
new TemporaryDirectoryManager(distributionManager, resourceManager)
val componentConfig = new GraalVMComponentConfiguration

val runtimeVersionManager = new RuntimeVersionManager(
userInterface,
Expand All @@ -61,6 +63,8 @@ class RuntimeVersionManagerTest
resourceManager,
engineProvider,
runtimeProvider,
componentConfig,
NoopComponentUpdaterFactory,
installerKind
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.enso.cli.task.TaskProgress
import org.enso.runtimeversionmanager.FileSystem.PathSyntax
import org.enso.runtimeversionmanager._
import org.enso.runtimeversionmanager.components.{
GraalVMComponentConfiguration,
GraalVMVersion,
InstallerKind,
Manifest,
Expand Down Expand Up @@ -146,13 +147,16 @@ class ConcurrencyTest

val temporaryDirectoryManager =
new TemporaryDirectoryManager(distributionManager, resourceManager)
val componentConfig = new GraalVMComponentConfiguration
val componentsManager = new RuntimeVersionManager(
TestRuntimeVersionManagementUserInterface.default,
distributionManager,
temporaryDirectoryManager,
resourceManager,
engineProvider,
runtimeProvider,
componentConfig,
NoopComponentUpdaterFactory,
InstallerKind.Launcher
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.enso.runtimeversionmanager.components

import org.enso.runtimeversionmanager.OS

/** Component configuration of the GraalVM distribution. */
class GraalVMComponentConfiguration extends RuntimeComponentConfiguration {

import GraalVMComponentConfiguration._

/** @inheritdoc */
override def getRequiredComponents(
version: GraalVMVersion,
os: OS
): Seq[GraalVMComponent] =
version.graalVersion match {
case GraalVersions.Major(v) if v > 20 && os.hasSulongSupport =>
Seq(GraalVMComponent.python, GraalVMComponent.R)
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
}
}

private object GraalVersions {

/** Get the major Graal version number. */
object Major {
def unapply(version: String): Option[Int] = {
version.takeWhile(_ != '.').toIntOption
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.enso.runtimeversionmanager.components

import java.nio.file.Path

import org.enso.runtimeversionmanager.OS

import scala.sys.process._
import scala.util.{Success, Try}

/** Module that manages components of the GraalVM distribution.
*
* @param runtime the GraalVM runtime
* @param os the operating system
*/
class GraalVMComponentUpdater(runtime: GraalRuntime, os: OS)
extends RuntimeComponentUpdater {

import GraalVMComponentUpdater._

/** List the installed GraalVM components.
*
* @return the list of installed GraalVM components
*/
override def list: Try[Seq[GraalVMComponent]] = {
val suppressStderr = ProcessLogger(_ => ())
val process = Process(
Seq[String](Paths.gu, "list", "-v"),
Some(runtime.path.toFile),
("JAVA_HOME", runtime.path),
("GRAALVM_HOME", runtime.path)
)

for {
lines <- Try(process.lazyLines(suppressStderr))
} yield ListOut.parse(lines)
}

/** 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 componentsList = components.map(_.id)
val process = Process(
Seq[String](Paths.gu, "install") ++ componentsList,
Some(runtime.path.toFile),
("JAVA_HOME", runtime.path),
("GRAALVM_HOME", runtime.path)
)
Try(process.!!)
} else {
Success(())
}
}

private object Paths {

/** Path to `gu` executable. */
val gu: Path = os match {
case OS.Linux => runtime.path / "bin" / "gu"
case OS.MacOS => runtime.path / "bin" / "gu"
case OS.Windows => runtime.path / "bin" / "gu.cmd"
}
}
}
object GraalVMComponentUpdater {

implicit private def pathToString(path: Path): String =
path.toAbsolutePath.toString

implicit private class PathExtensions(path: Path) {

def /(child: String): Path = path.resolve(child)
}

/** 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(_))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.enso.runtimeversionmanager.components

import org.enso.runtimeversionmanager.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]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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]
}
Loading

0 comments on commit a94590d

Please sign in to comment.