mirror of https://github.com/sbt/sbt.git
Allow RunSourceFromMain to use launcher
The repo overrides scripted test relies on using the launcher to modify the default resolvers. To support this, I extended the scripted launcher to use the bundled sbt launcher if it is passed in via the `-Dsbt.launch.jar` system property.
This commit is contained in:
parent
ae4d3aecb8
commit
86eaf9d572
13
build.sbt
13
build.sbt
|
|
@ -1099,15 +1099,16 @@ lazy val vscodePlugin = (project in file("vscode-sbt-scala"))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def scriptedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
def scriptedTask(launch: Boolean): Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
||||||
publishLocalBinAll.value
|
publishLocalBinAll.value
|
||||||
|
val launchJar = s"-Dsbt.launch.jar=${(bundledLauncherProj / Compile / packageBin).value}"
|
||||||
Scripted.doScripted(
|
Scripted.doScripted(
|
||||||
(scalaInstance in scriptedSbtReduxProj).value,
|
(scalaInstance in scriptedSbtReduxProj).value,
|
||||||
scriptedSource.value,
|
scriptedSource.value,
|
||||||
scriptedBufferLog.value,
|
scriptedBufferLog.value,
|
||||||
Def.setting(Scripted.scriptedParser(scriptedSource.value)).parsed,
|
Def.setting(Scripted.scriptedParser(scriptedSource.value)).parsed,
|
||||||
scriptedPrescripted.value,
|
scriptedPrescripted.value,
|
||||||
scriptedLaunchOpts.value,
|
scriptedLaunchOpts.value ++ (if (launch) Some(launchJar) else None),
|
||||||
scalaVersion.value,
|
scalaVersion.value,
|
||||||
version.value,
|
version.value,
|
||||||
(scriptedSbtReduxProj / Test / fullClasspathAsJars).value.map(_.data),
|
(scriptedSbtReduxProj / Test / fullClasspathAsJars).value.map(_.data),
|
||||||
|
|
@ -1161,8 +1162,8 @@ ThisBuild / scriptedPrescripted := { _ =>
|
||||||
|
|
||||||
def otherRootSettings =
|
def otherRootSettings =
|
||||||
Seq(
|
Seq(
|
||||||
scripted := scriptedTask.evaluated,
|
scripted := scriptedTask(false).evaluated,
|
||||||
scriptedUnpublished := scriptedTask.evaluated,
|
scriptedUnpublished := scriptedTask(false).evaluated,
|
||||||
scriptedSource := (sourceDirectory in sbtProj).value / "sbt-test",
|
scriptedSource := (sourceDirectory in sbtProj).value / "sbt-test",
|
||||||
watchTriggers in scripted += scriptedSource.value.toGlob / **,
|
watchTriggers in scripted += scriptedSource.value.toGlob / **,
|
||||||
watchTriggers in scriptedUnpublished := (watchTriggers in scripted).value,
|
watchTriggers in scriptedUnpublished := (watchTriggers in scripted).value,
|
||||||
|
|
@ -1186,8 +1187,8 @@ def otherRootSettings =
|
||||||
case Some(home) => List(s"-Dsbt.ivy.home=$home")
|
case Some(home) => List(s"-Dsbt.ivy.home=$home")
|
||||||
case _ => Nil
|
case _ => Nil
|
||||||
}),
|
}),
|
||||||
scripted := scriptedTask.evaluated,
|
scripted := scriptedTask(true).evaluated,
|
||||||
scriptedUnpublished := scriptedTask.evaluated,
|
scriptedUnpublished := scriptedTask(true).evaluated,
|
||||||
scriptedSource := (sourceDirectory in sbtProj).value / "repo-override-test"
|
scriptedSource := (sourceDirectory in sbtProj).value / "repo-override-test"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package sbt.internal.scriptedtest;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
|
@ -24,8 +25,10 @@ import xsbti.AppMain;
|
||||||
import xsbti.AppProvider;
|
import xsbti.AppProvider;
|
||||||
import xsbti.ApplicationID;
|
import xsbti.ApplicationID;
|
||||||
import xsbti.ComponentProvider;
|
import xsbti.ComponentProvider;
|
||||||
|
import xsbti.Continue;
|
||||||
import xsbti.CrossValue;
|
import xsbti.CrossValue;
|
||||||
import xsbti.Exit;
|
import xsbti.Exit;
|
||||||
|
import xsbti.FullReload;
|
||||||
import xsbti.GlobalLock;
|
import xsbti.GlobalLock;
|
||||||
import xsbti.Launcher;
|
import xsbti.Launcher;
|
||||||
import xsbti.MainResult;
|
import xsbti.MainResult;
|
||||||
|
|
@ -54,16 +57,16 @@ public class ScriptedLauncher {
|
||||||
String[] args)
|
String[] args)
|
||||||
throws MalformedURLException, InvocationTargetException, ClassNotFoundException,
|
throws MalformedURLException, InvocationTargetException, ClassNotFoundException,
|
||||||
NoSuchMethodException, IllegalAccessException {
|
NoSuchMethodException, IllegalAccessException {
|
||||||
|
if (System.getProperty("sbt.launch.jar") == null) {
|
||||||
while (true) {
|
while (true) {
|
||||||
final URL configURL = URLForClass(xsbti.AppConfiguration.class);
|
final URL configURL = URLForClass(xsbti.AppConfiguration.class);
|
||||||
final URL mainURL = URLForClass(sbt.xMain.class);
|
final URL mainURL = URLForClass(sbt.xMain.class);
|
||||||
final URL scriptedURL = URLForClass(ScriptedLauncher.class);
|
final URL scriptedURL = URLForClass(ScriptedLauncher.class);
|
||||||
final ClassLoader topLoader =
|
final ClassLoader topLoader = new URLClassLoader(new URL[] {configURL}, top());
|
||||||
new URLClassLoader(new URL[] {configURL}, ClassLoader.getSystemClassLoader().getParent());
|
final URLClassLoader loader =
|
||||||
final URLClassLoader loader = new URLClassLoader(new URL[] {mainURL, scriptedURL}, topLoader);
|
new URLClassLoader(new URL[] {mainURL, scriptedURL}, topLoader);
|
||||||
final ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
final ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
||||||
try {
|
try {
|
||||||
Thread.currentThread().setContextClassLoader(loader);
|
|
||||||
final AtomicInteger result = new AtomicInteger(-1);
|
final AtomicInteger result = new AtomicInteger(-1);
|
||||||
final AtomicReference<String[]> newArguments = new AtomicReference<>();
|
final AtomicReference<String[]> newArguments = new AtomicReference<>();
|
||||||
final Class<?> clazz = loader.loadClass("sbt.internal.scriptedtest.ScriptedLauncher");
|
final Class<?> clazz = loader.loadClass("sbt.internal.scriptedtest.ScriptedLauncher");
|
||||||
|
|
@ -97,14 +100,45 @@ public class ScriptedLauncher {
|
||||||
final int res = result.get();
|
final int res = result.get();
|
||||||
if (res >= 0) return res == Integer.MAX_VALUE ? Optional.empty() : Optional.of(res);
|
if (res >= 0) return res == Integer.MAX_VALUE ? Optional.empty() : Optional.of(res);
|
||||||
else args = newArguments.get();
|
else args = newArguments.get();
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
if (e.getCause() instanceof RuntimeException) throw (RuntimeException) e.getCause();
|
||||||
|
else throw e;
|
||||||
} finally {
|
} finally {
|
||||||
|
swap(loader, previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final URL url = new URL("file:" + System.getProperty("sbt.launch.jar"));
|
||||||
|
final URLClassLoader loader = new URLClassLoader(new URL[] {url}, top());
|
||||||
|
final Class<?> boot = loader.loadClass("xsbt.boot.Boot");
|
||||||
|
// If we don't initialize the arguments this way, then the call to invoke on
|
||||||
|
// xsbt.boot.Boot.main fails with an IllegalArgumentException
|
||||||
|
final Object newArgs = Array.newInstance(loader.loadClass("java.lang.String"), args.length);
|
||||||
|
for (int i = 0; i < args.length; ++i) ((String[]) newArgs)[i] = args[i];
|
||||||
|
final ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loader.close();
|
Thread.currentThread().setContextClassLoader(loader);
|
||||||
|
boot.getDeclaredMethod("main", newArgs.getClass()).invoke(null, newArgs);
|
||||||
|
return Optional.empty();
|
||||||
|
} finally {
|
||||||
|
swap(loader, previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassLoader top() {
|
||||||
|
ClassLoader result = ClassLoader.getSystemClassLoader();
|
||||||
|
while (result.getParent() != null) result = result.getParent();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void swap(final URLClassLoader old, final ClassLoader stashed) {
|
||||||
|
try {
|
||||||
|
old.close();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
}
|
}
|
||||||
Thread.currentThread().setContextClassLoader(previous);
|
Thread.currentThread().setContextClassLoader(stashed);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copy(final File[] files, final File toDirectory) {
|
private static void copy(final File[] files, final File toDirectory) {
|
||||||
|
|
@ -146,18 +180,26 @@ public class ScriptedLauncher {
|
||||||
final Class<?> clazz = loader.loadClass("sbt.xMain");
|
final Class<?> clazz = loader.loadClass("sbt.xMain");
|
||||||
final Object instance = clazz.getConstructor().newInstance();
|
final Object instance = clazz.getConstructor().newInstance();
|
||||||
final Method run = clazz.getDeclaredMethod("run", loader.loadClass("xsbti.AppConfiguration"));
|
final Method run = clazz.getDeclaredMethod("run", loader.loadClass("xsbti.AppConfiguration"));
|
||||||
final Object runResult = run.invoke(instance, conf);
|
Object runResult;
|
||||||
if (runResult instanceof xsbti.Reboot) newArguments.set(((Reboot) runResult).arguments());
|
try {
|
||||||
else {
|
runResult = run.invoke(instance, conf);
|
||||||
if (runResult instanceof xsbti.Exit) {
|
} catch (final InvocationTargetException e) {
|
||||||
|
runResult = e.getCause();
|
||||||
|
}
|
||||||
|
if (runResult instanceof Reboot) newArguments.set(((Reboot) runResult).arguments());
|
||||||
|
else if (runResult instanceof FullReload)
|
||||||
|
newArguments.set(((FullReload) runResult).arguments());
|
||||||
|
else if (runResult instanceof Exit) {
|
||||||
result.set(((Exit) runResult).code());
|
result.set(((Exit) runResult).code());
|
||||||
} else if (runResult instanceof xsbti.Continue) {
|
} else if (runResult instanceof Continue) {
|
||||||
result.set(Integer.MAX_VALUE);
|
result.set(Integer.MAX_VALUE);
|
||||||
|
} else if (runResult instanceof Throwable) {
|
||||||
|
((Throwable) runResult).printStackTrace(System.err);
|
||||||
|
result.set(1);
|
||||||
} else {
|
} else {
|
||||||
handleUnknownMainResult((MainResult) runResult);
|
handleUnknownMainResult((MainResult) runResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static void handleUnknownMainResult(MainResult x) {
|
private static void handleUnknownMainResult(MainResult x) {
|
||||||
final String clazz = x == null ? "" : " (class: " + x.getClass() + ")";
|
final String clazz = x == null ? "" : " (class: " + x.getClass() + ")";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue