Additions to help the sbt/xsbt combination

This commit is contained in:
Mark Harrah 2009-10-09 19:12:14 -04:00
parent 7bb72ecb8b
commit e88214efbd
9 changed files with 52 additions and 19 deletions

View File

@ -8,7 +8,7 @@ package xsbt
* provided by scalaInstance. This class requires a ComponentManager in order to obtain the interface code to scalac and
* the analysis plugin. Because these call Scala code for a different Scala version than the one used for this class, they must
* be compiled for the version of Scala being used.*/
class AnalyzingCompiler(scalaInstance: ScalaInstance, manager: ComponentManager) extends NotNull
class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager) extends NotNull
{
def apply(sources: Set[File], classpath: Set[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: CompileLogger): Unit =
apply(sources, classpath, outputDirectory, options, false, callback, maximumErrors, log)
@ -48,8 +48,9 @@ class AnalyzingCompiler(scalaInstance: ScalaInstance, manager: ComponentManager)
}
def console(classpath: Set[File], initialCommands: String, log: CompileLogger): Unit =
{
val classpathString = CompilerArguments.absString(classpath)
val bootClasspath = (new CompilerArguments(scalaInstance)).createBootClasspath
val arguments = new CompilerArguments(scalaInstance)
val classpathString = CompilerArguments.absString(arguments.finishClasspath(classpath, true))
val bootClasspath = arguments.createBootClasspath
call("xsbt.ConsoleInterface", log) (classOf[String], classOf[String], classOf[String], classOf[xLogger]) (bootClasspath, classpathString, initialCommands, log)
}
private def call(interfaceClassName: String, log: CompileLogger)(argTypes: Class[_]*)(args: AnyRef*)
@ -57,7 +58,8 @@ class AnalyzingCompiler(scalaInstance: ScalaInstance, manager: ComponentManager)
val interfaceClass = getInterfaceClass(interfaceClassName, log)
val interface = interfaceClass.newInstance.asInstanceOf[AnyRef]
val method = interfaceClass.getMethod("run", argTypes : _*)
method.invoke(interface, args: _*)
try { method.invoke(interface, args: _*) }
catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause }
}
private def getInterfaceClass(name: String, log: CompileLogger) =
{

View File

@ -46,8 +46,9 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
val (sourceFiles, resources) = extractedSources.partition(_.getName.endsWith(".scala"))
withTemporaryDirectory { outputDirectory =>
val xsbtiJars = manager.files(xsbtiID)
manager.log.info("'" + id + "' not yet compiled for Scala " + compiler.scalaInstance.actualVersion + ". Compiling...")
try { compiler(Set() ++ sourceFiles, Set() ++ xsbtiJars, outputDirectory, Nil, true) }
catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling component '" + id + "'") }
catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") }
copy(resources x (FileMapper.rebase(dir, outputDirectory)))
zip((outputDirectory ***) x (PathMapper.relativeTo(outputDirectory)), targetJar)
}

View File

@ -37,4 +37,7 @@ class RawCompiler(val scalaInstance: ScalaInstance, log: CompileLogger)
realArray
}
}
class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
{
override def fillInStackTrace = this
}

View File

