Skip to content

Commit

Permalink
Add fallback to scalac when JVM for Bloop cannot be downloaded
Browse files Browse the repository at this point in the history
  • Loading branch information
MaciejG604 committed Oct 9, 2023
1 parent 332ad1e commit a254163
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,7 @@ object WarningMessages {

val offlineModeBloopNotFound =
"Offline mode is ON and Bloop could not be fetched from the local cache, using scalac as fallback"

val offlineModeBloopJvmNotFound =
"Offline mode is ON and a JVM for Bloop could not be fetched from the local cache, using scalac as fallback"
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object Bloop extends ScalaCommand[BloopOptions] {
.map(JvmUtils.downloadJvm(_, options))
.getOrElse {
JvmUtils.getJavaCmdVersionOrHigher(17, options)
}
}.orExit(logger)

opts.compilationServer.bloopRifleConfig(
opts.global.logging.logger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ object PgpExternalCommand {
JvmUtils.getJavaCmdVersionOrHigher(
scalaCliSigningJvmVersion,
buildOptions
)
).orThrow

launcher(
cache,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import scala.build.Ops.EitherOptOps
import scala.build.*
import scala.build.compiler.{BloopCompilerMaker, ScalaCompilerMaker, SimpleScalaCompilerMaker}
import scala.build.directives.DirectiveDescription
import scala.build.errors.{AmbiguousPlatformError, BuildException, ConfigDbException}
import scala.build.errors.{AmbiguousPlatformError, BuildException, ConfigDbException, Severity}
import scala.build.input.{Element, Inputs, ResourceDirectory, ScalaCliInvokeData}
import scala.build.interactive.Interactive
import scala.build.interactive.Interactive.{InteractiveAsk, InteractiveNop}
import scala.build.internal.util.ConsoleUtils.ScalaCliConsole
import scala.build.internal.util.WarningMessages
import scala.build.internal.{Constants, FetchExternalBinary, ObjectCodeWrapper, OsLibc, Util}
import scala.build.options.ScalaVersionUtil.fileWithTtl0
import scala.build.options.{ComputeVersion, Platform, ScalacOpt, ShadowingSeq}
Expand Down Expand Up @@ -514,15 +515,19 @@ final case class SharedOptions(

def bloopRifleConfig(): Either[BuildException, BloopRifleConfig] = either {
val options = value(buildOptions(false, None))
lazy val defaultJvmCmd =
JvmUtils.downloadJvm(OsLibc.baseDefaultJvm(OsLibc.jvmIndexOs, "17"), options)
val javaCmd = compilationServer.bloopJvm.map(JvmUtils.downloadJvm(_, options)).orElse {
for (javaHome <- options.javaHomeLocationOpt()) yield {
val (javaHomeVersion, javaHomeCmd) = OsLibc.javaHomeVersion(javaHome.value)
if (javaHomeVersion >= 17) javaHomeCmd
else defaultJvmCmd
}
}.getOrElse(defaultJvmCmd)
lazy val defaultJvmCmd = value {
JvmUtils.downloadJvm(OsLibc.defaultJvm(OsLibc.jvmIndexOs), options)
}

val javaCmd = compilationServer.bloopJvm
.map(jvmId => value(JvmUtils.downloadJvm(jvmId, options)))
.orElse {
for (javaHome <- options.javaHomeLocationOpt()) yield {
val (javaHomeVersion, javaHomeCmd) = OsLibc.javaHomeVersion(javaHome.value)
if (javaHomeVersion >= 17) javaHomeCmd
else defaultJvmCmd
}
}.getOrElse(defaultJvmCmd)

compilationServer.bloopRifleConfig(
logging.logger,
Expand All @@ -537,19 +542,25 @@ final case class SharedOptions(
def compilerMaker(
threads: BuildThreads,
scaladoc: Boolean = false
): Either[BuildException, ScalaCompilerMaker] = either {
): Either[BuildException, ScalaCompilerMaker] =
if (scaladoc)
SimpleScalaCompilerMaker("java", Nil, scaladoc = true)
Right(SimpleScalaCompilerMaker("java", Nil, scaladoc = true))
else if (compilationServer.server.getOrElse(true))
new BloopCompilerMaker(
value(bloopRifleConfig()),
threads.bloop,
strictBloopJsonCheckOrDefault,
coursier.offline.getOrElse(false)
)
bloopRifleConfig() match {
case Right(config) =>
Right(new BloopCompilerMaker(
config,
threads.bloop,
strictBloopJsonCheckOrDefault,
coursier.offline.getOrElse(false)
))
case Left(ex) if coursier.offline.contains(true) =>
logger.diagnostic(WarningMessages.offlineModeBloopJvmNotFound, Severity.Warning)
Right(SimpleScalaCompilerMaker("java", Nil))
case Left(ex) => Left(ex)
}
else
SimpleScalaCompilerMaker("java", Nil)
}
Right(SimpleScalaCompilerMaker("java", Nil))

lazy val coursierCache = coursier.coursierCache(logging.logger.coursierLogger(""))

Expand Down
40 changes: 23 additions & 17 deletions modules/cli/src/main/scala/scala/cli/commands/util/JvmUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ package util
import java.io.File

import scala.build.EitherCps.{either, value}
import scala.build.errors.{BuildException, UnrecognizedDebugModeError}
import scala.build.errors.{BuildException, JvmDownloadError, UnrecognizedDebugModeError}
import scala.build.internal.CsLoggerUtil.*
import scala.build.internal.OsLibc
import scala.build.options.{JavaOpt, JavaOptions, ShadowingSeq}
import scala.build.{Os, Position, Positioned, options as bo}
import scala.cli.commands.shared.{CoursierOptions, SharedJvmOptions, SharedOptions}
import scala.concurrent.ExecutionContextExecutorService
import scala.util.Properties
import scala.util.control.NonFatal
import scala.util.{Failure, Properties, Success, Try}

object JvmUtils {
def javaOptions(opts: SharedJvmOptions): Either[BuildException, JavaOptions] = either {
Expand Down Expand Up @@ -67,38 +67,43 @@ object JvmUtils {
)
}

def downloadJvm(jvmId: String, options: bo.BuildOptions): String = {
def downloadJvm(jvmId: String, options: bo.BuildOptions): Either[BuildException, String] = {
implicit val ec: ExecutionContextExecutorService = options.finalCache.ec
val javaHomeManager = options.javaHomeManager
.withMessage(s"Downloading JVM $jvmId")
val logger = javaHomeManager.cache
.flatMap(_.archiveCache.cache.loggerOpt)
.getOrElse(_root_.coursier.cache.CacheLogger.nop)
val command = {
val path = logger.use {
try javaHomeManager.get(jvmId).unsafeRun()
catch {
case NonFatal(e) => throw new Exception(e)
}
}
os.Path(path)

val javaHomePathOrError = Try(javaHomeManager.get(jvmId).unsafeRun()) match {
case Success(path) => Right(path)
case Failure(e) => Left(JvmDownloadError(jvmId, e))
}

for {
javaHomePath <- javaHomePathOrError
} yield {
val javaHome = os.Path(javaHomePath)
val ext = if (Properties.isWin) ".exe" else ""
val javaCmd = (javaHome / "bin" / s"java$ext").toString
javaCmd
}
val ext = if (Properties.isWin) ".exe" else ""
val javaCmd = (command / "bin" / s"java$ext").toString
javaCmd
}

def getJavaCmdVersionOrHigher(
javaVersion: Int,
options: bo.BuildOptions
): String = {
): Either[BuildException, String] = {
val javaHomeCmdOpt = for {
javaHome <- options.javaHomeLocationOpt()
(javaHomeVersion, javaHomeCmd) = OsLibc.javaHomeVersion(javaHome.value)
if javaHomeVersion >= javaVersion
} yield javaHomeCmd

javaHomeCmdOpt.getOrElse(downloadJvm(javaVersion.toString, options))
javaHomeCmdOpt match {
case Some(cmd) => Right(cmd)
case None => downloadJvm(javaVersion.toString, options)
}
}

def getJavaCmdVersionOrHigher(
Expand All @@ -110,6 +115,7 @@ object JvmUtils {

for {
options <- sharedOpts.buildOptions()
} yield getJavaCmdVersionOrHigher(javaVersion, options)
javaCmd <- getJavaCmdVersionOrHigher(javaVersion, options)
} yield javaCmd
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package scala.build.errors

import scala.build.Position

final class JvmDownloadError(jvmId: String, cause: Throwable)
extends BuildException(
s"Cannot download JVM: $jvmId",
cause = cause
)

0 comments on commit a254163

Please sign in to comment.