Skip to content
This repository was archived by the owner on Apr 10, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class DirectoryScalaInstallationTest {
assertEquals("bad scala-compiler jar", basePath.append("scala-compiler_2.10.3-mixedCompatibleVersionsWithName.jar"), si.compiler.classJar)
assertEquals("bad scala-compiler source jar", Some(basePath.append("scala-compiler-src_2.10.3-mixedCompatibleVersionsWithName.jar")), si.compiler.sourceJar)

def checkExtraJar(id: String, versionSuffix: String, jars: List[IScalaModule]) = {
def checkExtraJar(id: String, versionSuffix: String, jars: Seq[IScalaModule]) = {
val path= basePath.append(s"scala-${id}${versionSuffix}.jar")
val (goodJars, remainder) = jars.partition(_.classJar == path)
assertFalse(s"Missing scala-$id jar", goodJars.isEmpty)
Expand Down Expand Up @@ -175,7 +175,7 @@ class DirectoryScalaInstallationTest {

assertEquals("bad scala-compiler jar", basePath.append(s"scala-compiler${versionSuffix}.jar"), si.compiler.classJar)

def checkExtraJar(check: Boolean, id: String, jars: List[IScalaModule]) = {
def checkExtraJar(check: Boolean, id: String, jars: Seq[IScalaModule]) = {
if (check) {
val path= basePath.append(s"scala-${id}${versionSuffix}.jar")
val (goodJars, remainder) = jars.partition(_.classJar == path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ trait IScalaInstallation {
* Are the registered components of this installation available on the file system ?
*/
def isValid(): Boolean
/**
* Returns if the project should be compiled with Hydra Compiler
*/
def isHydraInstallation: Boolean = version.unparse.contains("hydra")
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ class CachingCompiler private (cacheFile: File, sbtReporter: Reporter, log: Logg
.map {
case (a, s) => (Option(a), Option(s))
}.getOrElse((Option(SbtUtils.readAnalysis(cacheFile)), None))
cacheAndReturnLastAnalysis(new IncrementalCompilerImpl().compile(comps.scalac, comps.javac, in.sources, in.classpath, in.output, in.cache,
in.scalacOptions, in.javacOptions, o2jo(previousAnalysis), o2jo(previousSetup), lookup, sbtReporter, in.order,
skip = false, in.progress, in.incOptions, extra = Array(), log))

if (!in.scalaInstallation.isHydraInstallation)
cacheAndReturnLastAnalysis(new IncrementalCompilerImpl().compile(comps.scalac, comps.javac, in.sources, in.classpath, in.output, in.cache,
in.scalacOptions, in.javacOptions, o2jo(previousAnalysis), o2jo(previousSetup), lookup, sbtReporter, in.order,
skip = false, in.progress, in.incOptions, extra = Array(), log))
else
cacheAndReturnLastAnalysis(new sbt.internal.inc.hydra.IncrementalCompilerImpl().compile(comps.scalac, comps.javac, in.sources, in.classpath, in.output, in.cache,
in.scalacOptions, in.javacOptions, o2jo(previousAnalysis), o2jo(previousSetup), lookup, sbtReporter, in.order,
skip = false, in.progress, in.incOptions, extra = Array(), log))
}

private def cacheAndReturnLastAnalysis(compilationResult: CompileResult): Analysis = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ class CompilerBridgeStore(base: IPath, plugin: ScalaPlugin) extends HasLogger {
val name = s"Compiling compiler-bridge for ${installation.version.unparse}"
val monitor = SubMonitor.convert(pm, name, 2)
monitor.subTask(name)

(compilerBridgeSrc(installation.version), zincFullJar) match {
val compilerBridgeSource = getCompilerBridgeSources(installation)
(compilerBridgeSource, zincFullJar) match {
case (Some(compilerBridge), Some(zincInterface)) =>
val log = new SbtLogger
cacheDir(installation).toFile.mkdirs()
Expand All @@ -139,6 +139,13 @@ class CompilerBridgeStore(base: IPath, plugin: ScalaPlugin) extends HasLogger {
}
}

private def getCompilerBridgeSources(scalaInstallation: IScalaInstallation) = synchronized {
scalaInstallation.allJars.find(module => module.classJar.toString().contains("hydra-bridge")) match {
case Some(bridgeSource) => Some(bridgeSource.classJar)
case None => compilerBridgeSrc(scalaInstallation.version)
}
}

private class SbtLogger extends Logger {
private val errors = ListBuffer[String]()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import java.util.concurrent.atomic.AtomicReference

import scala.collection.mutable
import scala.tools.nsc.Settings
import scala.util.control.NonFatal

import org.eclipse.core.resources.IContainer
import org.eclipse.core.resources.IFile
Expand Down Expand Up @@ -46,7 +47,7 @@ import xsbti.compile.analysis.SourceInfo
*/
class EclipseSbtBuildManager(val project: IScalaProject, settings: Settings, analysisCache: Option[IFile] = None,
addToClasspath: Seq[IPath] = Seq.empty, srcOutputs: Seq[(IContainer, IContainer)] = Seq.empty)
extends EclipseBuildManager with HasLogger {
extends EclipseBuildManager with HasLogger {

/** Initialized in `build`, used by the SbtProgress. */
private var monitor: SubMonitor = _
Expand Down Expand Up @@ -87,8 +88,7 @@ class EclipseSbtBuildManager(val project: IScalaProject, settings: Settings, ana
"compile",
SbtUtils.NoPosition,
"SBT builder crashed while compiling. The error message is '" + e.getMessage() + "'. Check Error Log for details.",
xsbti.Severity.Error
))
xsbti.Severity.Error))
} finally {
ProductExposer.showJavaCompilationProducts(project.underlying)
}
Expand Down Expand Up @@ -197,7 +197,8 @@ class EclipseSbtBuildManager(val project: IScalaProject, settings: Settings, ana
*/
override def buildErrors: Set[IMarker] = Set.empty

/** Inspired by IC.compile
/**
* Inspired by IC.compile
*
* We need to duplicate IC.compile (by inlining insde this
* private method) because the Java interface it has as a
Expand All @@ -215,8 +216,7 @@ class EclipseSbtBuildManager(val project: IScalaProject, settings: Settings, ana
"compile",
SbtUtils.NoPosition,
errors,
xsbti.Severity.Error
))
xsbti.Severity.Error))
throw CompilerBridgeFailed
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class SbtInputs(

def sources = sourceFiles.toArray

def scalaInstallation = installation

private def srcOutDirs = (if (srcOutputs.nonEmpty) srcOutputs else project.sourceOutputFolders).map {
case (src, out) => (Option(src.getLocation).map(_.toFile()), Option(out.getLocation).map(_.toFile()))
}.collect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ abstract class ScalaClasspathContainerInitializer(desc: String) extends Classpat
}

class ScalaLibraryClasspathContainerInitializer extends ScalaClasspathContainerInitializer(SdtConstants.ScalaLibContName) {
override def entries = (platformInstallation.library +: platformInstallation.extraJars).map {_.libraryEntries()}.to[Array]
override def entries = Array(platformInstallation.library.libraryEntries())
}

class ScalaCompilerClasspathContainerInitializer extends ScalaClasspathContainerInitializer(SdtConstants.ScalaCompilerContName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ trait ScalaClasspathContainerHandler extends HasLogger {
def getAndUpdateScalaClasspathContainerEntry(containerPath: IPath, desc: String, versionString: String, project: IJavaProject, si:IScalaInstallation, existingEntries: Array[IClasspathEntry]): IClasspathEntry = {
val classpathEntriesOfScalaInstallation : Array[IClasspathEntry]=
if (containerPath.toPortableString() startsWith(SdtConstants.ScalaLibContId))
(si.library +: si.extraJars).map(_.libraryEntries()).toArray
Array(si.library.libraryEntries())
else if (containerPath.toPortableString() startsWith(SdtConstants.ScalaCompilerContId))
Array((si.compiler).libraryEntries())
else Array()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ object LabeledScalaInstallationsSaveHelper {
override def compiler = compilerMod
override def library = libraryMod
override def extraJars = extraJarsMods
override def version = ScalaInstallation.extractVersion(library.classJar).getOrElse(NoScalaVersion)
override def version = if (compiler.classJar.toFile().getName.contains("hydra")) ScalaInstallation.extractVersion(compiler.classJar).getOrElse(NoScalaVersion)
else ScalaInstallation.extractVersion(library.classJar).getOrElse(NoScalaVersion)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import org.scalaide.ui.internal.preferences.ScalaPluginSettings
import org.scalaide.util.eclipse.EclipseUtils
import org.scalaide.util.internal.CompilerUtils
import org.scalaide.util.internal.SettingConverterUtil
import scala.tools.nsc.settings.SpecificScalaVersion
import scala.tools.nsc.settings.{ Development, Final }

/** The Scala classpath broken down in the JDK, Scala library and user library.
*
Expand Down Expand Up @@ -525,12 +527,19 @@ trait ClasspathManagement extends HasLogger { self: ScalaProject =>
s"Compiler plugin ${new Path(path).lastSegment()} is cross-compiled with incompatible version for this project: ${v.unparse} vs ${installation.version.unparse}",
SdtConstants.ScalaVersionProblemMarkerId)

// Scala versions ending in `-hydraNN` are binary compatible with the corresponding final version so we just strip it
val installationVersion = installation.version match {
case ver @ SpecificScalaVersion(major, minor, rev, Development(str)) if str.startsWith("hydra") =>
ver.copy(build = Final)
case ver => ver
}

plugins.foldLeft(List[ClasspathErrorMarker]()) {
// plugins cross compiled with full Scala version
case (errors, p @ VersionInFile(version, true)) if version != installation.version
case (errors, p @ VersionInFile(version, true)) if version != installationVersion
error(version, p) :: errors
// plugins cross compiled with binary Scala version
case (errors, p @ VersionInFile(version, false)) if !CompilerUtils.isBinarySame(version, installation.version) ⇒
case (errors, p @ VersionInFile(version, false)) if !CompilerUtils.isBinarySame(version, installationVersion) ⇒
error(version, p) :: errors
case (errors, _) ⇒
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package org.scalaide.core.internal.project

import java.io.File
import java.io.FileFilter

import scala.tools.nsc.settings.NoScalaVersion
import scala.tools.nsc.settings.ScalaVersion
import scala.util.Try

import org.eclipse.core.runtime.IPath
import org.eclipse.core.runtime.Path
import org.scalaide.util.internal.CompilerUtils.isBinarySame
import org.scalaide.core.internal.project.ScalaInstallation.extractVersion
import scala.util.Try
import org.scalaide.util.internal.CompilerUtils.isBinarySame
import scala.collection.mutable.ListBuffer

/**
* This class tries to collect a valid scala installation (library, compiler jars) from a directory.
Expand All @@ -26,6 +30,21 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation
final val scalaCompilerPrefix = "scala-compiler"
final val scalaSwingPrefix = "scala-swing"

//Hydra specific jars
final val fullScalaLibraryPrefix = "org.scala-lang.scala-library"
final val hydraReflectPrefix = "com.triplequote.scala-reflect"
final val hydraCompilerPrefix = "com.triplequote.scala-compiler"
final val hydraPrefix = "com.triplequote.hydra"
final val hydraBridgePrefix = "hydra-bridge_1_0"
final val scalaLoggingPrefix = "com.typesafe.scala-logging.scala-logging_"
final val scalaXmlPrefix = "org.scala-lang.modules.scala-xml_"
final val logbackClassicPrefix = "ch.qos.logback.logback-classic"
final val logbackCorePrefix = "ch.qos.logback.logback-core"
final val slf4jPrefix = "org.slf4j.slf4j-api"
final val license4jPrefix = "com.license4j.license4j-runtime-library"
final val hydraDashboardPrefix = "com.triplequote.dashboard-model_"
final val hydraLicenseCheckingPrefix = "com.triplequote.license-checking"

private val dirAsValidFile: Option[File] = {
val f = directory.toFile()
if (f.isDirectory()) Some(f) else None
Expand All @@ -36,16 +55,16 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation
f.listFiles(fF)
}

private def versionOfFileName(f:File): Option[String] = {
val versionedRegex = """scala-\w+(.2\.\d+(?:\.\d*)?(?:-.*)?).jar""".r
private def versionOfFileName(f: File): Option[String] = {
val versionedRegex = """.*scala-\w+(.2\.\d+(?:\.\d*)?(?:-.*)?).jar""".r
f.getName() match {
case versionedRegex(version) => Some(version)
case _ => None
}
}

private def looksBinaryCompatible(version: ScalaVersion, module: ScalaModule) = {
extractVersion(module.classJar) forall (isBinarySame(version, _))
extractVersion(module.classJar) forall (isBinarySame(version, _))
}

/**
Expand All @@ -69,6 +88,7 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation
private def findScalaJars(prefixes: List[String], presumedVersion: Option[String]): List[ScalaModule] = {
presumedVersion foreach { s => require(""".2\.\d+(?:\.\d*)?(?:-.*)?""".r.pattern.matcher(s).matches) }
// for now this means we return whatever we could find: it may not be enough (missing scala-reflect, etc)

prefixes flatMap { p =>
val optionalVersion = """(?:.2\.\d+(?:\.\d*)?(?:-.*)?)?"""
val requiredVersion = presumedVersion.fold(optionalVersion)(s => s.replaceAll("""\.""", """\\."""))
Expand All @@ -77,11 +97,11 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation

// Beware : the 'find' below indicates we're returning for the first matching option
def jarLookup(r: scala.util.matching.Regex): Option[File] =
(extantJars flatMap (_.find { f => r.pattern.matcher(f.getName()).matches}))
(extantJars flatMap (_.find { f => r.pattern.matcher(f.getName()).matches }))

// Try with any version if the presumed String can't be matched
val classJarResult = jarLookup(versionedRegex) match {
case s@Some(_) => s
case s @ Some(_) => s
case None => jarLookup((s"$p$optionalVersion\\.jar").r)
}
val foundVersion = classJarResult flatMap versionOfFileName
Expand All @@ -96,12 +116,12 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation
}
}

private val libraryCandidate = findScalaJars(scalaLibraryPrefix, None)
private val libraryCandidate = findScalaJars(scalaLibraryPrefix, None).orElse(findScalaJars(fullScalaLibraryPrefix, None))
private val presumedLibraryVersionString = libraryCandidate flatMap (l => versionOfFileName(l.classJar.toFile))
private val versionCandidate: Option[ScalaVersion] = libraryCandidate.flatMap(l => extractVersion(l.classJar))
private val compilerCandidate = findScalaJars(scalaCompilerPrefix, presumedLibraryVersionString) filter {
private val compilerCandidate = findScalaJars(scalaCompilerPrefix, presumedLibraryVersionString).orElse(findScalaJars(hydraCompilerPrefix, presumedLibraryVersionString)) filter {
module => (versionCandidate forall (looksBinaryCompatible(_, module)))
}
}

/* initialization checks*/
if (!dirAsValidFile.isDefined) throw new IllegalArgumentException("The provided path does not point to a valid directory.")
Expand All @@ -111,15 +131,53 @@ class DirectoryScalaInstallation(val directory: IPath) extends ScalaInstallation
if (!versionCandidate.isDefined) throw new IllegalArgumentException("The Scala library jar in this directory has incorrect or missing version information, aborting.")
// TODO : this hard-coded hook will need changing
if (versionCandidate.isDefined && versionCandidate.get < ScalaVersion("2.10.0")) throw new IllegalArgumentException("This Scala version is too old for the presentation compiler to use. Please provide a 2.10 scala (or later).")
// Hydra initialization checks
if (isHydraInstallation) {
if (allJars.filter(module => module.classJar.toFile().getName.contains(hydraBridgePrefix)).isEmpty)
throw new IllegalArgumentException("Can not recognize a valid Hydra Bridge jar in this directory.")
if (allJars.filter(module => module.classJar.toFile().getName.contains(hydraPrefix)).isEmpty)
throw new IllegalArgumentException("Can not recognize a valid Hydra jar in this directory.")
if (allJars.filter(module => module.classJar.toFile().getName.contains(hydraLicenseCheckingPrefix)).isEmpty)
throw new IllegalArgumentException("Can not recognize a valid Hydra License Checking jar in this directory.")
if (allJars.filter(module => module.classJar.toFile().getName.contains(license4jPrefix)).isEmpty)
throw new IllegalArgumentException("Can not recognize a valid License4j jar in this directory.")
if (allJars.filter(module => module.classJar.toFile().getName.contains(hydraDashboardPrefix)).isEmpty)
throw new IllegalArgumentException("Can not recognize a valid Hydra Dashboard jar in this directory.")
}

override lazy val extraJars = findScalaJars(List(scalaReflectPrefix,
scalaSwingPrefix), presumedLibraryVersionString).filter {
private lazy val vanillaScalaExtraJars: List[ScalaModule] = findScalaJars(List(
scalaReflectPrefix,
scalaSwingPrefix,
scalaXmlPrefix
), presumedLibraryVersionString).filter {
module => versionCandidate forall (looksBinaryCompatible(_, module))
}
}


lazy val hydraJars: List[ScalaModule] = (extantJars.map { allJars =>
val jars = ListBuffer.empty[File]
val vanillaFiles: Set[File] = (for (module <- vanillaScalaExtraJars) yield {
module.sourceJar.toSeq.map(_.toFile()) :+ module.classJar.toFile()
}).flatten.toSet

for (f <- extantJars.getOrElse(Array[File]()) if !vanillaFiles(f))
jars += f

jars.toList
}).getOrElse(List()).map(jar => ScalaModule(new Path(jar.getCanonicalPath), None))

override lazy val extraJars = if (isHydraInstallation)
vanillaScalaExtraJars ++ hydraJars
else
vanillaScalaExtraJars

override lazy val allJars: Seq[ScalaModule] = library +: compiler +: (extraJars ++ hydraJars)

override lazy val compiler = compilerCandidate.get
override lazy val library = libraryCandidate.get
override lazy val version = versionCandidate.get

//If Hydra is used the version must be retrieved from the compiler jar
override lazy val version = if (compiler.classJar.toFile().getName.contains(hydraCompilerPrefix))
extractVersion(compiler.classJar).getOrElse(NoScalaVersion) else versionCandidate.get
}

object DirectoryScalaInstallation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ object ScalaInstallation {
val LibraryPropertiesPath = "library.properties"

def labelInFile(scalaPath: IPath): Option[String] = {
val scalaJarRegex = """scala-(\w+)(?:.2\.\d+(?:\.\d*)?(?:-.*)?)?.jar""".r
val scalaJarRegex = """.*scala-(\w+)(?:.2\.\d+(?:\.\d*)?(?:-.*)?)?.jar""".r
scalaPath.toFile().getName() match {
case scalaJarRegex(qualifier) => Some(qualifier + ".properties")
case _ => None
Expand Down
Loading