@ -10,12 +10,7 @@ package xsbt
final class ScalaInstance(val version: String, val loader: ClassLoader, val libraryJar: File, val compilerJar: File) extends NotNull
{
/** 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 =
{
import ScalaInstance.VersionPrefix
val v = Class.forName("scala.tools.nsc.Properties", true, loader).getMethod("versionString").invoke(null).toString
if(v.startsWith(VersionPrefix)) v.substring(VersionPrefix.length) else v
}
lazy val actualVersion = ScalaInstance.actualVersion(loader)(" version " + version)
}
object ScalaInstance
{
@ -25,4 +20,34 @@ object ScalaInstance
apply(version, launcher.getScala(version))
def apply(version: String, provider: xsbti.ScalaProvider): ScalaInstance =
new ScalaInstance(version, provider.loader, provider.libraryJar, provider.compilerJar)
}
def apply(scalaHome: File, launcher: xsbti.Launcher): ScalaInstance =
apply(libraryJar(scalaHome), compilerJar(scalaHome), launcher)
def apply(version: String, scalaHome: File, launcher: xsbti.Launcher): ScalaInstance =
apply(version, libraryJar(scalaHome), compilerJar(scalaHome), launcher)
def apply(libraryJar: File, compilerJar: File, launcher: xsbti.Launcher): ScalaInstance =
{
val loader = scalaLoader(launcher, libraryJar, compilerJar)
val version = actualVersion(loader)(" (library jar " + libraryJar.getAbsolutePath + ")")
new ScalaInstance(version, loader, libraryJar, compilerJar)
}
def apply(version: String, libraryJar: File, compilerJar: File, launcher: xsbti.Launcher): ScalaInstance =
new ScalaInstance(version, scalaLoader(launcher, libraryJar, compilerJar), libraryJar, compilerJar)
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(scalaHome, "lib" + File.separator + name)
/** Gets the version of Scala in the compiler.properties file from the loader.*/
private def actualVersion(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("Incompatible Scala instance: " + label, cause) }
if(v.startsWith(VersionPrefix)) v.substring(VersionPrefix.length) else v
}
import java.net.{URL, URLClassLoader}
private def scalaLoader(launcher: xsbti.Launcher, jars: File*): ClassLoader =
new URLClassLoader(jars.map(_.toURI.toURL).toArray[URL], launcher.topLoader)
}
class InvalidScalaInstance(message: String, cause: Throwable) extends RuntimeException(message, cause)

View File

@ -40,7 +40,7 @@ class CompilerInterface
{
phasesSet += sbtAnalyzer
val superd = super.computePhaseDescriptors
if(superd.contains(sbtAnalyzer)) superd else ( superd ++ Seq(sbtAnalyzer) ).toList
if(superd.contains(sbtAnalyzer)) superd else ( superd ++ List(sbtAnalyzer) ).toList
}
trait Compat27 { val runsBefore: List[String] = Nil }
}

View File

@ -11,7 +11,7 @@ import java.io.File
* This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
* machine.
*/
class ComponentManager(provider: xsbti.ComponentProvider, log: IvyLogger) extends NotNull
class ComponentManager(provider: xsbti.ComponentProvider, val log: IvyLogger) extends NotNull
{
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
def files(id: String): Iterable[File] =

View File

@ -53,11 +53,12 @@ class Launch(val bootDirectory: File, repositories: Seq[Repository]) extends xsb
private val scalaProviders = new HashMap[String, ScalaProvider]
def getScala(version: String): xsbti.ScalaProvider = scalaProviders.getOrElseUpdate(version, new ScalaProvider(version))
lazy val topLoader = new BootFilteredLoader(getClass.getClassLoader)
class ScalaProvider(val version: String) extends xsbti.ScalaProvider with Provider
{
def launcher: xsbti.Launcher = Launch.this
lazy val parentLoader = new BootFilteredLoader(getClass.getClassLoader)
def parentLoader = topLoader
lazy val configuration = new UpdateConfiguration(bootDirectory, version, repositories)
lazy val libDirectory = new File(configuration.bootDirectory, baseDirectoryName(version))

View File

@ -4,4 +4,5 @@ public interface Launcher
{
public static final int InterfaceVersion = 1;
public ScalaProvider getScala(String version);
public ClassLoader topLoader();
}

View File

@ -21,9 +21,9 @@ trait ProguardLaunch extends ProguardProject
log.debug("proguard configuration ivy jar location: " + ivyJars.mkString(", "))
(withJar(ivyJars.toSeq, "Ivy") + "(!META-INF/**,!fr/**,!**/antlib.xml,!**/*.png)") ::
((withJar(ivyJars.toSeq, "Ivy") + "(!META-INF/**,!fr/**,!**/antlib.xml,!**/*.png)") ::
(withJar(jlineJars, "JLine") + "(!META-INF/**)" ) ::
otherJars.map(jar => mkpath(jar) + "(!META-INF/**,!*.properties)").toList
otherJars.map(jar => mkpath(jar) + "(!META-INF/**,!*.properties)").toList) map { "-injars " + _ }
}
private def withJar[T](files: Seq[File], name: String) = mkpath(files.firstOption.getOrElse(error(name + " not present (try running update)")))