From 960ce31287f826fa82aea226d9e03eac3821d767 Mon Sep 17 00:00:00 2001 From: Lex Spoon Date: Thu, 14 Jun 2007 21:47:37 +0000 Subject: Refactored ScriptRunner and the offline compila... Refactored ScriptRunner and the offline compilation classes so that they can be subclassed effectively. --- src/compiler/scala/tools/nsc/CompileClient.scala | 25 +++++---- src/compiler/scala/tools/nsc/CompileServer.scala | 59 +++++++++++++--------- src/compiler/scala/tools/nsc/CompileSocket.scala | 31 +++++++----- src/compiler/scala/tools/nsc/CompilerCommand.scala | 2 +- .../scala/tools/nsc/OfflineCompilerCommand.scala | 28 ++++++++++ src/compiler/scala/tools/nsc/ScriptRunner.scala | 26 +++++++--- 6 files changed, 117 insertions(+), 54 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index 8454f522df..f58ce1c087 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -10,10 +10,12 @@ import java.io.{BufferedReader, File, InputStreamReader, PrintWriter} import scala.tools.util.StringOps -/** The main class for NSC, a compiler for the programming - * language Scala. +/** The client part of the fsc offline compiler. Instead of compiling + * things itself, it send requests to a CompileServer. */ -object CompileClient { +class StandardCompileClient { + def compileSocket: CompileSocket = CompileSocket // todo: should be lazy val + val versionMsg = "Fast Scala Compiler " + Properties.versionString + " -- " + Properties.copyrightString @@ -34,13 +36,15 @@ object CompileClient { pathsList.map(absFileName).mkString("", sep, "") } - private def normalize(args: Array[String]): (String, String) = { + val fileEnding = ".scala" + + protected def normalize(args: Array[String]): (String, String) = { var i = 0 val vmArgs = new StringBuilder var serverAdr = "" while (i < args.length) { val arg = args(i) - if (arg endsWith ".scala") { + if (arg endsWith fileEnding) { args(i) = absFileName(arg) } else if (arg startsWith "-J") { //see http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javac.html#J @@ -89,20 +93,20 @@ object CompileClient { Console.println("[Server arguments: " + args.mkString("", " ", "]")) Console.println("[VM arguments: " + vmArgs + "]") } - val socket = if (serverAdr == "") CompileSocket.getOrCreateSocket(vmArgs, !shutdown) - else CompileSocket.getSocket(serverAdr) + val socket = if (serverAdr == "") compileSocket.getOrCreateSocket(vmArgs, !shutdown) + else compileSocket.getSocket(serverAdr) if (shutdown && (socket==null)) { Console.println("[No compilation server running.]") return 0 } val out = new PrintWriter(socket.getOutputStream(), true) val in = new BufferedReader(new InputStreamReader(socket.getInputStream())) - out.println(CompileSocket.getPassword(socket.getPort())) + out.println(compileSocket.getPassword(socket.getPort())) out.println(args.mkString("", "\0", "")) var sawerror = false var fromServer = in.readLine() while (fromServer ne null) { - if (CompileSocket.errorPattern.matcher(fromServer).matches) + if (compileSocket.errorPattern.matcher(fromServer).matches) sawerror = true Console.println(fromServer) fromServer = in.readLine() @@ -119,3 +123,6 @@ object CompileClient { exit(status) } } + + +object CompileClient extends StandardCompileClient diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 8b8609a38b..3fcdd5d991 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -15,13 +15,16 @@ import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} import scala.tools.nsc.util.FakePos //Position import scala.tools.util.SocketServer -/** The main class for NSC, a compiler for the programming - * language Scala. +/** + * The server part of the fsc offline compiler. It awaits compilation + * commands and executes them. It caches a compiler instance so + * that it can respond more quickly. * * @author Martin Odersky * @version 1.0 */ -object CompileServer extends SocketServer { +class StandardCompileServer extends SocketServer { + def compileSocket: CompileSocket = CompileSocket // todo: make this a lazy val val versionMsg = "Fast Scala compiler " + Properties.versionString + " -- " + @@ -52,7 +55,7 @@ object CompileServer extends SocketServer { private def spawnWatchDog(): Unit = spawn { while (true) { Thread.sleep(10000) - if (!CompileSocket.portFile(port).exists() && !inSession) { + if (!compileSocket.portFile(port).exists() && !inSession) { progress = false spawn { Thread.sleep(10000) @@ -67,12 +70,28 @@ object CompileServer extends SocketServer { var reporter: ConsoleReporter = _ + + /** Create a new compiler instance */ + def newGlobal(settings: Settings, reporter: Reporter) = + new Global(settings, reporter) { + override def inform(msg: String) = out.println(msg) + } + + + protected def newOfflineCompilerCommand( + arguments: List[String], + settings: Settings, + error: String => Unit, + interactive: Boolean) + = new OfflineCompilerCommand(arguments, settings, error, interactive) + def session() { System.out.println("New session" + ", total memory = "+ runtime.totalMemory() + ", max memory = " + runtime.maxMemory() + ", free memory = " + runtime.freeMemory) - val password = CompileSocket.getPassword(port) + System.out.flush() + val password = compileSocket.getPassword(port) val guessedPassword = in.readLine() val input = in.readLine() if ((input ne null) && password == guessedPassword) { @@ -81,12 +100,12 @@ object CompileServer extends SocketServer { progress = true val args = input.split("\0").toList if (args contains "-shutdown") { - out.println("[Scala compile server exited]") + out.println("[Compile server exited]") shutDown = true return } if (args contains "-reset") { - out.println("[Scala compile server was reset]") + out.println("[Compile server was reset]") compiler = null return } @@ -94,16 +113,7 @@ object CompileServer extends SocketServer { reporter.error(/*new Position*/ FakePos("fsc"), msg + "\n fsc -help gives more information") } - val command = new CompilerCommand(args, new Settings(error), error, false) { - override val cmdName = "fsc" - settings.disable(settings.prompt) - settings.disable(settings.resident) - new settings.BooleanSetting("-reset", "Reset compile server caches") - new settings.BooleanSetting("-shutdown", "Shutdown compile server") - new settings.StringSetting("-server", "hostname:portnumber", - "Specify compile server socket", "") - new settings.BooleanSetting("-J", "Pass directly to runtime system") - } + val command = newOfflineCompilerCommand(args, new Settings(error), error, false) reporter = new ConsoleReporter(command.settings, in, out) { // disable prompts, so that compile server cannot block @@ -125,10 +135,8 @@ object CompileServer extends SocketServer { compiler.reporter = reporter } else { if (args contains "-verbose") - out.println("[Starting new Scala compile server instance]") - compiler = new Global(command.settings, reporter) { - override def inform(msg: String) = out.println(msg) - } + out.println("[Starting new compile server instance]") + compiler = newGlobal(command.settings, reporter) } val c = compiler val run = new c.Run @@ -156,7 +164,7 @@ object CompileServer extends SocketServer { } /** A directory holding redirected output */ - private val redirectDir = new File(CompileSocket.tmpDir, "output-redirects") + private val redirectDir = new File(compileSocket.tmpDir, "output-redirects") redirectDir.mkdirs private def redirect(setter: PrintStream => Unit, filename: String) { @@ -173,9 +181,12 @@ object CompileServer extends SocketServer { System.err.println("...starting server on socket "+port+"...") System.err.flush() spawnWatchDog() - CompileSocket.setPort(port) + compileSocket.setPort(port) run() - CompileSocket.deletePort(port) + compileSocket.deletePort(port) exit(0) } } + + +object CompileServer extends StandardCompileServer diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index ec63ed5be8..85c2e273f4 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -13,28 +13,32 @@ import java.io.{BufferedReader, FileReader} import java.util.regex.Pattern import java.net._ -object CompileSocket { +/** This class manages sockets for the fsc offline compiler. */ +class CompileSocket { + protected def compileClient: StandardCompileClient = CompileClient //todo: lazy val /** The prefix of the port identification file, which is followed * by the port number. */ - private val dirName = "scalac-compile-server-port" + protected def dirName = "scalac-compile-server-port" //todo: lazy val - /** The vm-part of the command to start a new scala compile server */ - private val vmCommand = + 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 => - Properties.cmdName + cmdName case dirname => - val trial = new File(new File(dirname, "bin"), Properties.cmdName) + val trial = new File(new File(dirname, "bin"), cmdName) if (trial.canRead) trial.getPath else - Properties.cmdName + cmdName } /** The class name of the scala compile server */ - private val serverClass = "scala.tools.nsc.CompileServer" + protected val serverClass = "scala.tools.nsc.CompileServer" /** A regular expression for checking compiler output for errors */ val errorRegex = ".*errors? found.*" @@ -42,15 +46,15 @@ object CompileSocket { /** A Pattern object for checking compiler output for errors */ val errorPattern = Pattern.compile(errorRegex) - private def error(msg: String) = System.err.println(msg) + protected def error(msg: String) = System.err.println(msg) - private def fatal(msg: String) = { + protected def fatal(msg: String) = { error(msg) exit(1) } - private def info(msg: String) = - if (CompileClient.verbose) System.out.println(msg) + protected def info(msg: String) = + if (compileClient.verbose) System.out.println(msg) /** A temporary directory to use */ val tmpDir = { @@ -256,3 +260,6 @@ object CompileSocket { result } } + + +object CompileSocket extends CompileSocket diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index 22acb56a6b..0907b589d3 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -20,7 +20,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings, val cmdName = "scalac" /** The file extension of files that the compiler can process */ - val fileEnding = ".scala" + def fileEnding = ".scala" //todo: lazy val private val helpSyntaxColumnWidth: Int = Iterable.max(settings.allSettings map (_.helpSyntax.length)) diff --git a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala new file mode 100644 index 0000000000..6a132fc116 --- /dev/null +++ b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala @@ -0,0 +1,28 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2007 LAMP/EPFL + * @author Martin Odersky + */ +// $Id$ + +package scala.tools.nsc + +/** A compiler command for the offline compiler. + * + * @author Martin Odersky and Lex Spoon + */ +class OfflineCompilerCommand( + arguments: List[String], + settings: Settings, + error: String => Unit, + interactive: Boolean) +extends CompilerCommand(arguments, new Settings(error), error, false) +{ + override val cmdName = "fsc" + settings.disable(settings.prompt) + settings.disable(settings.resident) + new settings.BooleanSetting("-reset", "Reset compile server caches") + new settings.BooleanSetting("-shutdown", "Shutdown compile server") + new settings.StringSetting("-server", "hostname:portnumber", + "Specify compile server socket", "") + new settings.BooleanSetting("-J", "Pass directly to runtime system") +} diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 435d178e4d..5ce1a64d4d 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -13,7 +13,7 @@ import java.net.URL import java.util.jar.{JarEntry, JarOutputStream} import scala.tools.nsc.io.PlainFile -import scala.tools.nsc.reporters.ConsoleReporter +import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} import scala.tools.nsc.util.{CompoundSourceFile, SourceFile, SourceFileFragment} /** An object that runs Scala code in script files. @@ -42,7 +42,11 @@ import scala.tools.nsc.util.{CompoundSourceFile, SourceFile, SourceFileFragment} * @todo It would be better if error output went to stderr instead * of stdout... */ -object ScriptRunner { +class ScriptRunner { + protected def compileClient: StandardCompileClient = CompileClient //todo: lazy val + protected def compileSocket: CompileSocket = CompileSocket //todo: make lazy val + + /** Default name to use for the wrapped script */ val defaultScriptMain = "Main" @@ -194,14 +198,14 @@ object ScriptRunner { settings: GenericRunnerSettings, scriptFileIn: String): Boolean = { - val scriptFile = CompileClient.absFileName(scriptFileIn) + val scriptFile = compileClient.absFileName(scriptFileIn) for (setting:settings.StringSetting <- List( settings.classpath, settings.sourcepath, settings.bootclasspath, settings.extdirs, settings.outdir)) - setting.value = CompileClient.absFileNames(setting.value) + setting.value = compileClient.absFileNames(setting.value) val compSettingNames = (new Settings(error)).allSettings.map(_.name) @@ -218,11 +222,11 @@ object ScriptRunner { (coreCompArgs ::: List("-script", scriptMain(settings), scriptFile)) - val socket = CompileSocket.getOrCreateSocket("") + val socket = compileSocket.getOrCreateSocket("") val out = new PrintWriter(socket.getOutputStream(), true) val in = new BufferedReader(new InputStreamReader(socket.getInputStream())) - out.println(CompileSocket.getPassword(socket.getPort)) + out.println(compileSocket.getPassword(socket.getPort)) out.println(compArgs.mkString("", "\0", "")) var compok = true @@ -230,7 +234,7 @@ object ScriptRunner { var fromServer = in.readLine() while (fromServer ne null) { Console.println(fromServer) - if (CompileSocket.errorPattern.matcher(fromServer).matches) + if (compileSocket.errorPattern.matcher(fromServer).matches) compok = false fromServer = in.readLine() @@ -242,6 +246,9 @@ object ScriptRunner { compok } + protected def newGlobal(settings: Settings, reporter: Reporter) = + new Global(settings, reporter) + /** Compile a script and then run the specified closure with * a classpath for the compiled script. */ @@ -265,7 +272,7 @@ object ScriptRunner { if (settings.nocompdaemon.value) { val reporter = new ConsoleReporter(settings) - val compiler = new Global(settings, reporter) + val compiler = newGlobal(settings, reporter) val cr = new compiler.Run val wrapped = wrappedScript( @@ -370,3 +377,6 @@ object ScriptRunner { }) } } + + +object ScriptRunner extends ScriptRunner -- cgit v1.2.3