summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-09-07 22:16:58 +0000
committerPaul Phillips <paulp@improving.org>2009-09-07 22:16:58 +0000
commitaef123719dbe81b20fe3eed6390df9d62fd24a0b (patch)
tree0148ea23a2d709ac7173edf3e87122bb9d580eb3 /src/compiler/scala/tools/nsc
parent3335e037a83edef65eb3c6fa75be23c0d0a46aab (diff)
downloadscala-aef123719dbe81b20fe3eed6390df9d62fd24a0b.tar.gz
scala-aef123719dbe81b20fe3eed6390df9d62fd24a0b.tar.bz2
scala-aef123719dbe81b20fe3eed6390df9d62fd24a0b.zip
Reverts scala.io.* to its natural state, and th...
Reverts scala.io.* to its natural state, and the rest of trunk to using java.io.File. Anyone who wants to salvage any usable bits is of course welcome to do so, so long as they also assume responsibility for those bits.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala53
-rw-r--r--src/compiler/scala/tools/nsc/CompileSocket.scala132
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala9
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala445
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala68
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala80
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualDirectory.scala36
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala14
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala479
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugin.scala91
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugins.scala146
11 files changed, 905 insertions, 648 deletions
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index 85c992a9e2..010d183bc8 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -6,9 +6,10 @@
package scala.tools.nsc
-import java.io.{ BufferedOutputStream, FileOutputStream, PrintStream, File => JFile }
-import scala.io.File
+import java.io.{BufferedOutputStream, File, FileOutputStream, PrintStream}
+import java.lang.{Runtime, System, Thread}
+import scala.concurrent.ops.spawn
import scala.tools.nsc.reporters.{Reporter, ConsoleReporter}
import scala.tools.nsc.util.FakePos //Position
import scala.tools.util.SocketServer
@@ -21,8 +22,7 @@ import scala.tools.util.SocketServer
* @author Martin Odersky
* @version 1.0
*/
-class StandardCompileServer extends SocketServer
-{
+class StandardCompileServer extends SocketServer {
def compileSocket: CompileSocket = CompileSocket // todo: make this a lazy val
val versionMsg = "Fast Scala compiler " +
@@ -44,7 +44,6 @@ class StandardCompileServer extends SocketServer
}
private val runtime = Runtime.getRuntime()
- import runtime.{ totalMemory, freeMemory, maxMemory }
var reporter: ConsoleReporter = _
@@ -55,31 +54,24 @@ class StandardCompileServer extends SocketServer
}
override def timeout() {
- if (!compileSocket.portFile(port).exists)
+ if (!compileSocket.portFile(port).exists())
fatal("port file no longer exists; skipping cleanup")
}
- def printMemoryStats() {
- System.out.println("New session, total memory = %s, max memory = %s, free memory = %s".format(
- totalMemory, maxMemory, freeMemory))
- System.out.flush()
- }
-
- def isMemoryFullEnough() = {
- runtime.gc()
- (totalMemory - freeMemory).toDouble / maxMemory.toDouble > MaxCharge
- }
-
protected def newOfflineCompilerCommand(
arguments: List[String],
settings: Settings,
error: String => Unit,
- interactive: Boolean
- ) = new OfflineCompilerCommand(arguments, settings, error, interactive)
+ interactive: Boolean)
+ = new OfflineCompilerCommand(arguments, settings, error, interactive)
def session() {
- printMemoryStats()
- val password = compileSocket getPassword port
+ System.out.println("New session" +
+ ", total memory = "+ runtime.totalMemory() +
+ ", max memory = " + runtime.maxMemory() +
+ ", free memory = " + runtime.freeMemory)
+ System.out.flush()
+ val password = compileSocket.getPassword(port)
val guessedPassword = in.readLine()
val input = in.readLine()
if ((input ne null) && password == guessedPassword) {
@@ -135,17 +127,24 @@ class StandardCompileServer extends SocketServer
shutDown = true
}
reporter.printSummary()
- if (isMemoryFullEnough)
- compiler = null
+ runtime.gc()
+ if ((runtime.totalMemory() - runtime.freeMemory()).toDouble /
+ runtime.maxMemory().toDouble > MaxCharge) compiler = null
}
}
}
/** A directory holding redirected output */
- private val redirectDir = (compileSocket.tmpDir / "output-redirects").createDirectory()
-
- private def redirect(setter: PrintStream => Unit, filename: String): Unit =
- setter(new PrintStream((redirectDir / filename).createFile().bufferedOutput()))
+ private val redirectDir = new File(compileSocket.tmpDir, "output-redirects")
+ redirectDir.mkdirs
+
+ private def redirect(setter: PrintStream => Unit, filename: String) {
+ setter(
+ new PrintStream(
+ new BufferedOutputStream(
+ new FileOutputStream(
+ new File(redirectDir, filename)))))
+ }
def main(args: Array[String]) {
redirect(System.setOut, "scala-compile-server-out.log")
diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala
index 30b8882904..8cb679f24b 100644
--- a/src/compiler/scala/tools/nsc/CompileSocket.scala
+++ b/src/compiler/scala/tools/nsc/CompileSocket.scala
@@ -6,16 +6,12 @@
package scala.tools.nsc
-import java.io.{ IOException, FileNotFoundException, PrintWriter, FileOutputStream }
-import java.io.{ BufferedReader, FileReader }
+import java.lang.{Thread, System, Runtime}
+import java.lang.NumberFormatException
+import java.io.{File, IOException, PrintWriter, FileOutputStream}
+import java.io.{BufferedReader, FileReader}
import java.util.regex.Pattern
import java.net._
-import java.security.SecureRandom
-
-import scala.io.{ File, Path }
-import scala.util.control.Exception.catching
-
-// class CompileChannel { }
/** This class manages sockets for the fsc offline compiler. */
class CompileSocket {
@@ -29,13 +25,17 @@ class CompileSocket {
protected def cmdName = Properties.cmdName //todo: lazy val
/** The vm part of the command to start a new scala compile server */
- protected val vmCommand = Properties.scalaHome match {
- case null => cmdName
- case dirname =>
- val trial = File(dirname) / "bin" / cmdName
- if (trial.canRead) trial.path
- else cmdName
- }
+ protected val vmCommand =
+ Properties.scalaHome match {
+ case null =>
+ cmdName
+ case dirname =>
+ val trial = new File(new File(dirname, "bin"), cmdName)
+ if (trial.canRead)
+ trial.getPath
+ else
+ cmdName
+ }
/** The class name of the scala compile server */
protected val serverClass = "scala.tools.nsc.CompileServer"
@@ -44,7 +44,7 @@ class CompileSocket {
val errorRegex = ".*(errors? found|don't know|bad option).*"
/** A Pattern object for checking compiler output for errors */
- val errorPattern = Pattern compile errorRegex
+ val errorPattern = Pattern.compile(errorRegex)
protected def error(msg: String) = System.err.println(msg)
@@ -59,7 +59,8 @@ class CompileSocket {
/** A temporary directory to use */
val tmpDir = {
val udir = Option(Properties.userName) getOrElse "shared"
- val f = (Path(Properties.tmpDir) / "scala-devel" / udir).createDirectory()
+ val f = new File(Properties.tmpDir, "scala-devel/" + udir)
+ f.mkdirs()
if (f.isDirectory && f.canWrite) {
info("[Temp directory: " + f + "]")
@@ -69,7 +70,8 @@ class CompileSocket {
}
/* A directory holding port identification files */
- val portsDir = (tmpDir / dirName).createDirectory()
+ val portsDir = new File(tmpDir, dirName)
+ portsDir.mkdirs
/** Maximum number of polls for an available port */
private val MaxAttempts = 100
@@ -101,16 +103,24 @@ class CompileSocket {
}
/** The port identification file */
- def portFile(port: Int) = portsDir / File(port.toString)
+ def portFile(port: Int) = new File(portsDir, port.toString())
/** Poll for a server port number; return -1 if none exists yet */
- private def pollPort(): Int =
- portsDir.list.toList match {
- case Nil => -1
- case p :: xs =>
- xs forall (_.delete())
- p.name.toInt
- }
+ private def pollPort(): Int = {
+ val hits = portsDir.listFiles()
+ if (hits.length == 0) -1
+ else
+ try {
+ for (i <- 1 until hits.length) hits(i).delete()
+ hits(0).getName.toInt
+ } catch {
+ case ex: NumberFormatException =>
+ fatal(ex.toString() +
+ "\nbad file in temp directory: " +
+ hits(0).getAbsolutePath() +
+ "\nplease remove the file and try again")
+ }
+ }
/** Get the port number to which a scala compile server is connected;
* If no server is running yet, then create one.
@@ -121,7 +131,6 @@ class CompileSocket {
if (port < 0)
startNewServer(vmArgs)
-
while (port < 0 && attempts < MaxAttempts) {
attempts += 1
Thread.sleep(sleepTime)
@@ -135,23 +144,25 @@ class CompileSocket {
/** Set the port number to which a scala compile server is connected */
def setPort(port: Int) {
- val file = portFile(port)
- val secret = new SecureRandom().nextInt.toString
-
- try file writeAll List(secret) catch {
- case e @ (_: FileNotFoundException | _: SecurityException) =>
- fatal("Cannot create file: %s".format(file.path))
+ try {
+ val f = new PrintWriter(new FileOutputStream(portFile(port)))
+ f.println(new java.security.SecureRandom().nextInt.toString)
+ f.close()
+ } catch {
+ case ex: /*FileNotFound+Security*/Exception =>
+ fatal("Cannot create file: " +
+ portFile(port).getAbsolutePath())
}
}
/** Delete the port number to which a scala compile server was connected */
- def deletePort(port: Int) = portFile(port).delete()
+ def deletePort(port: Int) { portFile(port).delete() }
/** Get a socket connected to a daemon. If create is true, then
* create a new daemon if necessary. Returns null if the connection
* cannot be established.
*/
- def getOrCreateSocket(vmArgs: String, create: Boolean = true): Socket = {
+ def getOrCreateSocket(vmArgs: String, create: Boolean): Socket = {
val nAttempts = 49 // try for about 5 seconds
def getsock(attempts: Int): Socket =
if (attempts == 0) {
@@ -182,40 +193,45 @@ class CompileSocket {
getsock(nAttempts)
}
- // XXX way past time for this to be central
- def parseInt(x: String): Option[Int] =
- try { Some(x.toInt) }
- catch { case _: NumberFormatException => None }
+ /** Same as getOrCreateSocket(vmArgs, true). */
+ def getOrCreateSocket(vmArgs: String): Socket =
+ getOrCreateSocket(vmArgs, true)
def getSocket(serverAdr: String): Socket = {
- def fail = fatal("Malformed server address: %s; exiting" format serverAdr)
- (serverAdr indexOf ':') match {
- case -1 => fail
- case cpos =>
- val hostName: String = serverAdr take cpos
- parseInt(serverAdr drop (cpos + 1)) match {
- case Some(port) => getSocket(hostName, port)
- case _ => fail
- }
+ val cpos = serverAdr indexOf ':'
+ if (cpos < 0)
+ fatal("Malformed server address: " + serverAdr + "; exiting")
+ else {
+ val hostName = serverAdr.substring(0, cpos)
+ val port = try {
+ serverAdr.substring(cpos+1).toInt
+ } catch {
+ case ex: Throwable =>
+ fatal("Malformed server address: " + serverAdr + "; exiting")
+ }
+ getSocket(hostName, port)
}
}
def getSocket(hostName: String, port: Int): Socket =
- try new Socket(hostName, port) catch {
- case e @ (_: IOException | _: SecurityException) =>
- fatal("Unable to establish connection to server %s:%d; exiting".format(hostName, port))
+ try {
+ new Socket(hostName, port)
+ } catch {
+ case e: /*IO+Security*/Exception =>
+ fatal("Unable to establish connection to server " +
+ hostName + ":" + port + "; exiting")
}
def getPassword(port: Int): String = {
- val ff = portFile(port)
- val f = ff.bufferedReader()
-
+ val ff = portFile(port)
+ val f = new BufferedReader(new FileReader(ff))
// allow some time for the server to start up
- def check = {
- Thread sleep 100
- ff.length
+ var retry = 50
+ while (ff.length() == 0 && retry > 0) {
+ Thread.sleep(100)
+ retry -= 1
}
- if (Iterator continually check take 50 find (_ > 0) isEmpty) {
+ if (ff.length() == 0) {
ff.delete()
fatal("Unable to establish connection to server.")
}
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index d34c4a8640..3f44bcdf9b 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -957,6 +957,15 @@ object Interpreter {
intLoop.closeInterpreter
}
+ /** Delete a directory tree recursively. Use with care! */
+ private[nsc] def deleteRecursively(path: File): Unit =
+ if (path.exists) {
+ if (path.isDirectory)
+ path.listFiles foreach deleteRecursively
+
+ path.delete
+ }
+
/** Heuristically strip interpreter wrapper prefixes
* from an interpreter output string.
*/
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index f99ea24031..e31dcd38f9 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -6,19 +6,12 @@
package scala.tools.nsc
-import java.io.{
- InputStream, OutputStream,
- BufferedReader, FileInputStream, FileOutputStream,
- FileReader, InputStreamReader, PrintWriter, FileWriter,
- IOException
-}
-import scala.io.{ Directory, File, Path }
-// import scala.io.arm.ManagedResource
-import java.io.{ File => JFile }
+import java.io.{BufferedReader, File, FileInputStream, FileOutputStream,
+ FileReader, InputStreamReader, PrintWriter,
+ FileWriter, IOException}
import java.lang.reflect.InvocationTargetException
import java.net.URL
-import java.util.jar.{ JarEntry, JarOutputStream }
-import java.util.regex.Pattern
+import java.util.jar.{JarEntry, JarOutputStream}
import scala.tools.nsc.io.PlainFile
import scala.tools.nsc.reporters.{Reporter,ConsoleReporter}
@@ -50,123 +43,136 @@ import scala.tools.nsc.util.{ClassPath, CompoundSourceFile, BatchSourceFile, Sou
* @todo It would be better if error output went to stderr instead
* of stdout...
*/
-object ScriptRunner
-{
- /* While I'm chasing down the fsc and script bugs. */
- def DBG(msg: Any) {
- System.err.println(msg.toString)
- System.err.flush()
- }
-
+object ScriptRunner {
/** Default name to use for the wrapped script */
val defaultScriptMain = "Main"
- private def addShutdownHook(body: => Unit) =
- Runtime.getRuntime addShutdownHook new Thread { override def run { body } }
-
/** Pick a main object name from the specified settings */
- def scriptMain(settings: Settings) = settings.script.value match {
- case "" => defaultScriptMain
- case x => x
- }
-
- /** Choose a jar filename to hold the compiled version of a script. */
+ def scriptMain(settings: Settings) =
+ if (settings.script.value == "")
+ defaultScriptMain
+ else
+ settings.script.value
+
+ /** Choose a jar filename to hold the compiled version
+ * of a script
+ */
private def jarFileFor(scriptFile: String): File = {
- val name =
- if (scriptFile endsWith ".jar") scriptFile
- else scriptFile + ".jar"
-
- File(name)
- }
-
- def copyStreams(in: InputStream, out: OutputStream) = {
- val buf = new Array[Byte](10240)
-
- def loop: Unit = in.read(buf, 0, buf.length) match {
- case -1 => in.close()
- case n => out.write(buf, 0, n) ; loop
- }
+ val filename =
+ if (scriptFile.matches(".*\\.[^.\\\\/]*"))
+ scriptFile.replaceFirst("\\.[^.\\\\/]*$", ".jar")
+ else
+ scriptFile + ".jar"
- loop
+ new File(filename)
}
/** Try to create a jar file out of all the contents
* of the directory <code>sourcePath</code>.
*/
- private def tryMakeJar(jarFile: File, sourcePath: Directory) = {
- def addFromDir(jar: JarOutputStream, dir: Directory, prefix: String) {
- def addFileToJar(entry: File) = {
- jar putNextEntry new JarEntry(prefix + entry.name)
- copyStreams(entry.inputStream, jar)
- jar.closeEntry
- }
-
- dir.list foreach { entry =>
- if (entry.isFile) addFileToJar(entry.toFile)
- else addFromDir(jar, entry.toDirectory, prefix + entry.name + "/")
+ private def tryMakeJar(jarFile: File, sourcePath: File) = {
+ try {
+ val jarFileStream = new FileOutputStream(jarFile)
+ val jar = new JarOutputStream(jarFileStream)
+ val buf = new Array[Byte](10240)
+
+ def addFromDir(dir: File, prefix: String) {
+ for (entry <- dir.listFiles) {
+ if (entry.isFile) {
+ jar.putNextEntry(new JarEntry(prefix + entry.getName))
+
+ val input = new FileInputStream(entry)
+ var n = input.read(buf, 0, buf.length)
+ while (n >= 0) {
+ jar.write (buf, 0, n)
+ n = input.read(buf, 0, buf.length)
+ }
+ jar.closeEntry
+ input.close
+ } else {
+ addFromDir(entry, prefix + entry.getName + "/")
+ }
+ }
}
- }
- try {
- val jar = new JarOutputStream(jarFile.outputStream())
- addFromDir(jar, sourcePath, "")
+ addFromDir(sourcePath, "")
jar.close
- }
- catch {
- case _: Error => jarFile.delete() // XXX what errors to catch?
+ } catch {
+ case _:Error => jarFile.delete // XXX what errors to catch?
}
}
+
/** Read the entire contents of a file as a String. */
- private def contentsOfFile(filename: String) = File(filename).slurp()
+ private def contentsOfFile(filename: String): String = {
+ val strbuf = new StringBuilder
+ val reader = new FileReader(filename)
+ val cbuf = new Array[Char](1024)
+ while(true) {
+ val n = reader.read(cbuf)
+ if (n <= 0)
+ return strbuf.toString
+ strbuf.append(cbuf, 0, n)
+ }
+ throw new Error("impossible")
+ }
/** Find the length of the header in the specified file, if
* there is one. The header part starts with "#!" or "::#!"
* and ends with a line that begins with "!#" or "::!#".
*/
private def headerLength(filename: String): Int = {
- val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE)
+ import java.util.regex._
+
val fileContents = contentsOfFile(filename)
- def isValid = List("#!", "::#!") exists (fileContents startsWith _)
- if (!isValid) 0 else {
- val matcher = headerPattern matcher fileContents
- if (matcher.find) matcher.end
- else throw new IOException("script file does not close its header with !# or ::!#")
- }
+ if (!(fileContents.startsWith("#!") || fileContents.startsWith("::#!")))
+ return 0
+
+ val matcher =
+ (Pattern.compile("^(::)?!#.*(\\r|\\n|\\r\\n)", Pattern.MULTILINE)
+ .matcher(fileContents))
+ if (!matcher.find)
+ throw new IOException("script file does not close its header with !# or ::!#")
+ return matcher.end
}
/** Split a fully qualified object name into a
* package and an unqualified object name */
- private def splitObjectName(fullname: String): (Option[String], String) =
- (fullname lastIndexOf '.') match {
- case -1 => (None, fullname)
- case idx => (Some(fullname take idx), fullname drop (idx + 1))
- }
+ private def splitObjectName(fullname: String):
+ (Option[String],String) =
+ {
+ val idx = fullname.lastIndexOf('.')
+ if (idx < 0)
+ (None, fullname)
+ else
+ (Some(fullname.substring(0,idx)), fullname.substring(idx+1))
+ }
/** Code that is added to the beginning of a script file to make
* it a complete Scala compilation unit.
*/
- protected def preambleCode(objectName: String): String = {
- val (maybePack, objName) = splitObjectName(objectName)
- val packageDecl = maybePack map ("package %s\n" format _) getOrElse ("")
-
- return """|
- | object %s {
- | def main(argv: Array[String]): Unit = {
- | val args = argv
- | new AnyRef {
- |""".stripMargin.format(objName)
+ protected def preambleCode(objectName: String) = {
+ val (maybePack, objName) = splitObjectName(objectName)
+
+ val packageDecl =
+ maybePack match {
+ case Some(pack) => "package " + pack + "\n"
+ case None => ""
+ }
+
+ (packageDecl +
+ "object " + objName + " {\n" +
+ " def main(argv: Array[String]): Unit = {\n" +
+ " val args = argv;\n" +
+ " new AnyRef {\n")
}
/** Code that is added to the end of a script file to make
* it a complete Scala compilation unit.
*/
- val endCode = """
- | }
- | }
- | }
- |""".stripMargin
+ val endCode = "\n} \n} }\n"
+
/** Wrap a script file into a runnable object named
* <code>scala.scripting.Main</code>.
@@ -174,12 +180,20 @@ object ScriptRunner
def wrappedScript(
objectName: String,
filename: String,
- getSourceFile: PlainFile => BatchSourceFile): SourceFile =
+ getSourceFile: PlainFile => SourceFile): SourceFile =
{
- val preamble = new BatchSourceFile("<script preamble>", preambleCode(objectName).toCharArray)
+ val preamble =
+ new BatchSourceFile("<script preamble>",
+ preambleCode(objectName).toCharArray)
+
val middle = {
- val bsf = getSourceFile(PlainFile fromPath filename)
- new SourceFileFragment(bsf, headerLength(filename), bsf.length)
+ val f = new File(filename)
+ val bsf = getSourceFile(new PlainFile(f)).asInstanceOf[BatchSourceFile]
+ new SourceFileFragment(
+ bsf,
+ headerLength(filename),
+ bsf.length)
+// f.length.asInstanceOf[Int])
}
val end = new BatchSourceFile("<script trailer>", endCode.toCharArray)
@@ -196,42 +210,53 @@ object ScriptRunner
settings: GenericRunnerSettings,
scriptFileIn: String): Boolean =
{
- val scriptFile = CompileClient absFileName scriptFileIn
+ val scriptFile = CompileClient.absFileName(scriptFileIn)
+ for (setting <- List(
+ settings.classpath,
+ settings.sourcepath,
+ settings.bootclasspath,
+ settings.extdirs,
+ settings.outdir))
+ setting.value = CompileClient.absFileNames(setting.value)
- {
- import settings._
- for (setting <- List(classpath, sourcepath, bootclasspath, extdirs, outdir)) {
- // DBG("%s = %s".format(setting.name, setting.value))
- setting.value = CompileClient absFileName setting.value
- }
- }
+ val compSettingNames =
+ (new Settings(error)).allSettings.map(_.name)
- val compSettingNames = new Settings(error).allSettings map (_.name)
- val compSettings = settings.allSettings filter (compSettingNames contains _.name)
- val coreCompArgs = compSettings flatMap (_.unparse)
- val compArgs = coreCompArgs ::: List("-Xscript", scriptMain(settings), scriptFile)
- var compok = true
-
- // XXX temporary as I started using ManagedResource not remembering it wasn't checked in.
- def ManagedResource[T](x: => T) = Some(x)
-
- for {
- socket <- ManagedResource(CompileSocket getOrCreateSocket "")
- val _ = if (socket == null) return false
- out <- ManagedResource(new PrintWriter(socket.getOutputStream(), true))
- in <- ManagedResource(new BufferedReader(new InputStreamReader(socket.getInputStream())))
- } {
- out println (CompileSocket getPassword socket.getPort)
- out println (compArgs mkString "\0")
-
- for (fromServer <- (Iterator continually in.readLine()) takeWhile (_ != null)) {
- Console.err println fromServer
- if (CompileSocket.errorPattern matcher fromServer matches)
- compok = false
- }
- // XXX temp until managed resource is available
- in.close() ; out.close() ; socket.close()
+ val compSettings =
+ settings.allSettings.filter(stg =>
+ compSettingNames.contains(stg.name))
+
+ val coreCompArgs =
+ compSettings.foldLeft[List[String]](Nil)((args, stg) =>
+ stg.unparse ::: args)
+
+ val compArgs =
+ (coreCompArgs :::
+ List("-Xscript", scriptMain(settings), scriptFile))
+
+ val socket = CompileSocket.getOrCreateSocket("")
+ if (socket eq null)
+ return false
+
+ val out = new PrintWriter(socket.getOutputStream(), true)
+ val in = new BufferedReader(new InputStreamReader(socket.getInputStream()))
+
+ out.println(CompileSocket.getPassword(socket.getPort))
+ out.println(compArgs.mkString("", "\0", ""))
+
+ var compok = true
+
+ var fromServer = in.readLine()
+ while (fromServer ne null) {
+ Console.err.println(fromServer)
+ if (CompileSocket.errorPattern.matcher(fromServer).matches)
+ compok = false
+
+ fromServer = in.readLine()
}
+ in.close()
+ out.close()
+ socket.close()
compok
}
@@ -244,80 +269,101 @@ object ScriptRunner
*
* @returns true if compilation and the handler succeeds, false otherwise.
*/
- private def withCompiledScript(
- settings: GenericRunnerSettings,
- scriptFile: String)
- (handler: String => Boolean): Boolean =
- {
- /** Compiles the script file, and returns the directory with the compiled
- * class files, if the compilation succeeded.
- */
- def compile: Option[Directory] = {
- val compiledPath = Directory makeTemp "scalascript"
+ private def withCompiledScript
+ (settings: GenericRunnerSettings, scriptFile: String)
+ (handler: String => Boolean)
+ : Boolean = {
+ import Interpreter.deleteRecursively
+
+ /** Compiles the script file, and returns
+ * the directory with the compiled class files,
+ * if the compilation succeeded.
+ */
+ def compile: Option[File] = {
+ val compiledPath = File.createTempFile("scalascript", "")
+ compiledPath.delete // the file is created as a file; make it a directory
+ compiledPath.mkdirs
// delete the directory after the user code has finished
- addShutdownHook(compiledPath.deleteRecursively())
+ Runtime.getRuntime.addShutdownHook(new Thread {
+ override def run { deleteRecursively(compiledPath) }})
- settings.outdir.value = compiledPath.path
+ settings.outdir.value = compiledPath.getPath
if (settings.nocompdaemon.value) {
val reporter = new ConsoleReporter(settings)
val compiler = newGlobal(settings, reporter)
val cr = new compiler.Run
- val wrapped = wrappedScript(scriptMain(settings), scriptFile, compiler getSourceFile _)
-
- cr compileSources List(wrapped)
- if (reporter.hasErrors) None else Some(compiledPath)
+ val wrapped =
+ wrappedScript(
+ scriptMain(settings),
+ scriptFile,
+ compiler.getSourceFile _)
+ cr.compileSources(List(wrapped))
+ if (!reporter.hasErrors)
+ Some(compiledPath)
+ else
+ None
+ } else {
+ if (compileWithDaemon(settings, scriptFile))
+ Some(compiledPath)
+ else
+ None
}
- else if (compileWithDaemon(settings, scriptFile)) Some(compiledPath)
- else None
}
if (settings.savecompiled.value) {
val jarFile = jarFileFor(scriptFile)
- def jarOK = jarFile.canRead && (jarFile isFresher File(scriptFile))
- def recompile() = {
- jarFile.delete()
+ def jarOK = (jarFile.canRead &&
+ (jarFile.lastModified > new File(scriptFile).lastModified))
+
+ if (jarOK) {
+ // pre-compiled jar is current
+ handler(jarFile.getAbsolutePath)
+ } else {
+ // The pre-compiled jar is old. Recompile the script.
+ jarFile.delete
compile match {
case Some(compiledPath) =>
tryMakeJar(jarFile, compiledPath)
if (jarOK) {
- compiledPath.deleteRecursively()
- handler(jarFile.toAbsolute.path)
+ deleteRecursively(compiledPath) // may as well do it now
+ handler(jarFile.getAbsolutePath)
+ } else {
+ // jar failed; run directly from the class files
+ handler(compiledPath.getPath)
}
- // jar failed; run directly from the class files
- else handler(compiledPath.path)
- case _ => false
+ case None => false
}
}
-
- if (jarOK) handler(jarFile.toAbsolute.path) // pre-compiled jar is current
- else recompile() // jar old - recompile the script.
+ } else {
+ // don't use a cache jar at all--just use the class files
+ compile match {
+ case Some(compiledPath) => handler(compiledPath.getPath)
+ case None => false
+ }
}
- // don't use a cache jar at all--just use the class files
- else compile map (cp => handler(cp.path)) getOrElse false
}
+
/** Run a script after it has been compiled
*
* @returns true if execution succeeded, false otherwise
*/
- private def runCompiled(
- settings: GenericRunnerSettings,
- compiledLocation: String,
- scriptArgs: List[String]): Boolean =
- {
- def fileToURL(f: JFile): Option[URL] =
- try Some(f.toURL) catch { case _: Exception => None }
+ private def runCompiled(settings: GenericRunnerSettings,
+ compiledLocation: String,
+ scriptArgs: List[String]) : Boolean = {
+ def fileToURL(f: File): Option[URL] =
+ try { Some(f.toURL) }
+ catch { case e => Console.err.println(e); None }
def paths(str: String, expandStar: Boolean): List[URL] =
- for {
- file <- ClassPath.expandPath(str, expandStar) map (new JFile(_))
- if file.exists
- url <- fileToURL(file)
- } yield url
+ for (
+ file <- ClassPath.expandPath(str, expandStar) map (new File(_)) if file.exists;
+ val url = fileToURL(file); if !url.isEmpty
+ ) yield url.get
val classpath =
(paths(settings.bootclasspath.value, true) :::
@@ -330,47 +376,64 @@ object ScriptRunner
scriptMain(settings),
scriptArgs.toArray)
true
- }
- catch {
- case e @ (_: ClassNotFoundException | _: NoSuchMethodException) =>
- Console println e
+ } catch {
+ case e: ClassNotFoundException =>
+ Console.println(e)
false
- case e: InvocationTargetException =>
+ case e: NoSuchMethodException =>
+ Console.println(e)
+ false
+ case e:InvocationTargetException =>
e.getCause.printStackTrace
false
}
}
+
/** Run a script file with the specified arguments and compilation
* settings.
*
* @returns true if compilation and execution succeeded, false otherwise.
*/
- def runScript(
- settings: GenericRunnerSettings,
+ def runScript(settings: GenericRunnerSettings,
scriptFile: String,
- scriptArgs: List[String]): Boolean =
- {
- if (File(scriptFile).isFile)
- withCompiledScript(settings, scriptFile) { runCompiled(settings, _, scriptArgs) }
- else
- throw new IOException("no such file: " + scriptFile)
+ scriptArgs: List[String]) : Boolean = {
+ val f = new File(scriptFile)
+ if (!f.isFile) {
+ throw new IOException("no such file: " + scriptFile)
+ } else {
+ try {
+ withCompiledScript(settings, scriptFile){compiledLocation =>
+ runCompiled(settings, compiledLocation, scriptArgs)
+ }
+ } catch {
+ case e => throw e
+ }
+ }
}
/** Run a command
*
* @returns true if compilation and execution succeeded, false otherwise.
*/
- def runCommand(
- settings: GenericRunnerSettings,
- command: String,
- scriptArgs: List[String]) : Boolean =
- {
- val scriptFile = File.makeTemp("scalacmd", ".scala")
+ def runCommand(settings: GenericRunnerSettings,
+ command: String,
+ scriptArgs: List[String]) : Boolean = {
+ val scriptFile = File.createTempFile("scalacmd", ".scala")
+
// save the command to the file
- scriptFile writeAll List(command)
+ {
+ val str = new FileWriter(scriptFile)
+ str.write(command)
+ str.close()
+ }
- try withCompiledScript(settings, scriptFile.path) { runCompiled(settings, _, scriptArgs) }
- finally scriptFile.delete() // in case there was a compilation error
+ try {
+ withCompiledScript(settings, scriptFile.getPath){compiledLocation =>
+ runCompiled(settings, compiledLocation, scriptArgs)
+ }
+ } catch {
+ case e => throw e
+ } finally scriptFile.delete() // in case there was a compilation error
}
}
diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
index 5cbd504fd3..eaa3091eee 100644
--- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala
+++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
@@ -8,10 +8,8 @@
package scala.tools.nsc
package io
-import java.io.{ File => JFile, FileOutputStream, IOException, InputStream, OutputStream }
+import java.io.{File, FileOutputStream, IOException, InputStream, OutputStream}
import java.net.URL
-import scala.io.{ Path, Directory, File }
-import PartialFunction._
import scala.collection.mutable.ArrayBuffer
@@ -19,23 +17,21 @@ import scala.collection.mutable.ArrayBuffer
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
-object AbstractFile
-{
- def isJarOrZip(f: Path) = cond(f.extension) { case Some("zip" | "jar") => true }
+object AbstractFile {
/** Returns "getFile(new File(path))". */
- def getFile(path: String): AbstractFile = getFile(Path(path))
- def getFile(path: Path): AbstractFile = getFile(path.toFile)
+ def getFile(path: String): AbstractFile = getFile(new File(path))
/**
* If the specified File exists and is a regular file, returns an
* abstract regular file backed by it. Otherwise, returns <code>null</code>.
*/
def getFile(file: File): AbstractFile =
- if (file.isFile) new PlainFile(file) else null
+ if (file.isFile() && file.exists()) new PlainFile(file) else null
+
/** Returns "getDirectory(new File(path))". */
- def getDirectory(path: Path): AbstractFile = getDirectory(path.toFile)
+ def getDirectory(path: String): AbstractFile = getDirectory(new File(path))
/**
* If the specified File exists and is either a directory or a
@@ -45,10 +41,15 @@ object AbstractFile
* @param file ...
* @return ...
*/
- def getDirectory(file: File): AbstractFile =
- if (file.isDirectory) new PlainFile(file)
- else if (file.isFile && isJarOrZip(file)) ZipArchive fromFile file
- else null
+ def getDirectory(file: File): AbstractFile = {
+ if (file.isDirectory() && file.exists()) return new PlainFile(file)
+ if (file.isFile() && file.exists()) {
+ val path = file.getPath()
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ return ZipArchive.fromFile(file);
+ }
+ null
+ }
/**
* If the specified URL exists and is a readable zip or jar archive,
@@ -59,7 +60,15 @@ object AbstractFile
* @return ...
*/
def getURL(url: URL): AbstractFile =
- Option(url) filterMap { case url: URL if isJarOrZip(url.getPath) => ZipArchive fromURL url } orNull
+ if (url ne null) {
+ val path = url.getPath()
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ ZipArchive.fromURL(url)
+ else
+ null
+ }
+ else
+ null
}
/**
@@ -101,12 +110,11 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] {
def container : AbstractFile
/** Returns the underlying File if any and null otherwise. */
- def file: JFile
- def sfile = File(file) // XXX
+ def file: File
/** Does this abstract file denote an existing file? */
def exists: Boolean =
- if (file ne null) file.exists
+ if (file ne null) file.exists()
else true
/** Create a file on disk, if one does not exist already. */
@@ -199,11 +207,11 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] {
private def lookup(getFile: (AbstractFile, String, Boolean) => AbstractFile,
path0: String,
directory: Boolean): AbstractFile = {
- val separator = JFile.separatorChar
+ val separator = File.separatorChar
// trim trailing '/'s
- val path: String = if (path0.last == separator) path0 dropRight 1 else path0
+ val path = if (path0.charAt(path0.length - 1) == separator) path0.substring(0, path0.length - 1) else path0
val length = path.length()
- assert(length > 0 && !(path.last == separator), path)
+ assert(0 < length && path.lastIndexOf(separator) < length - 1, path)
var file = this
var start = 0
while (true) {
@@ -223,7 +231,14 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] {
*/
def fileNamed(name: String): AbstractFile = {
assert(isDirectory)
- Option(lookupName(name, false)) getOrElse new PlainFile((sfile / name).createFile())
+ val existing = lookupName(name, false)
+ if (existing == null) {
+ val newFile = new File(file, name)
+ newFile.createNewFile()
+ new PlainFile(newFile)
+ } else {
+ existing
+ }
}
/**
@@ -232,7 +247,14 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] {
*/
def subdirectoryNamed(name: String): AbstractFile = {
assert (isDirectory)
- Option(lookupName(name, true)) getOrElse new PlainFile((sfile / name).createDirectory())
+ val existing = lookupName(name, true)
+ if (existing == null) {
+ val dir = new File(file, name)
+ dir.mkdir()
+ new PlainFile(dir)
+ } else {
+ existing
+ }
}
/** Returns the path of this abstract file. */
diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala
index 7e5e8576b1..0394a16a93 100644
--- a/src/compiler/scala/tools/nsc/io/PlainFile.scala
+++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala
@@ -8,9 +8,7 @@
package scala.tools.nsc
package io
-import java.io.{ File => JFile, FileInputStream, FileOutputStream, IOException }
-import scala.io.{ File, Path }
-import PartialFunction._
+import java.io.{File, FileInputStream, FileOutputStream, IOException}
object PlainFile
{
@@ -18,46 +16,56 @@ object PlainFile
* If the specified File exists, returns an abstract file backed
* by it. Otherwise, returns null.
*/
- def fromPath(file: Path): PlainFile =
- if (file.exists) new PlainFile(file) else null
+ def fromFile(file: File): PlainFile =
+ if (file.exists()) new PlainFile(file) else null
+
+ def fromPath(path: String): PlainFile = fromFile(new File(path))
}
/** This class implements an abstract file backed by a File.
*/
-class PlainFile(val givenPath: Path) extends AbstractFile {
- assert(path ne null)
+class PlainFile(val file: File) extends AbstractFile {
+ private val fpath = try { file.getCanonicalPath }
+ catch { case _: IOException => file.getAbsolutePath }
- val file = givenPath.jfile
- private val fpath = try givenPath.normalize catch { case _: IOException => givenPath.toAbsolute }
+ assert(file ne null)
+// assert(file.exists(), "non-existent file: " + file)
/** Returns the name of this abstract file. */
- def name = givenPath.name
+ def name = file.getName()
/** Returns the path of this abstract file. */
- def path = givenPath.path
+ def path = file.getPath()
/** The absolute file. */
- def absolute = new PlainFile(givenPath.normalize)
+ def absolute = new PlainFile(file.getCanonicalFile())
+
+ override def container : AbstractFile = new PlainFile(file.getParentFile)
- override def container: AbstractFile = new PlainFile(givenPath.parent.get)
- override def input = givenPath.toFile.inputStream()
- override def output = givenPath.toFile.outputStream()
- override def sizeOption = Some(givenPath.length.toInt)
+ override def input = new FileInputStream(file)
+ override def output = new FileOutputStream(file)
+
+ override def sizeOption = Some(file.length.toInt)
override def hashCode(): Int = fpath.hashCode
+
override def equals(that: Any): Boolean =
- cond(that) { case other: PlainFile => fpath == other.fpath }
+ that.isInstanceOf[PlainFile] &&
+ fpath.equals(that.asInstanceOf[PlainFile].fpath)
/** Is this abstract file a directory? */
- def isDirectory: Boolean = givenPath.isDirectory
+ def isDirectory: Boolean = file.isDirectory()
/** Returns the time that this abstract file was last modified. */
- def lastModified: Long = givenPath.lastModified
+ def lastModified: Long = file.lastModified()
/** Returns all abstract subfiles of this abstract directory. */
def iterator: Iterator[AbstractFile] = {
- assert(isDirectory, "not a directory '%s'" format this)
- givenPath.toDirectory.list filter (_.exists) map (new PlainFile(_))
+ assert(isDirectory, "not a directory '" + this + "'")
+ val names: Array[String] = file.list()
+ if ((names eq null) || names.length == 0) Iterator.empty
+ else names.iterator.map { name: String => new File(file, name) }
+ .filter(_.exists).map(file => new PlainFile(file))
}
/**
@@ -71,22 +79,34 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
* @return ...
*/
def lookupName(name: String, directory: Boolean): AbstractFile = {
- val child = givenPath / name
- if ((child.isDirectory && directory) || (child.isFile && !directory)) new PlainFile(child)
- else null
+ //assert(isDirectory, "not a directory '" + this + "'")
+ val child = new File(file, name)
+ if (!child.exists() || (directory != child.isDirectory) ||
+ directory == child.isFile()) null
+ else new PlainFile(child)
}
/** Does this abstract file denote an existing file? */
- def create: Unit = if (!exists) givenPath.createFile()
+ def create {
+ if (!exists)
+ file.createNewFile()
+ }
/** Delete the underlying file or directory (recursively). */
- def delete: Unit =
- if (givenPath.isFile) givenPath.delete()
- else if (givenPath.isDirectory) givenPath.toDirectory.deleteRecursively()
+ def delete {
+ if (file.isFile) file.delete
+ else if (file.isDirectory) {
+ iterator.foreach(_.delete)
+ file.delete
+ }
+ }
/** Returns a plain file with the given name. It does not
* check that it exists.
*/
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
- new PlainFile(givenPath / name)
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = {
+ val f = new File(file, name)
+ new PlainFile(f)
+ }
+
}
diff --git a/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala b/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala
index 6b5af87d7c..16381bbe6e 100644
--- a/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala
+++ b/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala
@@ -4,7 +4,7 @@
// $Id$
package scala.tools.nsc
package io
-import scala.collection.mutable
+import scala.collection.{mutable=>mut}
/**
* An in-memory directory.
@@ -24,7 +24,9 @@ extends AbstractFile {
def container = maybeContainer.get
def isDirectory = true
var lastModified: Long = System.currentTimeMillis
-
+ private def updateLastModified {
+ lastModified = System.currentTimeMillis
+ }
override def file = null
override def input = error("directories cannot be read")
override def output = error("directories cannot be written")
@@ -45,28 +47,44 @@ extends AbstractFile {
def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
throw new UnsupportedOperationException()
- private val files = mutable.Map.empty[String, AbstractFile]
+ private val files = mut.Map.empty[String, AbstractFile]
// the toList is so that the directory may continue to be
// modified while its elements are iterated
def iterator = files.valuesIterator.toList.iterator
- override def lookupName(name: String, directory: Boolean): AbstractFile =
- files get name filter (_.isDirectory == directory) orNull
+ override def lookupName(name: String, directory: Boolean): AbstractFile = {
+ files.get(name) match {
+ case None => null
+ case Some(file) =>
+ if (file.isDirectory == directory)
+ file
+ else
+ null
+ }
+ }
- override def fileNamed(name: String): AbstractFile =
- Option(lookupName(name, false)) getOrElse {
+ override def fileNamed(name: String): AbstractFile = {
+ val existing = lookupName(name, false)
+ if (existing == null) {
val newFile = new VirtualFile(name, path+'/'+name)
files(name) = newFile
newFile
+ } else {
+ existing
}
+ }
- override def subdirectoryNamed(name: String): AbstractFile =
- Option(lookupName(name, true)) getOrElse {
+ override def subdirectoryNamed(name: String): AbstractFile = {
+ val existing = lookupName(name, true)
+ if (existing == null) {
val dir = new VirtualDirectory(name, Some(this))
files(name) = dir
dir
+ } else {
+ existing
}
+ }
def clear() {
files.clear();
diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
index 1c8f132d36..14d081991e 100644
--- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala
+++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
@@ -8,16 +8,16 @@
package scala.tools.nsc
package io
-import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream, File }
-import PartialFunction._
+import java.io.{ByteArrayInputStream, ByteArrayOutputStream,
+ File, InputStream, OutputStream}
/** This class implements an in-memory file.
*
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
-class VirtualFile(val name: String, _path: String) extends AbstractFile
-{
+class VirtualFile(val name: String, _path: String) extends AbstractFile {
+
assert((name ne null) && (path ne null), name + " - " + path)
//########################################################################
@@ -33,7 +33,11 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile
def this(name: String) = this(name, name)
override def hashCode = name.hashCode
- override def equals(that: Any) = cond(that) { case x: VirtualFile => x.name == name }
+ override def equals(that : Any) = that match {
+ case that : VirtualFile => name == that.name
+ case _ => false
+ }
+
//########################################################################
// Private data
diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
index 2221a3df03..9d322af889 100644
--- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala
+++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
@@ -8,25 +8,28 @@
package scala.tools.nsc
package io
-import scala.io.{ File, Path }
+import java.io.{File, IOException, InputStream}
import java.net.URL
import java.util.Enumeration
-import java.io.{ File => JFile, IOException, InputStream, BufferedInputStream, ByteArrayInputStream }
-import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
-import PartialFunction._
+import java.util.zip.{ZipEntry, ZipFile, ZipInputStream}
-import scala.collection.Traversable
-import scala.collection.mutable.{ Map, HashMap }
-import scala.collection.immutable.{ StringVector => SV }
-import scala.collection.JavaConversions.asIterator
+import scala.collection.mutable.{Map, HashMap}
/**
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
-object ZipArchive
-{
- def fromPath(path: Path): ZipArchive = fromFile(path.toFile)
+object ZipArchive {
+
+ //########################################################################
+
+ /**
+ * ...
+ *
+ * @param path ...
+ * @return ...
+ */
+ def fromPath(path: String): AbstractFile = fromFile(new File(path))
/**
* If the specified file <code>file</code> exists and is a readable
@@ -36,115 +39,56 @@ object ZipArchive
* @param file ...
* @return ...
*/
- def fromFile(file: File): ZipArchive =
- try new ZipArchive(file, new ZipFile(file.jfile))
+ def fromFile(file: File): AbstractFile =
+ try { new ZipArchive(file, new ZipFile(file)) }
catch { case _: IOException => null }
/**
* Returns an abstract directory backed by the specified archive.
+ *
+ * @param archive ...
+ * @return ...
*/
- def fromArchive(archive: ZipFile): ZipArchive =
- new ZipArchive(File(archive.getName()), archive)
+ def fromArchive(archive: ZipFile): AbstractFile =
+ new ZipArchive(new File(archive.getName()), archive)
/**
* Returns an abstract directory backed by the specified archive.
+ *
+ * @param url ...
+ * @return ...
*/
- def fromURL(url: URL): AbstractFile = new URLZipArchive(url)
-
- private[io] class ZipEntryTraversableClass(in: InputStream) extends Traversable[ZipEntry] {
- val zis = new ZipInputStream(in)
-
- def foreach[U](f: ZipEntry => U) = {
- def loop(x: ZipEntry): Unit = if (x != null) {
- f(x)
- zis.closeEntry()
- loop(zis.getNextEntry())
- }
- loop(zis.getNextEntry())
- }
- }
+ def fromURL(url: URL): AbstractFile =
+ new URLZipArchive(url)
}
-/** This abstraction aims to factor out the common code between
- * ZipArchive (backed by a zip file) and URLZipArchive (backed
- * by an InputStream.)
+/**
+ * This class implements an abstract directory backed by a zip
+ * archive. We let the encoding be <code>null</code>, because we behave like
+ * a directory.
+ *
+ * @author Philippe Altherr
+ * @version 1.0, 23/03/2004
*/
-private[io] trait ZipContainer extends AbstractFile
-{
- /** Abstract types */
- type SourceType // InputStream or AbstractFile
- type CreationType // InputStream or ZipFile
- type ZipTrav = Traversable[ZipEntry] { def zis: ZipInputStream }
-
- /** Abstract values */
- protected val creationSource: CreationType
- protected val root: DirEntryInterface
- protected def DirEntryConstructor: (AbstractFile, String, String) => DirEntryInterface
- protected def FileEntryConstructor: (SourceType, String, String, ZipEntry) => FileEntryInterface
- protected def ZipTravConstructor: CreationType => ZipTrav
-
- protected[io] trait EntryInterface extends VirtualFile {
- def name: String
- def path: String
- }
-
- protected[io] trait DirEntryInterface extends EntryInterface {
- def source: SourceType
- val entries: Map[String, EntryInterface] = new HashMap()
- var entry: ZipEntry = _
-
- override def input = throw new Error("cannot read directories")
- override def lastModified: Long =
- if (entry ne null) entry.getTime() else super.lastModified
+final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) {
- override def isDirectory = true
- override def iterator: Iterator[AbstractFile] = entries.valuesIterator
- override def lookupName(name: String, directory: Boolean): AbstractFile = {
- def slashName = if (directory) name + "/" else name
- entries.getOrElse(slashName, null)
- }
- }
+ assert(archive ne null)
+ //########################################################################
+ // Private Fields
- protected[io] trait FileEntryInterface extends EntryInterface {
- def entry: ZipEntry
+ /** The root directory or null if not yet initialized */
+ private var root: DirEntry = _
- override def lastModified: Long = entry.getTime()
- override def sizeOption = Some(entry.getSize().toInt)
- }
+ //########################################################################
+ // Public Methods
- class ZipRootCreator(f: ZipRootCreator => SourceType) {
- val root = DirEntryConstructor(ZipContainer.this, "<root>", "/")
-
- // Map from paths to DirEntries
- val dirs = HashMap[String, DirEntryInterface]("/" -> root)
- val traverser = ZipTravConstructor(creationSource)
- private[this] var _parent: DirEntryInterface = _
- def parent = _parent
-
- def addEntry(entry: ZipEntry) {
- val path = entry.getName
- if (entry.isDirectory) {
- val dir: DirEntryInterface = getDir(dirs, path)
- if (dir.entry == null) dir.entry = entry
- }
- else {
- val (home, name) = splitPath(path)
- _parent = getDir(dirs, home)
- _parent.entries(name) = FileEntryConstructor(f(this), name, path, entry)
- }
- }
-
- def apply() = {
- traverser foreach addEntry
- root
- }
- }
+ /** Returns true. */
+ override def isDirectory = true
- protected def splitPath(path: String): (String, String) = {
- (path lastIndexOf '/') match {
- case -1 => ("/", path)
- case idx => SV.splitAt(path, idx + 1)
- }
+ /** Returns all abstract subfiles of this abstract directory. */
+ override def iterator: Iterator[AbstractFile] = {
+ if (root eq null) load()
+ root.iterator
}
/**
@@ -153,8 +97,10 @@ private[io] trait ZipContainer extends AbstractFile
* argument "directory" tells whether to look for a directory or
* or a regular file.
*/
- override def lookupName(name: String, directory: Boolean): AbstractFile =
+ override def lookupName(name: String, directory: Boolean): AbstractFile = {
+ if (root eq null) load()
root.lookupName(name, directory)
+ }
/** Returns an abstract file with the given name. It does not
* check that it exists.
@@ -162,90 +108,114 @@ private[io] trait ZipContainer extends AbstractFile
override def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
throw new UnsupportedOperationException()
- /** Returns all abstract subfiles of this abstract directory. */
- override def iterator: Iterator[AbstractFile] = root.iterator
+ //########################################################################
+ // Private Methods
+
+ /** Loads the archive and creates the root directory. */
+ private def load() {
+ this.root = new DirEntry(this, "<root>", "/")
+ // A path to DirEntry map
+ val dirs: Map[String, DirEntry] = new HashMap()
+ dirs.update("/", root)
+ val entries = archive.entries()
+ while (entries.hasMoreElements()) {
+ val entry = entries.nextElement().asInstanceOf[ZipEntry]
+ val path = entry.getName()
+ assert(entry.isDirectory() == path.endsWith("/"),
+ this.toString() + " - " + path);
+ if (entry.isDirectory()) {
+ val dir: DirEntry = getDir(dirs, path)
+ // this assertion causes an unnecessary bomb if a directory is twice listed in the jar
+ // assert(dir.entry eq null, this.toString() + " - " + path)
+ if (dir.entry eq null) dir.entry = entry
+ } else {
+ val index = path.lastIndexOf('/')
+ val name = if (index < 0) path else path.substring(index + 1)
+ val home = if (index < 0) "/" else path.substring(0, index + 1)
+ val parent: DirEntry = getDir(dirs, home)
+ // OLD: assert(!parent.entries.contains(path))
+ // MAYBE: assert(!parent.entries.contains(name))
+ //if (parent.entries.contains(name))
+ // Console.println("XXX: " + this.toString() + " - " + home + "/" + name)
+ parent.entries.update(name, new FileEntry(parent, name, path, entry))
+ }
+ }
+ }
/**
- * Looks up the path in the given map and returns if found.
- * If not present, creates a new DirEntry, adds to both given
- * map and parent.entries, and returns it.
+ * Lookups the specified table for a DirEntry with the specified
+ * path. If successful, returns the found DirEntry. Otherwise
+ * creates a new DirEntry, enters it into the table and in the
+ * table of its parent ZipDir and returns it.
*/
- protected def getDir(dirs: Map[String, DirEntryInterface], path: String): DirEntryInterface =
- dirs.getOrElseUpdate(path, {
- val (home, name) = splitPath(SV init path)
- val parent = getDir(dirs, home)
- val dir = DirEntryConstructor(parent, name, path)
- parent.entries(name + path.last) = dir
- dir
+ private def getDir(dirs: Map[String,DirEntry], path: String): DirEntry =
+ dirs.get(path) match {
+ case Some(dir) => dir
+ case None =>
+ val index = path.lastIndexOf('/', path.length() - 2);
+ val name = if (index < 0) path else path.substring(index + 1);
+ val home = if (index < 0) "/" else path.substring(0, index + 1);
+ val parent: DirEntry = getDir(dirs, home);
+ val dir = new DirEntry(parent, name.substring(0, name.length() - 1), path);
+ parent.entries.update(name, dir);
+ dirs.update(path, dir);
+ dir
+ }
+
+ //########################################################################
+ // Private Class - Entry
+
+ /** Superclass of archive entries */
+ abstract class Entry(override val container : AbstractFile, name: String, path: String)
+ extends VirtualFile(name, path) {
+ final override def path = ZipArchive.this.toString() + "(" + pathInArchive + ")"
+ final def getArchive = ZipArchive.this.archive
+ def pathInArchive = super.path
+ override def hashCode = super.hashCode + container.hashCode
+ override def equals(that : Any) = super.equals(that) && (that match {
+ case entry : Entry => container == entry.container
+ case _ => false
})
+ }
- override def isDirectory = true
-}
+ //########################################################################
+ // Private Class - DirEntry
-/**
- * This class implements an abstract directory backed by a zip
- * archive. We let the encoding be <code>null</code>, because we behave like
- * a directory.
- *
- * @author Philippe Altherr
- * @version 1.0, 23/03/2004
- */
-final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) with ZipContainer
-{
- self =>
-
- type SourceType = AbstractFile
- type CreationType = ZipFile
-
- protected val creationSource = archive
- protected lazy val root = new ZipRootCreator(_.parent)()
- protected def DirEntryConstructor = new DirEntry(_, _, _)
- protected def FileEntryConstructor = new FileEntry(_, _, _, _)
- protected def ZipTravConstructor = zipTraversableFromZipFile _
-
- abstract class Entry(
- override val container: AbstractFile,
- name: String,
- path: String
- ) extends VirtualFile(name, path)
+ /** A directory archive entry */
+ private final class DirEntry(container : AbstractFile, name: String, path: String)
+ extends Entry(container, name, path)
{
- final override def path = "%s(%s)".format(self, pathInArchive)
- final def getArchive = self.archive
- def pathInArchive = super.path
- override def hashCode = super.hashCode + container.hashCode
- override def equals(that : Any) =
- super.equals(that) && (cond(that) {
- case e: Entry => container == e.container
- })
- }
+ val entries: Map[String, Entry] = new HashMap()
- final class DirEntry(
- container: AbstractFile,
- name: String,
- path: String
- ) extends Entry(container, name, path) with DirEntryInterface
- {
- def source = container
- }
+ var entry: ZipEntry = _
- final class FileEntry(
- container: AbstractFile,
- name: String,
- path: String,
- val entry: ZipEntry
- ) extends Entry(container, name, path) with FileEntryInterface
- {
- def archive = self.archive
- override def input = archive getInputStream entry
- }
+ override def isDirectory = true
+ override def input = throw new Error("cannot read directories")
- private def zipTraversableFromZipFile(z: ZipFile): ZipTrav =
- new Traversable[ZipEntry] {
- def zis: ZipInputStream = null // not valid for this type
- val itStream = asIterator(z.entries()).toStream
- def foreach[U](f: ZipEntry => U) = itStream foreach f
+ override def lastModified: Long =
+ if (entry ne null) entry.getTime() else super.lastModified
+
+ override def iterator: Iterator[AbstractFile] = entries.valuesIterator
+
+ override def lookupName(name: String, directory: Boolean): AbstractFile =
+ entries.get(if (directory) name + "/" else name) match {
+ case Some(dir) => dir
+ case None => null
}
+ }
+
+ //########################################################################
+ // Private Class - FileEntry
+
+ /** A regular file archive entry */
+ final class FileEntry(container : AbstractFile, name: String, path: String, val entry: ZipEntry)
+ extends Entry(container, name, path) {
+ def archive = ZipArchive.this.archive
+ override def lastModified: Long = entry.getTime()
+ override def input = archive.getInputStream(entry)
+ override def sizeOption = Some(entry.getSize().toInt)
+ }
}
/**
@@ -255,53 +225,144 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file)
* @author Stephane Micheloud
* @version 1.0, 29/05/2007
*/
-final class URLZipArchive(url: URL) extends AbstractFile with ZipContainer
-{
- type SourceType = InputStream
- type CreationType = InputStream
+final class URLZipArchive(url: URL) extends AbstractFile {
+ assert(url ne null)
- protected lazy val creationSource = input
- protected lazy val root = new ZipRootCreator(x => byteInputStream(x.traverser.zis))()
+ private var root: DirEntry = _
- protected def DirEntryConstructor = (_, name, path) => new DirEntry(name, path)
- protected def FileEntryConstructor = new FileEntry(_, _, _, _)
- protected def ZipTravConstructor = new ZipArchive.ZipEntryTraversableClass(_)
+ def container = throw new Error("unsupported")
def name: String = url.getFile()
+
def path: String = url.getPath()
- def input: InputStream = url.openStream()
+
+ def file: File = null
+
def absolute: AbstractFile = this
+
+ def isDirectory: Boolean = true
+
def lastModified: Long =
- try url.openConnection().getLastModified()
- catch { case _: IOException => 0 }
+ try { url.openConnection().getLastModified() }
+ catch { case _ => 0 }
+
+ /** Does this abstract file denote an existing file? */
+ def create {
+ throw new UnsupportedOperationException
+ }
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete {
+ throw new UnsupportedOperationException
+ }
+
+ def input: InputStream = url.openStream()
- /** Methods we don't support but have to implement because of the design */
- def file: JFile = null
- def create: Unit = throw new UnsupportedOperationException
- def delete: Unit = throw new UnsupportedOperationException
def output = throw new Error("unsupported")
- def container = throw new Error("unsupported")
- abstract class Entry(name: String, path: String) extends VirtualFile(name, path) {
- final override def path = "%s(%s)".format(URLZipArchive.this, super.path)
+ override def iterator: Iterator[AbstractFile] = {
+ if (root eq null) load()
+ root.iterator
}
- final class DirEntry(name: String, path: String) extends Entry(name, path) with DirEntryInterface {
- def source = input
+
+ override def lookupName(name: String, directory: Boolean): AbstractFile = {
+ if (root eq null) load()
+ root.lookupName(name, directory)
+ }
+
+ /** Returns an abstract file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ throw new UnsupportedOperationException()
+
+ private def load() {
+ def getEntryInputStream(in: InputStream): InputStream = {
+ val buf = new scala.collection.mutable.ArrayBuffer[Byte]
+ val data = new Array[Byte](1024)
+ var n = in.read(data)
+ while (n > 0) {
+ buf.++=(data, 0, n)
+ n = in.read(data)
+ }
+ new java.io.ByteArrayInputStream(buf.toArray)
+ }
+ this.root = new DirEntry("<root>", "/")
+ // A path to DirEntry map
+ val dirs: Map[String, DirEntry] = new HashMap()
+ dirs.update("/", root)
+ val zis = new ZipInputStream(input)
+ var entry = zis.getNextEntry()
+ while (entry ne null) {
+ val path = entry.getName()
+ assert(entry.isDirectory() == path.endsWith("/"),
+ this.toString() + " - " + path);
+ if (entry.isDirectory()) {
+ val dir: DirEntry = getDir(dirs, path)
+ assert(dir.entry eq null, this.toString() + " - " + path)
+ dir.entry = entry
+ } else {
+ val index = path.lastIndexOf('/')
+ val name = if (index < 0) path else path.substring(index + 1)
+ val home = if (index < 0) "/" else path.substring(0, index + 1)
+ val parent: DirEntry = getDir(dirs, home)
+ assert(!parent.entries.contains(path), this.toString() + " - " + path)
+ val in = getEntryInputStream(zis)
+ parent.entries.update(name, new FileEntry(name, path, entry, in))
+ }
+ zis.closeEntry()
+ entry = zis.getNextEntry()
+ }
+ }
+
+ private def getDir(dirs: Map[String, DirEntry], path: String): DirEntry =
+ dirs.get(path) match {
+ case Some(dir) => dir
+ case None =>
+ val index = path.lastIndexOf('/', path.length() - 2)
+ val name = if (index < 0) path else path.substring(index + 1)
+ val home = if (index < 0) "/" else path.substring(0, index + 1)
+ val parent: DirEntry = getDir(dirs, home)
+ val dir = new DirEntry(name.substring(0, name.length() - 1), path)
+ parent.entries.update(name, dir)
+ dirs.update(path, dir)
+ dir
+ }
+
+ /** Superclass of archive entries */
+ abstract class Entry(name: String, path: String)
+ extends VirtualFile(name, path) {
+ final override def path = URLZipArchive.this.toString() + "(" + super.path + ")"
+ //final def getArchive = URLZipArchive.this.archive
}
- final class FileEntry(
- val in: InputStream,
- name: String,
- path: String,
- val entry: ZipEntry
- ) extends Entry(name, path) with FileEntryInterface
+
+ /** A directory archive entry */
+ private final class DirEntry(name: String, path: String)
+ extends Entry(name, path)
{
- override def input = in
+ val entries: Map[String, Entry] = new HashMap()
+ var entry: ZipEntry = _
+
+ override def isDirectory = true
+ override def input = throw new Error("cannot read directories")
+
+ override def lastModified: Long =
+ if (entry ne null) entry.getTime() else super.lastModified
+
+ override def iterator: Iterator[AbstractFile] = entries.valuesIterator
+
+ override def lookupName(name: String, directory: Boolean): AbstractFile =
+ entries.get(if (directory) name + "/" else name) match {
+ case Some(dir) => dir
+ case None => null
+ }
}
- /** Private methods **/
- private def byteInputStream(in: InputStream): InputStream = {
- val buf = new BufferedInputStream(in)
- val bytes = Iterator continually in.read().toByte takeWhile (_ != -1)
- new ByteArrayInputStream(bytes.toSequence.toArray)
+ final class FileEntry(name: String, path: String,
+ val entry: ZipEntry, val in: InputStream)
+ extends Entry(name, path) {
+ override def lastModified: Long = entry.getTime()
+ override def input = in
+ override def sizeOption = Some(entry.getSize().toInt)
}
}
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
index a7b686e750..3013199c36 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
@@ -7,7 +7,7 @@
package scala.tools.nsc
package plugins
-import scala.io.{ File, Path }
+import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
import java.util.zip.ZipException
@@ -63,44 +63,39 @@ abstract class Plugin {
* @author Lex Spoon
* @version 1.0, 2007-5-21
*/
-object Plugin
-{
- private val PluginXML = "scalac-plugin.xml"
-
+object Plugin {
/** Create a class loader with the specified file plus
* the loader that loaded the Scala compiler.
*/
- private def loaderFor(jarfiles: Seq[Path]): ClassLoader = {
+ private def loaderFor(jarfiles: Seq[File]): ClassLoader = {
val compilerLoader = classOf[Plugin].getClassLoader
- val jarurls = jarfiles map (_.toURL)
-
- new URLClassLoader(jarurls.toArray, compilerLoader)
+ val jarurls = jarfiles.map(_.toURL).toArray
+ new URLClassLoader(jarurls, compilerLoader)
}
/** Try to load a plugin description from the specified
* file, returning None if it does not work. */
- private def loadDescription(jarfile: Path): Option[PluginDescription] =
- // XXX Return to this once we have some ARM support
- if (!jarfile.exists) None
- else try {
- val jar = new JarFile(jarfile.jfile)
+ private def loadDescription(jarfile: File): Option[PluginDescription] = {
+ if (!jarfile.exists) return None
+ try {
+ val jar = new JarFile(jarfile)
try {
- (jar getEntry PluginXML) match {
- case null => None
- case entry =>
- val in = jar getInputStream entry
- val packXML = XML load in
- in.close()
-
- PluginDescription fromXML packXML
- }
+ val ent = jar.getEntry("scalac-plugin.xml")
+ if (ent == null) return None
+
+ val inBytes = jar.getInputStream(ent)
+ val packXML = XML.load(inBytes)
+ inBytes.close()
+
+ PluginDescription.fromXML(packXML)
+ } finally {
+ jar.close()
}
- finally jar.close()
- }
- catch {
+ } catch {
case _: ZipException => None
}
+ }
type AnyClass = Class[_]
@@ -108,13 +103,16 @@ object Plugin
* if the jar file has no plugin in it or if the plugin
* is badly formed.
*/
- def loadFrom(jarfile: Path, loader: ClassLoader): Option[AnyClass] = {
+ def loadFrom(jarfile: File, loader: ClassLoader): Option[AnyClass] = {
val pluginInfo = loadDescription(jarfile).get
- try Some(loader loadClass pluginInfo.classname) catch {
- case _: ClassNotFoundException =>
- println("Warning: class not found for plugin in %s (%s)".format(jarfile, pluginInfo.classname))
- None
+ try {
+ Some(loader.loadClass(pluginInfo.classname))
+ } catch {
+ case _:ClassNotFoundException =>
+ println("Warning: class not found for plugin in " + jarfile +
+ " (" + pluginInfo.classname + ")")
+ None
}
}
@@ -123,28 +121,35 @@ object Plugin
* directories specified. Skips all plugins in <code>ignoring</code>.
* A single classloader is created and used to load all of them.
*/
- def loadAllFrom(
- jars: List[Path],
- dirs: List[Path],
- ignoring: List[String]): List[AnyClass] =
+ def loadAllFrom(jars: List[File],
+ dirs: List[File],
+ ignoring: List[String]): List[AnyClass] =
{
- val alljars = jars ::: (for {
+ val alljars = new ListBuffer[File]
+
+ alljars ++= jars
+
+ for {
dir <- dirs if dir.isDirectory
- entry <- dir.toDirectory.files.toList sortWith (_.name <= _.name)
- if entry.name.toLowerCase endsWith ".jar"
+ entries = dir.listFiles
+ if entries ne null
+ entry <- entries.toList.sort(_.getName <= _.getName)
+ if entry.toString.toLowerCase endsWith ".jar"
pdesc <- loadDescription(entry)
if !(ignoring contains pdesc.name)
- } yield entry)
+ } alljars += entry
- val loader = loaderFor(alljars)
- alljars map (loadFrom(_, loader)) flatten
+ val loader = loaderFor(alljars.toList)
+ alljars.toList.map(f => loadFrom(f,loader)).flatMap(x => x)
}
/** Instantiate a plugin class, given the class and
* the compiler it is to be used in.
*/
def instantiate(clazz: AnyClass, global: Global): Plugin = {
- val constructor = clazz getConstructor classOf[Global]
- (constructor newInstance global).asInstanceOf[Plugin]
+ //println("instantiating "+clazz)
+ //println(clazz.getDeclaredConstructors)
+ val constructor = clazz.getConstructor(classOf[Global])
+ constructor.newInstance(global).asInstanceOf[Plugin]
}
}
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
index a67218ee01..1163ae5a6a 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
@@ -8,7 +8,7 @@
package scala.tools.nsc
package plugins
-import scala.io.{ File, Path }
+import java.io.File
/** Support for run-time loading of compiler plugins.
*
@@ -16,9 +16,7 @@ import scala.io.{ File, Path }
* @version 1.1, 2009/1/2
* Updated 2009/1/2 by Anders Bach Nielsen: Added features to implement SIP 00002
*/
-trait Plugins
-{
- self: Global =>
+trait Plugins { self: Global =>
/** Load a rough list of the plugins. For speed, it
* does not instantiate a compiler run. Therefore it cannot
@@ -26,17 +24,24 @@ trait Plugins
* filtered from the final list of plugins.
*/
protected def loadRoughPluginsList(): List[Plugin] = {
- val jars = settings.plugin.value map Path.apply
- val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map Path.apply
- val classes = Plugin.loadAllFrom(jars, dirs, settings.disable.value)
-
- classes foreach (c => Plugin.instantiate(c, this))
+ val jars = settings.plugin.value.map(new File(_))
+ val dirs =
+ for (name <- settings.pluginsDir.value.split(File.pathSeparator).toList)
+ yield new File(name)
for (plugClass <- Plugin.loadAllFrom(jars, dirs, settings.disable.value))
yield Plugin.instantiate(plugClass, this)
}
- protected lazy val roughPluginsList: List[Plugin] = loadRoughPluginsList
+ private var roughPluginsListCache: Option[List[Plugin]] = None
+
+ protected def roughPluginsList: List[Plugin] =
+ roughPluginsListCache match {
+ case Some(list) => list
+ case None =>
+ roughPluginsListCache = Some(loadRoughPluginsList)
+ roughPluginsListCache.get
+ }
/** Load all available plugins. Skips plugins that
* either have the same name as another one, or which
@@ -49,70 +54,105 @@ trait Plugins
plugNames: Set[String],
phaseNames: Set[String]): List[Plugin] =
{
- if (plugins.isEmpty) return Nil // early return
-
- val plug :: tail = plugins
- val plugPhaseNames = Set(plug.components map (_.phaseName): _*)
- def withoutPlug = pick(tail, plugNames, plugPhaseNames)
- def withPlug = plug :: pick(tail, plugNames + plug.name, phaseNames ++ plugPhaseNames)
- lazy val commonPhases = phaseNames intersect plugPhaseNames
-
- def note(msg: String): Unit = if (settings.verbose.value) inform(msg format plug.name)
- def fail(msg: String) = { note(msg) ; withoutPlug }
-
- if (plugNames contains plug.name)
- fail("[skipping a repeated plugin: %s]")
- else if (settings.disable.value contains plug.name)
- fail("[disabling plugin: %s]")
- else if (!commonPhases.isEmpty)
- fail("[skipping plugin %s because it repeats phase names: " + (commonPhases mkString ", ") + "]")
- else {
- note("[loaded plugin %s]")
- withPlug
+ plugins match {
+ case Nil => Nil
+ case plug :: rest =>
+ val plugPhaseNames = Set.empty ++ plug.components.map(_.phaseName)
+ def withoutPlug = pick(rest, plugNames, plugPhaseNames)
+ def withPlug =
+ (plug ::
+ pick(rest,
+ plugNames+plug.name,
+ phaseNames++plugPhaseNames))
+
+ if (plugNames.contains(plug.name)) {
+ if (settings.verbose.value)
+ inform("[skipping a repeated plugin: " + plug.name + "]")
+ withoutPlug
+ } else if (settings.disable.value contains(plug.name)) {
+ if (settings.verbose.value)
+ inform("[disabling plugin: " + plug.name + "]")
+ withoutPlug
+ } else {
+ val commonPhases = phaseNames.intersect(plugPhaseNames)
+ if (!commonPhases.isEmpty) {
+ if (settings.verbose.value)
+ inform("[skipping plugin " + plug.name +
+ "because it repeats phase names: " +
+ commonPhases.mkString(", ") + "]")
+ withoutPlug
+ } else {
+ if (settings.verbose.value)
+ inform("[loaded plugin " + plug.name + "]")
+ withPlug
+ }
+ }
}
}
- val plugs = pick(roughPluginsList, Set(), phasesSet map (_.phaseName) toSet)
+ val plugs =
+ pick(roughPluginsList,
+ Set.empty,
+ Set.empty ++ phasesSet.map(_.phaseName))
- /** Verify requirements are present. */
- for (req <- settings.require.value ; if !(plugs exists (_.name == req)))
+ for (req <- settings.require.value; if !plugs.exists(p => p.name==req))
error("Missing required plugin: " + req)
- /** Process plugin options. */
- def namec(plug: Plugin) = plug.name + ":"
- def optList(xs: List[String], p: Plugin) = xs filter (_ startsWith namec(p))
- def doOpts(p: Plugin): List[String] =
- optList(settings.pluginOptions.value, p) map (_ stripPrefix namec(p))
- for (p <- plugs) {
- val opts = doOpts(p)
+ for (plug <- plugs) {
+ val nameColon = plug.name + ":"
+ val opts = for {
+ raw <- settings.pluginOptions.value
+ if raw.startsWith(nameColon)
+ } yield raw.substring(nameColon.length)
+
if (!opts.isEmpty)
- p.processOptions(opts, error)
+ plug.processOptions(opts, error)
}
- /** Verify no non-existent plugin given with -P */
- for (opt <- settings.pluginOptions.value ; if plugs forall (p => optList(List(opt), p).isEmpty))
- error("bad option: -P:" + opt)
+ for {
+ opt <- settings.pluginOptions.value
+ if !plugs.exists(p => opt.startsWith(p.name + ":"))
+ } error("bad option: -P:" + opt)
plugs
}
- lazy val plugins: List[Plugin] = loadPlugins
+ private var pluginsCache: Option[List[Plugin]] = None
+
+ def plugins: List[Plugin] = {
+ if (pluginsCache.isEmpty)
+ pluginsCache = Some(loadPlugins)
+ pluginsCache.get
+ }
/** A description of all the plugins that are loaded */
- def pluginDescriptions: String =
- roughPluginsList map (x => "%s - %s".format(x.name, x.description)) mkString "\n"
+ def pluginDescriptions: String = {
+ val messages =
+ for (plugin <- roughPluginsList)
+ yield plugin.name + " - " + plugin.description
+ messages.mkString("\n")
+ }
/**
* Extract all phases supplied by plugins and add them to the phasesSet.
* @see phasesSet
*/
- protected def computePluginPhases(): Unit =
- phasesSet ++= (plugins flatMap (_.components))
+ protected def computePluginPhases() {
+ val plugPhases = plugins.flatMap(_.components)
+ for (pPhase <- plugPhases) {
+ phasesSet += pPhase
+ }
+ }
/** Summary of the options for all loaded plugins */
- def pluginOptionsHelp: String =
- (for (plug <- roughPluginsList ; help <- plug.optionsHelp) yield {
- "Options for plugin %s:\n%s\n".format(plug.name, help)
- }) mkString
+ def pluginOptionsHelp: String = {
+ val buf = new StringBuffer
+ for (plug <- roughPluginsList; help <- plug.optionsHelp) {
+ buf append ("Options for plugin " + plug.name + ":\n")
+ buf append help
+ buf append "\n"
+ }
+ buf.toString
+ }
}