2009-08-18 06:51:08 +02:00
|
|
|
package xsbt
|
|
|
|
|
|
|
|
|
|
import java.io.File
|
2010-04-02 02:19:29 +02:00
|
|
|
import sbt.{ComponentManager, IfMissing, InvalidComponent}
|
2009-08-18 06:51:08 +02:00
|
|
|
|
|
|
|
|
object ComponentCompiler
|
|
|
|
|
{
|
|
|
|
|
val xsbtiID = "xsbti"
|
2009-08-24 04:21:15 +02:00
|
|
|
val srcExtension = "-src"
|
|
|
|
|
val binSeparator = "-bin_"
|
|
|
|
|
val compilerInterfaceID = "compiler-interface"
|
|
|
|
|
val compilerInterfaceSrcID = compilerInterfaceID + srcExtension
|
2009-12-30 04:14:56 +01:00
|
|
|
val javaVersion = System.getProperty("java.class.version")
|
2009-08-18 06:51:08 +02:00
|
|
|
}
|
2009-09-05 21:01:04 +02:00
|
|
|
/** This class provides source components compiled with the provided RawCompiler.
|
|
|
|
|
* The compiled classes are cached using the provided component manager according
|
|
|
|
|
* to the actualVersion field of the RawCompiler.*/
|
|
|
|
|
class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
|
2009-08-18 06:51:08 +02:00
|
|
|
{
|
|
|
|
|
import ComponentCompiler._
|
2010-06-16 02:38:18 +02:00
|
|
|
import sbt.IO.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory}
|
2009-08-18 06:51:08 +02:00
|
|
|
def apply(id: String): File =
|
2010-04-02 02:19:29 +02:00
|
|
|
try { getPrecompiled(id) }
|
|
|
|
|
catch { case _: InvalidComponent => getLocallyCompiled(id) }
|
|
|
|
|
|
|
|
|
|
/** Gets the precompiled (distributed with sbt) component with the given 'id'
|
|
|
|
|
* If the component has not been precompiled, this throws InvalidComponent. */
|
|
|
|
|
def getPrecompiled(id: String): File = manager.file( binaryID(id, false) )(IfMissing.Fail)
|
|
|
|
|
/** Get the locally compiled component with the given 'id' or compiles it if it has not been compiled yet.
|
|
|
|
|
* If the component does not exist, this throws InvalidComponent. */
|
|
|
|
|
def getLocallyCompiled(id: String): File =
|
2009-08-18 06:51:08 +02:00
|
|
|
{
|
2010-04-02 02:19:29 +02:00
|
|
|
val binID = binaryID(id, true)
|
2009-10-11 04:01:03 +02:00
|
|
|
manager.file(binID)( new IfMissing.Define(true, compileAndInstall(id, binID)) )
|
2009-08-18 06:51:08 +02:00
|
|
|
}
|
2010-04-02 02:19:29 +02:00
|
|
|
def clearCache(id: String): Unit = manager.clearCache(binaryID(id, true))
|
|
|
|
|
protected def binaryID(id: String, withJavaVersion: Boolean) =
|
|
|
|
|
{
|
|
|
|
|
val base = id + binSeparator + compiler.scalaInstance.actualVersion
|
|
|
|
|
if(withJavaVersion) base + "__" + javaVersion else base
|
|
|
|
|
}
|
2009-10-11 04:01:03 +02:00
|
|
|
protected def compileAndInstall(id: String, binID: String)
|
2009-08-18 06:51:08 +02:00
|
|
|
{
|
2009-08-24 04:21:15 +02:00
|
|
|
val srcID = id + srcExtension
|
2009-09-27 20:39:26 +02:00
|
|
|
withTemporaryDirectory { binaryDirectory =>
|
|
|
|
|
val targetJar = new File(binaryDirectory, id + ".jar")
|
2009-10-11 04:01:03 +02:00
|
|
|
compileSources(manager.files(srcID)(IfMissing.Fail), targetJar, id)
|
2009-09-27 20:39:26 +02:00
|
|
|
manager.define(binID, Seq(targetJar))
|
|
|
|
|
}
|
2009-08-18 06:51:08 +02:00
|
|
|
}
|
|
|
|
|
/** Extract sources from source jars, compile them with the xsbti interfaces on the classpath, and package the compiled classes and
|
|
|
|
|
* any resources from the source jars into a final jar.*/
|
2009-08-24 04:21:15 +02:00
|
|
|
private def compileSources(sourceJars: Iterable[File], targetJar: File, id: String)
|
2009-08-18 06:51:08 +02:00
|
|
|
{
|
2010-04-01 04:33:42 +02:00
|
|
|
val isSource = (f: File) => isSourceName(f.getName)
|
|
|
|
|
def keepIfSource(files: Set[File]): Set[File] = if(files.exists(isSource)) files else Set()
|
|
|
|
|
|
2009-08-18 06:51:08 +02:00
|
|
|
withTemporaryDirectory { dir =>
|
2010-04-01 04:33:42 +02:00
|
|
|
val extractedSources = (Set[File]() /: sourceJars) { (extracted, sourceJar)=> extracted ++ keepIfSource(unzip(sourceJar, dir)) }
|
|
|
|
|
val (sourceFiles, resources) = extractedSources.partition(isSource)
|
2009-08-18 06:51:08 +02:00
|
|
|
withTemporaryDirectory { outputDirectory =>
|
2009-10-11 04:01:03 +02:00
|
|
|
val xsbtiJars = manager.files(xsbtiID)(IfMissing.Fail)
|
2009-10-10 01:12:14 +02:00
|
|
|
manager.log.info("'" + id + "' not yet compiled for Scala " + compiler.scalaInstance.actualVersion + ". Compiling...")
|
2009-10-19 04:25:50 +02:00
|
|
|
val start = System.currentTimeMillis
|
|
|
|
|
try
|
|
|
|
|
{
|
2010-06-27 15:16:53 +02:00
|
|
|
compiler(sourceFiles.toSeq, xsbtiJars.toSeq ++ sourceJars, outputDirectory, "-nowarn" :: Nil)
|
2009-10-19 04:25:50 +02:00
|
|
|
manager.log.info(" Compilation completed in " + (System.currentTimeMillis - start) / 1000.0 + " s")
|
|
|
|
|
}
|
2009-10-10 01:12:14 +02:00
|
|
|
catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") }
|
2010-06-16 02:38:18 +02:00
|
|
|
import sbt.Path._
|
|
|
|
|
copy(resources x rebase(dir, outputDirectory))
|
|
|
|
|
zip((outputDirectory ***) x relativeTo(outputDirectory), targetJar)
|
2009-08-18 06:51:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-01 04:33:42 +02:00
|
|
|
private def isSourceName(name: String): Boolean = name.endsWith(".scala") || name.endsWith(".java")
|
2009-08-18 06:51:08 +02:00
|
|
|
}
|