enso/project/CopyTruffleJAR.scala
2020-07-01 13:21:13 +02:00

132 lines
4.3 KiB
Scala

import sbt.Keys._
import sbt._
import sbt.internal.util.ManagedLogger
object CopyTruffleJAR {
/**
* The task that is used for copying the Truffle JAR file to our target
* directory. It should be ran when setting-up the project and after each
* update of Graal version.
*
* As the JARs have to be available to the sbt JVM on startup, to ensure the
* JARs are available, the whole sbt process must be restarted (otherwise the
* compilation would fail with cryptic errors). To make sure that the user
* restarts the process, it is terminated.
*/
lazy val bootstrapJARs = Def.task {
val log = streams.value.log
if (
ensureTruffleJARUpToDate(
baseDirectory.value,
(Compile / update).value,
log
)
) {
log.info("Truffle JARs have been updated.")
System.err.println(
"You have to restart the sbt JVM for the changes to take effect."
)
System.out.flush()
System.err.flush()
System.exit(0)
} else {
log.info("Truffle JARs are up to date.")
}
}
/**
* This task should be added as a dependency of compileInputs in the runtime
* subproject. It ensures that the compilation will not proceed unless the
* JARs have not been bootstrapped. If the JARs were out of date, they are
* updated within this task, so bootstrap does not have to be re-run.
* However, for the same reasons as for [[bootstrapJARs]], the sbt process is
* terminated, because a restart is required.
*/
lazy val preCompileTask = Def.task {
val log = streams.value.log
if (
ensureTruffleJARUpToDate(
baseDirectory.value,
(Compile / update).value,
log
)
) {
log.error(
"JARs that have to be loaded by the sbt JVM at startup have been" +
" modified or did not exist.\n" +
"Did you run bootstrap?"
)
log.warn(
"Bootstrap has been triggered automatically, but the sbt JVM must be" +
" restarted to apply the changes, so the compilation had to be stopped."
)
log.warn(
"To avoid disrupting compilation, remember to run bootstrap when " +
"setting up the project and after each version change of Graal."
)
System.err.println(
"The sbt JVM has to be restarted to apply the changes.\n" +
"Please re-launch sbt and re-run the last command."
)
System.out.flush()
System.err.flush()
System.exit(0)
}
}
/**
* Checks the Truffle JARs and updates them if necessary.
*
* @param libraryUpdates the value of Compile / updates
* @return true if an update has been performed and the JVM needs a restart
*/
private def ensureTruffleJARUpToDate(
baseDirectory: File,
libraryUpdates: UpdateReport,
log: ManagedLogger
): Boolean = {
var truffleInstancesFound = 0
var restartRequired = false
libraryUpdates.allFiles.foreach { f =>
if (f.getName.contains("truffle-api")) {
truffleInstancesFound += 1
val dest = baseDirectory / "build-cache" / "truffle-api.jar"
val needsUpdate = if (!dest.exists()) {
log.debug("truffle-api.jar does not exist in target/")
true
} else if (dest.lastModified() < f.lastModified()) {
log.debug("truffle-api.jar in target/ is out of date")
true
} else false
if (needsUpdate) {
IO.copyFile(f, dest)
restartRequired = true
}
}
}
if (truffleInstancesFound == 0) {
throw new IllegalStateException(
"Truffle API has not been found in the dependencies!\n" +
"If dependencies have been changed in build.sbt, make sure " +
"the algorithm locating truffle-api.jar in" +
" project/CopyTruffleJAR.scala has been updated accordingly.\n" +
"Please report this as a bug."
)
} else if (truffleInstancesFound > 1) {
throw new IllegalStateException(
"More than one version of Truffle API has been found in the " +
"dependencies.\n" +
"If dependencies have been changed in build.sbt, make sure " +
"the algorithm locating truffle-api.jar in" +
" project/CopyTruffleJAR.scala has been updated accordingly.\n" +
"Please report this as a bug."
)
}
restartRequired
}
}