Fix actions/completions

When loading a scripted test, sbt creates a jar file and loads it.
The path of the jar file is the same for all the batched tests.
We must prevent the JDK from caching this jar file to force a reload after each test.
Otherwise sbt tries to load the auto-plugins of a previous test and fails.
This commit is contained in:
Adrien Piquerez 2024-03-28 11:59:55 +01:00
parent 52fd2b4427
commit b0f3cb0a8e
3 changed files with 30 additions and 6 deletions

View File

@ -8,10 +8,14 @@
package sbt.internal;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Paths;
import xsbti.*;
/**
@ -25,6 +29,10 @@ public class XMainConfiguration {
public xsbti.MainResult run(String moduleName, xsbti.AppConfiguration configuration)
throws Throwable {
try {
boolean isScripted = Boolean.parseBoolean(System.getProperty("sbt.scripted"));
// in batch scripted tests, we disable caching of JAR URL connections to avoid interference
// between tests
if (isScripted) disableCachingOfURLConnections();
ClassLoader topLoader = configuration.provider().scalaProvider().launcher().topLoader();
xsbti.AppConfiguration updatedConfiguration = null;
try {
@ -56,7 +64,7 @@ public class XMainConfiguration {
clw.getMethod("warmup").invoke(clw.getField("MODULE$").get(null));
return (xsbti.MainResult) runMethod.invoke(instance, updatedConfiguration);
} catch (InvocationTargetException e) {
// This propogates xsbti.FullReload to the launcher
// This propagates xsbti.FullReload to the launcher
throw e.getCause();
}
} catch (ReflectiveOperationException e) {
@ -104,6 +112,22 @@ public class XMainConfiguration {
}
}
private class FakeURLConnection extends URLConnection {
public FakeURLConnection(URL url) {
super(url);
}
public void connect() throws IOException {}
}
private void disableCachingOfURLConnections() {
try {
URLConnection conn = new FakeURLConnection(Paths.get(".").toUri().toURL());
conn.setDefaultUseCaches(false);
} catch (MalformedURLException e) {
}
}
/*
* Replaces the AppProvider.loader method with a new loader that puts the sbt test interface
* jar ahead of the rest of the sbt classpath in the classloading hierarchy.

View File

@ -337,10 +337,9 @@ object EvaluateTask {
def evalPluginDef(pluginDef: BuildStructure, state: State): PluginData = {
val root = ProjectRef(pluginDef.root, Load.getRootProject(pluginDef.units)(pluginDef.root))
val pluginKey = pluginData
val config = extractedTaskConfig(Project.extract(state), pluginDef, state)
val evaluated =
apply(pluginDef, ScopedKey(pluginKey.scope, pluginKey.key), state, root, config)
apply(pluginDef, ScopedKey(pluginData.scope, pluginData.key), state, root, config)
val (newS, result) = evaluated getOrElse sys.error(
"Plugin data does not exist for plugin definition at " + pluginDef.root
)

View File

@ -136,9 +136,10 @@ object PluginDiscovery:
.getResources(resourceName)
.asScala
.toSeq
.filter(onClasspath(classpath, converter)) flatMap { u =>
IO.readLinesURL(u).map(_.trim).filter(!_.isEmpty)
}
.filter(onClasspath(classpath, converter))
.flatMap { u =>
IO.readLinesURL(u).map(_.trim).filter(!_.isEmpty)
}
/** Returns `true` if `url` is an entry in `classpath`. */
def onClasspath(classpath: Def.Classpath, converter: FileConverter)(url: URL): Boolean =