Some 11th hour modifications with the dual purpose of a smooth

console life for sbt and so the repl can be used on google app engine.
Although this patch may look largish to be entering at RC4, there
isn't a lot going on.  It's trying to make these dangerous things:

 - property and environment variable accesses
 - thread creation
 - signal handler installation

happpen in a sufficiently uniform way that people who don't
want them and places who don't allow them are not left with an
unfixable situation where things blow up inside private methods.
Also, the (ahem) lower than usual elegance levels are due to it
being intended for 2.9.x as well.  Review by harrah.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25549 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2011-08-23 22:57:15 +00:00
parent c8630fa0da
commit a978f24ba3
9 changed files with 96 additions and 35 deletions

View File

@ -119,7 +119,6 @@ abstract class SymbolTable extends api.Universe
object perRunCaches {
import java.lang.ref.WeakReference
import scala.tools.util.Signallable
import scala.runtime.ScalaRunTime.stringOf
// We can allow ourselves a structural type, these methods
@ -143,9 +142,9 @@ abstract class SymbolTable extends api.Universe
))
}
}
if (settings.debug.value) {
println(Signallable("dump compiler caches")(dumpCaches()))
}
// if (settings.debug.value) {
// println(Signallable("dump compiler caches")(dumpCaches()))
// }
def recordCache[T <: Clearable](cache: T): T = {
caches += new WeakReference(cache)

View File

@ -66,7 +66,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
// Install a signal handler so we can be prodded.
private val signallable =
if (isReplDebug) Signallable("Dump repl state.")(dumpCommand())
if (isReplDebug && !settings.Yreplsync.value)
Signallable("Dump repl state.")(dumpCommand())
else null
// classpath entries added via :cp
@ -95,19 +96,21 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
override lazy val formatting = new Formatting {
def prompt = ILoop.this.prompt
}
override protected def createLineManager() = new Line.Manager {
override def onRunaway(line: Line[_]): Unit = {
val template = """
|// She's gone rogue, captain! Have to take her out!
|// Calling Thread.stop on runaway %s with offending code:
|// scala> %s""".stripMargin
override protected def createLineManager(): Line.Manager =
if (ReplPropsKludge.noThreadCreation(settings)) null else new Line.Manager {
override def onRunaway(line: Line[_]): Unit = {
val template = """
|// She's gone rogue, captain! Have to take her out!
|// Calling Thread.stop on runaway %s with offending code:
|// scala> %s""".stripMargin
echo(template.format(line.thread, line.code))
// XXX no way to suppress the deprecation warning
line.thread.stop()
in.redrawLine()
echo(template.format(line.thread, line.code))
// XXX no way to suppress the deprecation warning
line.thread.stop()
in.redrawLine()
}
}
}
override protected def parentClassLoader =
settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader )
}

View File

