From 3493aa528566a41a0a3bc781131f4f39c116a0ed Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 4 Mar 2010 13:30:13 -0500 Subject: [PATCH] Make 'run' reuse warm Scala class loader and same JLine as sbt --- .gitignore | 3 +++ project/build/SbtProject.scala | 2 +- src/main/scala/sbt/DefaultProject.scala | 2 +- src/main/scala/sbt/Run.scala | 36 +++++++++++++++++++++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 130e42047..3f1ed73c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ LazyJettyRun6.scala LazyJettyRun7.scala +install/project/boot/ +scripted/project/boot/ +project/plugins/project/ diff --git a/project/build/SbtProject.scala b/project/build/SbtProject.scala index 23ef7c534..8edb601be 100644 --- a/project/build/SbtProject.scala +++ b/project/build/SbtProject.scala @@ -19,7 +19,7 @@ class SbtProject(info: ProjectInfo) extends DefaultProject(info) with test.SbtSc //val publishTo = Resolver.file("technically", new File("/var/dbwww/repo/")) val technically = Resolver.url("technically.us", new URL("http://databinder.net/repo/"))(Resolver.ivyStylePatterns) - override def compileOptions = Nil + override def compileOptions = CompileOption("-Xno-varargs-conversion") :: Nil /** configuration of scripted testing **/ // Set to false to show logging as it happens without buffering, true to buffer until it completes and only show if the task fails. diff --git a/src/main/scala/sbt/DefaultProject.scala b/src/main/scala/sbt/DefaultProject.scala index ebff0a888..9b67ce97d 100644 --- a/src/main/scala/sbt/DefaultProject.scala +++ b/src/main/scala/sbt/DefaultProject.scala @@ -250,7 +250,7 @@ abstract class BasicScalaProject extends ScalaProject with BasicDependencyProjec fork match { case Some(fr: ForkScalaRun) => new ForkRun(fr) - case _ => new Run(buildCompiler) + case _ => new Run(buildScalaInstance) } } diff --git a/src/main/scala/sbt/Run.scala b/src/main/scala/sbt/Run.scala index d82974634..44e9fb34d 100644 --- a/src/main/scala/sbt/Run.scala +++ b/src/main/scala/sbt/Run.scala @@ -10,6 +10,7 @@ import scala.tools.nsc.util.ClassPath import java.io.File import java.net.{URL, URLClassLoader} +import java.lang.reflect.Modifier.{isPublic, isStatic} trait ScalaRun { @@ -35,14 +36,45 @@ class ForkRun(config: ForkScalaRun) extends ScalaRun Some("Nonzero exit code returned from " + label + ": " + exitCode) } } -class Run(compiler: xsbt.AnalyzingCompiler) extends ScalaRun +class Run(instance: xsbt.ScalaInstance) extends ScalaRun { /** Runs the class 'mainClass' using the given classpath and options using the scala runner.*/ def run(mainClass: String, classpath: Iterable[Path], options: Seq[String], log: Logger) = { - def execute = compiler.run(Set() ++ classpath.map(_.asFile), mainClass, options, log) + log.info("Running " + mainClass + " " + options.mkString(" ")) + + def execute = + try { run0(mainClass, classpath, options, log) } + catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause } + Run.executeTrapExit( execute, log ) } + private def run0(mainClassName: String, classpath: Iterable[Path], options: Seq[String], log: Logger) + { + val loader = getLoader(classpath, log) + val main = getMainMethod(mainClassName, loader) + + val currentThread = Thread.currentThread + val oldLoader = Thread.currentThread.getContextClassLoader() + currentThread.setContextClassLoader(loader) + try { main.invoke(null, options.toArray[String].asInstanceOf[Array[String]] ) } + finally { currentThread.setContextClassLoader(oldLoader) } + } + def getMainMethod(mainClassName: String, loader: ClassLoader) = + { + val mainClass = Class.forName(mainClassName, true, loader) + val method = mainClass.getMethod("main", classOf[Array[String]]) + val modifiers = method.getModifiers + if(!isPublic(modifiers)) throw new NoSuchMethodException(mainClassName + ".main is not public") + if(!isStatic(modifiers)) throw new NoSuchMethodException(mainClassName + ".main is not static") + method + } + def getLoader(classpath: Iterable[Path], log: Logger) = + { + val classpathURLs = classpath.toSeq.map(_.asURL).toArray + log.debug(" Classpath:\n\t" + classpathURLs.mkString("\n\t")) + new URLClassLoader( classpathURLs, instance.loader) + } } /** This module is an interface to starting the scala interpreter or runner.*/