From d2950da9dd59b0eaaedc7c10f31f2cad3f3cd207 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Tue, 9 Sep 2014 08:56:51 -0400 Subject: [PATCH] Fix issue where ScalaInstance broke the thread-context-classloader for all scala classes. The issue is that when you manually set a ScalaInstance, i.e. not one from Ivy, the classpath which is returned for any given configuration ONLY uses Ivy. This means that the legitimate Scala JAR files that need to be on the classpath are missing from the list. For some reason, the way we instantiate tests uses an unfiltered classloader against the ScalaInstance, *BUT* the thread-context-classloader DOES use a filtered instance by classpath. This add the hook into the TestFramework runner creation so that the classpath accurately reflects the jars needed. cc @rkuhn --- testing/src/main/scala/sbt/TestFramework.scala | 7 ++++++- util/classpath/src/main/scala/sbt/ScalaInstance.scala | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index 6595fd472..0bbab2058 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -191,7 +191,12 @@ object TestFramework { val notInterfaceFilter = (name: String) => !interfaceFilter(name) val dual = new DualLoader(scalaInstance.loader, notInterfaceFilter, x => true, getClass.getClassLoader, interfaceFilter, x => false) val main = ClasspathUtilities.makeLoader(classpath, dual, scalaInstance, tempDir) - ClasspathUtilities.filterByClasspath(interfaceJar +: classpath, main) + // TODO - There's actually an issue with the classpath facility such that unmanagedScalaInstances are not added + // to the classpath correctly. We have a temporary workaround here. + val cp: Seq[File] = + if (scalaInstance.isManagedVersion) interfaceJar +: classpath + else scalaInstance.allJars ++ (interfaceJar +: classpath) + ClasspathUtilities.filterByClasspath(cp, main) } def createTestFunction(loader: ClassLoader, taskDef: TaskDef, runner: TestRunner, testTask: TestTask): TestFunction = new TestFunction(taskDef, runner, (r: TestRunner) => withContextLoader(loader) { r.run(taskDef, testTask) }) { def tags = testTask.tags } diff --git a/util/classpath/src/main/scala/sbt/ScalaInstance.scala b/util/classpath/src/main/scala/sbt/ScalaInstance.scala index c0a207887..b2bf5bc3d 100644 --- a/util/classpath/src/main/scala/sbt/ScalaInstance.scala +++ b/util/classpath/src/main/scala/sbt/ScalaInstance.scala @@ -19,6 +19,12 @@ final class ScalaInstance(val version: String, val loader: ClassLoader, val libr @deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0") val compilerJar: File, @deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0") val extraJars: Seq[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 // These are to implement xsbti.ScalaInstance @deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0") def otherJars: Array[File] = extraJars.toArray