diff --git a/compile/AnalyzingCompiler.scala b/compile/AnalyzingCompiler.scala index 0056a7fd6..e8c70ff40 100644 --- a/compile/AnalyzingCompiler.scala +++ b/compile/AnalyzingCompiler.scala @@ -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) = { diff --git a/compile/ComponentCompiler.scala b/compile/ComponentCompiler.scala index c0cbf68d5..980042158 100644 --- a/compile/ComponentCompiler.scala +++ b/compile/ComponentCompiler.scala @@ -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) } diff --git a/compile/RawCompiler.scala b/compile/RawCompiler.scala index 17a3e4295..0e4d87f38 100644 --- a/compile/RawCompiler.scala +++ b/compile/RawCompiler.scala @@ -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 \ No newline at end of file +class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed +{ + override def fillInStackTrace = this +} \ No newline at end of file diff --git a/compile/ScalaInstance.scala b/compile/ScalaInstance.scala index f868a48d2..a0ab64fe5 100644 --- a/compile/ScalaInstance.scala +++ b/compile/ScalaInstance.scala @@ -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) -} \ No newline at end of file + + 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) \ No newline at end of file diff --git a/compile/interface/CompilerInterface.scala b/compile/interface/CompilerInterface.scala index 479f3dcf2..01f3a10ef 100644 --- a/compile/interface/CompilerInterface.scala +++ b/compile/interface/CompilerInterface.scala @@ -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 } } diff --git a/ivy/ComponentManager.scala b/ivy/ComponentManager.scala index d13459a67..e420ffe22 100644 --- a/ivy/ComponentManager.scala +++ b/ivy/ComponentManager.scala @@ -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] = diff --git a/launch/Launch.scala b/launch/Launch.scala index c45a5c54f..8da3ed4fa 100644 --- a/launch/Launch.scala +++ b/launch/Launch.scala @@ -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)) diff --git a/launch/interface/src/main/java/xsbti/Launcher.java b/launch/interface/src/main/java/xsbti/Launcher.java index 4292a8d8a..c5b813c7b 100644 --- a/launch/interface/src/main/java/xsbti/Launcher.java +++ b/launch/interface/src/main/java/xsbti/Launcher.java @@ -4,4 +4,5 @@ public interface Launcher { public static final int InterfaceVersion = 1; public ScalaProvider getScala(String version); + public ClassLoader topLoader(); } \ No newline at end of file diff --git a/project/build/LauncherProguard.scala b/project/build/LauncherProguard.scala index af98730e0..0216fe064 100644 --- a/project/build/LauncherProguard.scala +++ b/project/build/LauncherProguard.scala @@ -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)")))