From 6dfcae30bfcdc93509755185f814c8e318a64012 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 7 Sep 2010 17:48:09 +0000 Subject: Some modifications to repl classloading to make... Some modifications to repl classloading to make it usable in managed classloader environments. Contributed by mark harrah. Review by rytz. --- src/compiler/scala/tools/nsc/Interpreter.scala | 15 +++++++----- src/compiler/scala/tools/nsc/InterpreterLoop.scala | 3 ++- .../scala/tools/nsc/settings/MutableSettings.scala | 28 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 7dd6d3ba04..3be1b44a4c 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -229,7 +229,9 @@ class Interpreter(val settings: Settings, out: PrintWriter) { private def methodByName(c: Class[_], name: String): reflect.Method = c.getMethod(name, classOf[Object]) - protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader() + protected def parentClassLoader: ClassLoader = + settings.explicitParentLoader.getOrElse( this.getClass.getClassLoader() ) + def getInterpreterClassLoader() = classLoader // Set the current Java "context" class loader to this interpreter's class loader @@ -1267,15 +1269,16 @@ object Interpreter { } } } - def breakIf(assertion: => Boolean, args: DebugParam[_]*): Unit = - if (assertion) break(args.toList) + // provide the enclosing type T + // in order to set up the interpreter's classpath and parent class loader properly + def breakIf[T: Manifest](assertion: => Boolean, args: DebugParam[_]*): Unit = + if (assertion) break[T](args.toList) // start a repl, binding supplied args - def break(args: List[DebugParam[_]]): Unit = { + def break[T: Manifest](args: List[DebugParam[_]]): Unit = { val intLoop = new InterpreterLoop intLoop.settings = new Settings(Console.println) - // XXX come back to the dot handling - intLoop.settings.classpath.value = "." + intLoop.settings.embeddedDefaults[T] intLoop.createInterpreter intLoop.in = InteractiveReader.createDefault(intLoop.interpreter) diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index f68ce4a5b4..bdcd7b9f58 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -117,7 +117,8 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite settings.classpath append addedClasspath interpreter = new Interpreter(settings, out) { - override protected def parentClassLoader = classOf[InterpreterLoop].getClassLoader + override protected def parentClassLoader = + settings.explicitParentLoader.getOrElse( classOf[InterpreterLoop].getClassLoader ) } interpreter.setContextClassLoader() // interpreter.quietBind("settings", "scala.tools.nsc.InterpreterSettings", interpreter.isettings) diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index 1e0e00e01d..c15a4279fb 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -11,6 +11,7 @@ package settings import io.{AbstractFile, VirtualDirectory} import scala.tools.util.StringOps import scala.collection.mutable.ListBuffer +import scala.io.Source /** A mutable Settings object. */ @@ -160,6 +161,33 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal doArgs(args) } + /** Initializes these settings for embedded use by type `T`. + * The class loader defining `T` should provide resources `app.class.path` + * and `boot.class.path`. These resources should contain the application + * and boot classpaths in the same form as would be passed on the command line.*/ + def embeddedDefaults[T: Manifest]: Unit = + embeddedDefaults(implicitly[Manifest[T]].erasure.getClassLoader) + + /** Initializes these settings for embedded use by a class from the given class loader. + * The class loader for `T` should provide resources `app.class.path` + * and `boot.class.path`. These resources should contain the application + * and boot classpaths in the same form as would be passed on the command line.*/ + def embeddedDefaults(loader: ClassLoader) { + explicitParentLoader = Option(loader) // for the Interpreter parentClassLoader + getClasspath("app", loader) foreach { classpath.value = _ } + getClasspath("boot", loader) foreach { bootclasspath append _ } + } + + /** The parent loader to use for the interpreter.*/ + private[nsc] var explicitParentLoader: Option[ClassLoader] = None + + /** Retrieves the contents of resource "${id}.class.path" from `loader` + * (wrapped in Some) or None if the resource does not exist.*/ + private def getClasspath(id: String, loader: ClassLoader): Option[String] = + Option(loader).flatMap(ld => Option(ld.getResource(id + ".class.path"))).map { cp => + Source.fromURL(cp).mkString + } + // a wrapper for all Setting creators to keep our list up to date private def add[T <: Setting](s: T): T = { allSettings += s -- cgit v1.2.3