@ -47,7 +47,7 @@ trait ILoopInit {
}
ignoring(classOf[Exception]) {
SignalManager("INT") = {
if (intp == null)
if (intp == null || intp.lineManager == null)
onExit()
else if (intp.lineManager.running)
intp.lineManager.cancel()

View File

@ -62,7 +62,7 @@ import IMain._
*/
class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports {
imain =>
private var currentSettings: Settings = initialSettings
def settings = currentSettings
def savingSettings[T](fn: Settings => Unit)(body: => T): T = {
@ -265,7 +265,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Create a line manager. Overridable. */
protected def createLineManager(): Line.Manager =
if (replProps.noThreads) null else new Line.Manager
if (ReplPropsKludge.noThreadCreation(settings)) null else new Line.Manager
/** Instantiate a compiler. Overridable. */
protected def newCompiler(settings: Settings, reporter: Reporter) = {
@ -967,7 +967,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** load and run the code using reflection */
def loadAndRun: (String, Boolean) = {
if (replProps.noThreads) return {
if (lineManager == null) return {
try { ("" + (lineRep call sessionNames.print), true) }
catch { case ex => (lineRep.bindError(ex), false) }
}

View File

@ -24,3 +24,9 @@ class ReplProps {
val powerInitCode = Prop[JFile]("scala.repl.power.initcode")
val powerBanner = Prop[JFile]("scala.repl.power.banner")
}
object ReplPropsKludge {
// !!! short term binary compatibility hack for 2.9.1 to put this
// here - needed a not previously existing object.
def noThreadCreation(settings: Settings) = replProps.noThreads || settings.Yreplsync.value
}

View File

@ -0,0 +1,39 @@
/* NSC -- new Scala compiler
* Copyright 2006-2011 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools
package reflect
import scala.util.PropertiesTrait
import java.security.AccessControlException
/** For placing a wrapper function around property functions.
* Motivated by places like google app engine throwing exceptions
* on property lookups.
*/
trait WrappedProperties extends PropertiesTrait {
def wrap[T](body: => T): Option[T]
protected def propCategory = "wrapped"
protected def pickJarBasedOn = this.getClass
override def propIsSet(name: String) = wrap(super.propIsSet(name)) exists (x => x)
override def propOrElse(name: String, alt: String) = wrap(super.propOrElse(name, alt)) getOrElse alt
override def setProp(name: String, value: String) = wrap(super.setProp(name, value)) orNull
override def clearProp(name: String) = wrap(super.clearProp(name)) orNull
override def envOrElse(name: String, alt: String) = wrap(super.envOrElse(name, alt)) getOrElse alt
override def envOrNone(name: String) = wrap(super.envOrNone(name)).flatten
def systemProperties: Iterator[(String, String)] = {
import scala.collection.JavaConverters._
wrap(System.getProperties.asScala.iterator) getOrElse Iterator.empty
}
}
object WrappedProperties {
object AccessControl extends WrappedProperties {
def wrap[T](body: => T) = try Some(body) catch { case _: AccessControlException => None }
}
}

View File

@ -7,7 +7,7 @@ package scala.tools
package util
import java.net.{ URL, MalformedURLException }
import scala.util.Properties._
import scala.tools.reflect.WrappedProperties.AccessControl
import nsc.{ Settings, GenericRunnerSettings }
import nsc.util.{ ClassPath, JavaClassPath, ScalaClassLoader }
import nsc.io.{ File, Directory, Path, AbstractFile }
@ -18,6 +18,10 @@ import PartialFunction.condOpt
// https://wiki.scala-lang.org/display/SW/Classpath
object PathResolver {
// Imports property/environment functions which suppress
// security exceptions.
import AccessControl._
def firstNonEmpty(xs: String*) = xs find (_ != "") getOrElse ""
/** Map all classpath elements to absolute paths and reconstruct the classpath.
@ -34,10 +38,9 @@ object PathResolver {
/** Values found solely by inspecting environment or property variables.
*/
object Environment {
private def searchForBootClasspath = {
import scala.collection.JavaConversions._
System.getProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse ""
}
private def searchForBootClasspath = (
systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse ""
)
/** Environment variables which java pays attention to so it
* seems we do as well.

View File

@ -6,11 +6,17 @@
package scala.tools
package util
import java.security.AccessControlException
/** A class for things which are signallable.
*/
abstract class Signallable[T] private (val signal: String, val description: String) {
private var last: Option[T] = None
private def lastString = last filterNot (_ == ()) map (_.toString) getOrElse ""
private def lastString = last match {
case Some(()) => ""
case Some(x) => "" + x
case _ => ""
}
/** The most recent result from the signal handler. */
def lastResult: Option[T] = last
@ -29,8 +35,9 @@ abstract class Signallable[T] private (val signal: String, val description: Stri
object Signallable {
/** Same as the other apply, but an open signal is found for you.
*/
def apply[T](description: String)(body: => T): Signallable[T] =
def apply[T](description: String)(body: => T): Signallable[T] = wrap {
apply(SignalManager.findOpenSignal().name, description)(body)
}
/** Given a signal name, a description, and a handler body, this
* registers a signal handler and returns the Signallable instance.
@ -38,16 +45,21 @@ object Signallable {
* SignalManager.info(), or sending SIGINFO to the manager will
* dump it to console.
*/
def apply[T](signal: String, description: String)(body: => T): Signallable[T] = {
val result = new Signallable[T](signal, description) {
def onSignal(): T = {
def apply[T](signal: String, description: String)(body: => T): Signallable[T] = wrap {
val result = create[T](signal, description, body)
SignalManager.public(signal, description)(result.onSignal())
result
}
private def wrap[T](body: => Signallable[T]): Signallable[T] =
try body catch { case _: AccessControlException => null }
private def create[T](signal: String, description: String, body: => T): Signallable[T] =
new Signallable[T](signal, description) {
def onSignal = {
val result = body
last = Some(result)
result
}
}
SignalManager.public(signal, description)(result.onSignal())
result
}
}

View File

@ -11,7 +11,6 @@ package nest
import java.io.{ File }
import java.util.StringTokenizer
import scala.util.Properties.{ setProp }
import scala.tools.util.Signallable
import scala.tools.nsc.util.ScalaClassLoader
import scala.tools.nsc.io.Path
import scala.collection.{ mutable, immutable }