Skip to content

Commit

Permalink
Java and Graal versions are checked before the build starts (#9106)
Browse files Browse the repository at this point in the history
Add checks of Java and GraalVM versions before the `sbt` project is fully loaded. This ensures that all the devs have exactly the version specified in our `build.sbt`.

# Important Notes
Trying to start `sbt` with a different java versions now results in:

```
$ java -version
openjdk version "21" 2023-09-19
OpenJDK Runtime Environment GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15)
OpenJDK 64-Bit Server VM GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing)
$ sbt
[info] welcome to sbt 1.9.7 (GraalVM Community Java 21)
[info] loading settings for project enso-build from plugins.sbt ...
[info] loading project definition from /home/pavel/dev/enso/project
[info] loading settings for project enso from build.sbt ...
[info] resolving key references (65272 settings) ...
[info] set current project to enso (in build file:/home/pavel/dev/enso/)
[error] Running on GraalVM version 21. Expected GraalVM version 21.0.2.
[error] Total time: 0 s, completed Feb 20, 2024, 1:06:18 PM
[warn] Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)
```

```
$ java -version
openjdk version "17.0.10" 2024-01-16
OpenJDK Runtime Environment JBR-17.0.10+1-1087.17-jcef (build 17.0.10+1-b1087.17)
OpenJDK 64-Bit Server VM JBR-17.0.10+1-1087.17-jcef (build 17.0.10+1-b1087.17, mixed mode)
$ sbt
[info] welcome to sbt 1.9.7 (JetBrains s.r.o. Java 17.0.10)
[info] loading settings for project enso-build from plugins.sbt ...
[info] loading project definition from /home/pavel/dev/enso/project
[info] compiling 44 Scala sources to /home/pavel/dev/enso/project/target/scala-2.12/sbt-1.0/classes ...
[info] loading settings for project enso from build.sbt ...
[info] resolving key references (65272 settings) ...
[info] set current project to enso (in build file:/home/pavel/dev/enso/)
[warn] Running on non-GraalVM JVM (The actual java.vendor is JetBrains s.r.o.). Expected GraalVM Community java.vendor.
[error] Running on Java version 17. Expected Java version 21.
[error] Total time: 0 s, completed Feb 20, 2024, 1:07:40 PM
[warn] Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)
```
  • Loading branch information
Akirathan committed Feb 21, 2024
1 parent d415d13 commit 9daca28
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

env:
# Please ensure that this is in sync with graalVersion in build.sbt
javaVersion: 21.0.1
javaVersion: 21.0.2
# Please ensure that this is in sync with project/build.properties
sbtVersion: 1.9.7

Expand Down
21 changes: 18 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,24 @@ val currentEdition = sys.env.getOrElse(
val stdLibVersion = defaultDevEnsoVersion
val targetStdlibVersion = ensoVersion

Global / onLoad := GraalVM.addVersionCheck(
graalMavenPackagesVersion
)((Global / onLoad).value)
lazy val graalVMVersionCheck = taskKey[Unit]("Check GraalVM and Java versions")
graalVMVersionCheck := {
GraalVM.versionCheck(
graalVersion,
graalMavenPackagesVersion,
javaVersion,
state.value.log
)
}

// Inspired by https://www.scala-sbt.org/1.x/docs/Howto-Startup.html#How+to+take+an+action+on+startup
lazy val startupStateTransition: State => State = { s: State =>
"graalVMVersionCheck" :: s
}
Global / onLoad := {
val old = (Global / onLoad).value
startupStateTransition compose old
}

/* Note [Engine And Launcher Version]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
74 changes: 58 additions & 16 deletions project/GraalVM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,67 @@ object GraalVM {
*
* @param graalVersion the GraalVM version that should be used for
* building this project
* @param oldTransition the state transition to be augmented
* @param graalPackagesVersion Version of Truffle and GraalVM packages that
* will be downloaded from Maven
* @param javaVersion Version of the Java source code
* @return an augmented state transition that does all the state changes of
* oldTransition but also runs the version checks
*/
def addVersionCheck(
graalVersion: String
)(
oldTransition: State => State
): State => State =
(state: State) => {
val newState = oldTransition(state)
val logger = newState.log
if (graalVersion != version) {
logger.error("GraalVM version check failed.")
throw new IllegalStateException(
s"Expected GraalVM version $version, but got $graalVersion. " +
s"Version specified in build.sbt and GraalVM.scala must be in sync"
def versionCheck(
graalVersion: String,
graalPackagesVersion: String,
javaVersion: String,
log: ManagedLogger
): Unit = {
if (graalPackagesVersion != version) {
log.error(
s"Expected GraalVM packages version $version, but got $graalPackagesVersion. " +
s"Version specified in build.sbt and GraalVM.scala must be in sync"
)
throw new IllegalStateException("GraalVM version check failed")
}
val javaVendor = System.getProperty("java.vendor")
if (javaVendor != "GraalVM Community") {
log.warn(
s"Running on non-GraalVM JVM (The actual java.vendor is $javaVendor). " +
s"Expected GraalVM Community java.vendor."
)
}

val javaSpecVersion = System.getProperty("java.specification.version")
if (javaSpecVersion != javaVersion) {
log.error(
s"Running on Java version $javaSpecVersion. " +
s"Expected Java version $javaVersion."
)
throw new IllegalStateException("java.specification.vendor check failed")
}

val vmVersion = System.getProperty("java.vm.version")
tryParseJavaVMVersion(vmVersion) match {
case Some(version) =>
if (version != graalVersion) {
log.error(
s"Running on GraalVM version $version. " +
s"Expected GraalVM version $graalVersion."
)
throw new IllegalStateException("java.vm.version check failed")
}
case None =>
log.error(
s"Could not parse GraalVM version from java.vm.version: $vmVersion."
)
}
newState
throw new IllegalStateException("java.vm.version check failed")
}
}

private def tryParseJavaVMVersion(
version: String
): Option[String] = {
if (version.contains('+')) {
Some(version.split('+')(0))
} else {
None
}
}
}

0 comments on commit 9daca28

Please sign in to comment.