Revert "Place scalatest framework jar in its own classloader"

This partially reverts commit 8518c4b4fd.

I left in the useful changes to ReverseLookupClassLoader.
This commit is contained in:
Ethan Atkins 2019-12-23 13:24:55 -08:00
parent ae01f25bab
commit 424fe958e1
3 changed files with 16 additions and 75 deletions

View File

@ -1,34 +0,0 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal;
import java.net.URL;
import java.net.URLClassLoader;
final class ScalaTestFrameworkClassLoader extends URLClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
private final URL[] jars;
ScalaTestFrameworkClassLoader(final URL[] jars, final ClassLoader parent) {
super(jars, parent);
this.jars = jars;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < jars.length; ++ i) {
builder.append(jars[i].toString());
if (i < jars.length - 2) builder.append(", ");
}
return "ScalaTestFrameworkClassLoader(" + builder + " parent = " + getParent() + ")";
}
}

View File

@ -161,25 +161,11 @@ private[sbt] object ClassLoaders {
val cpFiles = fullCP.map(_._1)
val allDependencies = cpFiles.filter(allDependenciesSet)
/*
* We need to put scalatest and its dependencies (scala-xml) in its own layer so that the
* classloader for scalatest is generally not ever closed. This is because one project
* closing its scalatest loader can cause a crash in another project if that project
* is reading the scalatest bundle properties because the underlying JarFile instance is
* shared across URLClassLoaders if it points to the same jar.
*
* TODO: Make this configurable and/or add other frameworks in this layer.
*/
val (frameworkDependencies, otherDependencies) = allDependencies.partition { d =>
val name = d.getName
name.startsWith("scalatest_") || name.startsWith("scalactic_") ||
name.startsWith("scala-xml_")
}
def isReflectJar(f: File) =
def isReflectJar(f: File): Boolean =
f.getName == "scala-reflect.jar" || f.getName.startsWith("scala-reflect-")
val scalaReflectJar = otherDependencies.collectFirst {
case f if isReflectJar(f) => si.allJars.find(isReflectJar).getOrElse(f)
}
val scalaReflectJar = allDependencies.collectFirst {
case f if isReflectJar(f) => si.allJars.find(isReflectJar)
}.flatten
val scalaReflectLayer = scalaReflectJar
.map { file =>
cache.apply(
@ -190,46 +176,35 @@ private[sbt] object ClassLoaders {
}
.getOrElse(scalaLibraryLayer)
// layer 2 framework jars
val frameworkLayer =
if (frameworkDependencies.isEmpty) scalaReflectLayer
else {
cache.apply(
frameworkDependencies.map(file => file -> IO.getModifiedTimeOrZero(file)).toList,
scalaLibraryLayer,
() => new ScalaTestFrameworkClassLoader(frameworkDependencies.urls, scalaReflectLayer)
)
}
// layer 3 (optional if in the test config and the runtime layer is not shared)
// layer 2 (optional if in the test config and the runtime layer is not shared)
val dependencyLayer: ClassLoader =
if (layerDependencies && otherDependencies.nonEmpty) {
if (layerDependencies && allDependencies.nonEmpty) {
cache(
otherDependencies.toList.map(f => f -> IO.getModifiedTimeOrZero(f)),
frameworkLayer,
allDependencies.toList.map(f => f -> IO.getModifiedTimeOrZero(f)),
scalaReflectLayer,
() =>
new ReverseLookupClassLoaderHolder(
otherDependencies,
frameworkLayer,
allDependencies,
scalaReflectLayer,
close,
allowZombies,
logger
)
)
} else frameworkLayer
} else scalaReflectLayer
val scalaJarNames = (si.libraryJars ++ scalaReflectJar).map(_.getName).toSet
// layer 3
val filteredSet =
if (layerDependencies) allDependencies.toSet ++ si.libraryJars ++ scalaReflectJar
else Set(frameworkDependencies ++ si.libraryJars ++ scalaReflectJar: _*)
else Set(si.libraryJars ++ scalaReflectJar: _*)
val dynamicClasspath = cpFiles.filterNot(f => filteredSet(f) || scalaJarNames(f.getName))
dependencyLayer match {
case dl: ReverseLookupClassLoaderHolder =>
dl.checkout(dynamicClasspath, tmp)
dl.checkout(cpFiles, tmp)
case cl =>
cl.getParent match {
case dl: ReverseLookupClassLoaderHolder => dl.checkout(dynamicClasspath, tmp)
case dl: ReverseLookupClassLoaderHolder => dl.checkout(cpFiles, tmp)
case _ =>
new LayeredClassLoader(dynamicClasspath.urls, cl, tmp, close, allowZombies, logger)
}

View File

@ -56,7 +56,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
*
* @return a ClassLoader
*/
def checkout(dynamicClasspath: Seq[File], tempDir: File): ClassLoader = {
def checkout(fullClasspath: Seq[File], tempDir: File): ClassLoader = {
if (closed.get()) {
val msg = "Tried to extract class loader from closed ReverseLookupClassLoaderHolder. " +
"Try running the `clearCaches` command and re-trying."
@ -69,7 +69,7 @@ private[internal] final class ReverseLookupClassLoaderHolder(
reverseLookupClassLoader.setup(tempDir)
new BottomClassLoader(
ReverseLookupClassLoaderHolder.this,
dynamicClasspath.map(_.toURI.toURL).toArray,
fullClasspath.map(_.toURI.toURL).toArray,
reverseLookupClassLoader,
tempDir,
closeThis,