From b0b34dfcec2990dbb52ee7608f15cac3cbe60af2 Mon Sep 17 00:00:00 2001 From: Mirco Dotta Date: Fri, 22 Dec 2017 17:44:30 +0100 Subject: [PATCH] Hydra Scala version detection heuristic fallbacks to module SDK version. Fix #37 Our heuristic for extracting the scala version from the scala-compiler jar name may not work if the scala-compiler jar in the classpath has no version happended (this for instance can happen when importing an sbt project with the `scalaHome` setting set to point to a locally installed Scala distribution). The implemented solution consists in falling back to the module SDK Scala version if the version cannot be extracted from the scala-compiler jar name. --- .../plugins/hydra/HydraVersions.scala | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/scala/scala-impl/src/org/jetbrains/plugins/hydra/HydraVersions.scala b/scala/scala-impl/src/org/jetbrains/plugins/hydra/HydraVersions.scala index e73a361761f..6a7e9beb93b 100644 --- a/scala/scala-impl/src/org/jetbrains/plugins/hydra/HydraVersions.scala +++ b/scala/scala-impl/src/org/jetbrains/plugins/hydra/HydraVersions.scala @@ -1,10 +1,8 @@ package org.jetbrains.plugins.hydra import com.intellij.openapi.diagnostic.Logger -import org.jetbrains.plugins.scala.project.{ProjectExt, ScalaModule, Version} import com.intellij.openapi.project.Project - -import scala.collection.breakOut +import org.jetbrains.plugins.scala.project.{ProjectExt, ScalaModule, ScalaSdk, Version} /** * @author Maris Alexandru @@ -14,31 +12,50 @@ object HydraVersions { val DefaultHydraVersion = "0.9.7" private val MinScalaVersion = "2.11.8" private val UnsupportedScalaVersion = "2.12.0" - private val CompilerRegex = """.*scala-compiler-(\d+\.\d+\.\d+)(-SNAPSHOT)?\.jar""".r + private val CompilerJarName = "scala-compiler" + private val CompilerVersionRegex = """.*scala-compiler-(\d+\.\d+\.\d+)(-SNAPSHOT)?\.jar""".r private final val Log: Logger = Logger.getInstance(this.getClass.getName) def getSupportedScalaVersions(project: Project): Seq[String] = { val scalaModules = project.scalaModules - // we can't use `module.sdk.compilerVersion` because it assumes the *name* of the Sdk library - // matches `SDK-2.12.3` or the like. For the Scala project this is simply called `starr`, so we - // need to look inside and retrieve the actual classpath entries - val scalaVersionsPerModule: Map[ScalaModule, String] = (for { + val module2scalaVersion: Map[ScalaModule, String] = (for { module <- scalaModules - classpathFile <- module.sdk.compilerClasspath - mtch <- CompilerRegex.findFirstMatchIn(classpathFile.getName) - scalaVersion = mtch.group(1) - if scalaVersion != UnsupportedScalaVersion - version = Version(scalaVersion) - if version >= Version(MinScalaVersion) - } yield module -> version.presentation)(breakOut) - - if (scalaModules.size != scalaVersionsPerModule.size) { - // we have some modules that don't have a scala version, we should log it - for (module <- scalaModules.filterNot(scalaVersionsPerModule.contains)) - Log.info(s"Could not retrieve Scala version in module '${module.getName}' with compiler classpath: ${module.sdk.compilerClasspath}") + scalaVersion <- findScalaVersionInClasspath(module.sdk) + } yield module -> scalaVersion)(collection.breakOut) + + val (supported, unsupported) = module2scalaVersion.foldLeft(Map.empty[ScalaModule, String] -> Map.empty[ScalaModule, String]) { (acc, e) => + val (supported, unsupported) = acc + val (module, scalaVersion) = e + if (scalaVersion != UnsupportedScalaVersion && Version(scalaVersion) >= Version(MinScalaVersion)) + (supported + e) -> unsupported + else + supported -> (unsupported + e) + } + + if (unsupported.nonEmpty) { + // we have some modules that use a Scala version we don't support + for((module, scalaVersion) <- unsupported) + Log.info(s"Cannot enable Hydra on module '${module.getName}' because its Scala version ($scalaVersion) is unsupported. The module compiler classpath is: ${module.sdk.compilerClasspath}") } - scalaVersionsPerModule.values.toSeq.distinct + supported.values.toList.distinct + } + + private def findScalaVersionInClasspath(sdk: ScalaSdk): Option[String] = { + // we can't use `module.sdk.compilerVersion` because it assumes the *name* of the Sdk library + // matches `SDK-2.12.3` or the like. For the Scala project this is simply called `starr`, so we + // need to look inside and retrieve the actual classpath entries + val maybeScalaVersion = for { + compiler <- sdk.compilerClasspath.find(_.getName.contains(CompilerJarName)) + matchedJar <- CompilerVersionRegex.findFirstMatchIn(compiler.getName) + version <- Option(matchedJar.group(1)) + } yield version + + // However, if the user has set the scalaHome in his sbt build, then the scala-compiler jar in + // the compiler classpath will likely not have the version happended, and hence the above heuristic + // for determining the scala version won't work. Hence, if no version is found, let's still fallback + // to using the sdk.compilerVersion. + maybeScalaVersion.orElse(sdk.compilerVersion) } }