sbt.internal.inc.ScalaInstance.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zinc-classpath_2.11 Show documentation
Show all versions of zinc-classpath_2.11 Show documentation
Incremental compiler of Scala
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
package sbt
package internal
package inc
import java.io.File
import xsbti.ArtifactInfo.{ ScalaCompilerID, ScalaLibraryID, ScalaOrganization }
import sbt.io.IO
/**
* Represents the source for Scala classes for a given version. The reason both a ClassLoader and the jars are required
* is that the compiler requires the location of the library jar on the (boot)classpath and the loader is used
* for the compiler itself.
* The 'version' field is the version used to obtain the Scala classes. This is typically the version for the maven repository.
* The 'actualVersion' field should be used to uniquely identify the compiler. It is obtained from the compiler.properties file.
*
* This should be constructed via the ScalaInstance.apply methods. The primary constructor is deprecated.
*/
final class ScalaInstance(val version: String, val loader: ClassLoader,
val libraryJar: File,
val compilerJar: File,
val allJars: Array[File],
val explicitActual: Option[String]) extends xsbti.compile.ScalaInstance {
/**
* This tells us if the scalaInstance is from a managed (i.e. ivy-resolved) scala *or*
* if it's a free-floating ScalaInstance, in which case we need to do tricks to the classpaths we find
* because it won't be on them.
*/
final def isManagedVersion = explicitActual.isDefined
def otherJars = (allJars.toSet - libraryJar - compilerJar).toArray
require(version.indexOf(' ') < 0, "Version cannot contain spaces (was '" + version + "')")
/** Gets the version of Scala in the compiler.properties file from the loader. This version may be different than that given by 'version'*/
lazy val actualVersion = explicitActual getOrElse ScalaInstance.actualVersion(loader)("\n version " + version + ", " + jarStrings)
def jarStrings = "library jar: " + libraryJar + ", compiler jar: " + compilerJar
override def toString = "Scala instance{version label " + version + ", actual version " + actualVersion + ", " + jarStrings + "}"
}
object ScalaInstance {
val ScalaOrg = ScalaOrganization
val VersionPrefix = "version "
def isDotty(version: String): Boolean =
// We rely on the fact that the first public version of Scala was 1.0 and
// that Dotty will keep being version 0.x for a long time.
version.startsWith("0.")
def apply(org: String, version: String, launcher: xsbti.Launcher): ScalaInstance =
// Due to incompatibility with previous launchers if scalaOrg has default value revert to an existing method
if (org == ScalaOrg)
apply(version, launcher)
else try {
apply(version, launcher.getScala(version, "", org))
} catch {
case x: NoSuchMethodError => sys.error("Incompatible version of the xsbti.Launcher interface. Use an sbt 0.12+ launcher instead.")
}
/** Creates a ScalaInstance using the given provider to obtain the jars and loader.*/
def apply(version: String, launcher: xsbti.Launcher): ScalaInstance =
apply(version, launcher.getScala(version))
def apply(version: String, provider: xsbti.ScalaProvider): ScalaInstance = {
val libraryJar = provider.jars find (_.getName == "scala-library.jar") getOrElse (throw new InvalidScalaProvider("Couldn't find 'scala-library.jar'"))
val compilerJar = provider.jars find (_.getName == "scala-compiler.jar") getOrElse (throw new InvalidScalaProvider("Couldn't find 'scala-compiler.jar'"))
new ScalaInstance(version, provider.loader, libraryJar, compilerJar, provider.jars.toArray, None)
}
def apply(scalaHome: File, launcher: xsbti.Launcher): ScalaInstance =
apply(scalaHome)(scalaLoader(launcher))
def apply(scalaHome: File)(classLoader: List[File] => ClassLoader): ScalaInstance = {
val all = allJars(scalaHome)
val loader = classLoader(all.toList)
val library = libraryJar(scalaHome)
val version = actualVersion(loader)(" (library jar " + library.getAbsolutePath + ")")
new ScalaInstance(version, loader, library, compilerJar(scalaHome), all.toArray, None)
}
def apply(version: String, scalaHome: File, launcher: xsbti.Launcher): ScalaInstance =
apply(version, libraryJar(scalaHome), compilerJar(scalaHome), allJars(scalaHome): _*)(scalaLoader(launcher))
// TODO: These two overloads are deprecated, but they are used by a non-deprecated overload.
// @deprecated("Does not handle modularized Scala. Use a variant that only accepts all jars.", "0.13.0")
private def apply(version: String, libraryJar: File, compilerJar: File, extraJars: File*)(classLoader: List[File] => ClassLoader): ScalaInstance =
apply(version, None, libraryJar, compilerJar, extraJars: _*)(classLoader)
// @deprecated("Does not handle modularized Scala. Use a variant that only accepts all jars.", "0.13.0")
private def apply(version: String, explicitActual: Option[String], libraryJar: File, compilerJar: File, extraJars: File*)(classLoader: List[File] => ClassLoader): ScalaInstance =
new ScalaInstance(version, classLoader(libraryJar :: compilerJar :: extraJars.toList), libraryJar, compilerJar, extraJars.toArray, explicitActual)
def allJars(scalaHome: File): Seq[File] = IO.listFiles(scalaLib(scalaHome)).filter(f => !blacklist(f.getName))
private[this] def scalaLib(scalaHome: File): File = new File(scalaHome, "lib")
private[this] val blacklist: Set[String] = Set("scala-actors.jar", "scalacheck.jar", "scala-partest.jar", "scala-partest-javaagent.jar", "scalap.jar", "scala-swing.jar")
private def compilerJar(scalaHome: File) = scalaJar(scalaHome, "scala-compiler.jar")
private def libraryJar(scalaHome: File) = scalaJar(scalaHome, "scala-library.jar")
def scalaJar(scalaHome: File, name: String) = new File(scalaLib(scalaHome), name)
/** Gets the version of Scala in the compiler.properties file from the loader.*/
private def actualVersion(scalaLoader: ClassLoader)(label: String) =
try fastActualVersion(scalaLoader)
catch { case e: Exception => slowActualVersion(scalaLoader)(label) }
private def slowActualVersion(scalaLoader: ClassLoader)(label: String) =
{
val v = try { Class.forName("scala.tools.nsc.Properties", true, scalaLoader).getMethod("versionString").invoke(null).toString }
catch { case cause: Exception => throw new InvalidScalaInstance("Scala instance doesn't exist or is invalid: " + label, cause) }
if (v.startsWith(VersionPrefix)) v.substring(VersionPrefix.length) else v
}
private def fastActualVersion(scalaLoader: ClassLoader): String =
{
val stream = scalaLoader.getResourceAsStream("compiler.properties")
try {
val props = new java.util.Properties
props.load(stream)
props.getProperty("version.number")
} finally stream.close()
}
import java.net.{ URL, URLClassLoader }
private def scalaLoader(launcher: xsbti.Launcher): Seq[File] => ClassLoader = jars =>
new URLClassLoader(jars.map(_.toURI.toURL).toArray[URL], launcher.topLoader)
}
class InvalidScalaInstance(message: String, cause: Throwable) extends RuntimeException(message, cause)
class InvalidScalaProvider(message: String) extends RuntimeException(message)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy