Skip to content

Commit

Permalink
Hydra Scala version detection heuristic fallbacks to module SDK versi…
Browse files Browse the repository at this point in the history
…on. Fix triplequote#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.
  • Loading branch information
dotta committed Dec 23, 2017
1 parent 6e440b0 commit 8e58156
Showing 1 changed file with 38 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
}
}

0 comments on commit 8e58156

Please sign in to comment.