diff options
author | Paul Phillips <paulp@improving.org> | 2009-08-18 18:11:24 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-08-18 18:11:24 +0000 |
commit | 1d28a77bf349e8e03a0eb53da554959c80864220 (patch) | |
tree | 42a4c13621da73f601d284300e1831e7bcd2f1b9 | |
parent | 917101fd0de9580e1fd18b69778022f01cb6d29d (diff) | |
download | scala-1d28a77bf349e8e03a0eb53da554959c80864220.tar.gz scala-1d28a77bf349e8e03a0eb53da554959c80864220.tar.bz2 scala-1d28a77bf349e8e03a0eb53da554959c80864220.zip |
A bunch of cleanup on scriptrunner and fsc perf...
A bunch of cleanup on scriptrunner and fsc performed in a quest to fix
#1889. I understand why #1889 happens now but I believe fixing it is
going to require adjusting the logic in SymbolLoaders.
-rw-r--r-- | src/compiler/scala/tools/nsc/CompileSocket.scala | 93 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ScriptRunner.scala | 449 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/PlainFile.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/util/SocketServer.scala | 10 | ||||
-rw-r--r-- | src/library/scala/io/File.scala | 33 |
7 files changed, 283 insertions, 319 deletions
diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index 1a0fc7d877..42b91a59ad 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -6,10 +6,8 @@ package scala.tools.nsc -import java.lang.{Thread, System, Runtime} -import java.lang.NumberFormatException -import java.io.{File, IOException, PrintWriter, FileOutputStream} -import java.io.{BufferedReader, FileReader} +import java.io.{ File, IOException, FileNotFoundException, PrintWriter, FileOutputStream } +import java.io.{ BufferedReader, FileReader } import java.util.regex.Pattern import java.net._ @@ -25,17 +23,13 @@ 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 = new File(new File(dirname, "bin"), cmdName) - if (trial.canRead) - trial.getPath - else - cmdName - } + protected val vmCommand = Properties.scalaHome match { + case null => cmdName + case dirname => + val trial = scala.io.File(dirname) / "bin" / cmdName + if (trial.canRead) trial.path + else cmdName + } /** The class name of the scala compile server */ protected val serverClass = "scala.tools.nsc.CompileServer" @@ -44,7 +38,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) @@ -144,14 +138,12 @@ class CompileSocket { /** Set the port number to which a scala compile server is connected */ def setPort(port: Int) { - 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()) + val file = scala.io.File(portFile(port)) + val secret = new java.security.SecureRandom().nextInt.toString + + try file writeAll List(secret) catch { + case e @ (_: FileNotFoundException | _: SecurityException) => + fatal("Cannot create file: %s".format(file.absolutePath)) } } @@ -162,7 +154,7 @@ class CompileSocket { * create a new daemon if necessary. Returns null if the connection * cannot be established. */ - def getOrCreateSocket(vmArgs: String, create: Boolean): Socket = { + def getOrCreateSocket(vmArgs: String, create: Boolean = true): Socket = { val nAttempts = 49 // try for about 5 seconds def getsock(attempts: Int): Socket = if (attempts == 0) { @@ -193,45 +185,40 @@ class CompileSocket { getsock(nAttempts) } - /** Same as getOrCreateSocket(vmArgs, true). */ - def getOrCreateSocket(vmArgs: String): Socket = - getOrCreateSocket(vmArgs, true) + // XXX way past time for this to be central + def parseInt(x: String): Option[Int] = + try { Some(x.toInt) } + catch { case _: NumberFormatException => None } def getSocket(serverAdr: String): Socket = { - 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 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 + } } } def getSocket(hostName: String, port: Int): Socket = - try { - new Socket(hostName, port) - } catch { - case e: /*IO+Security*/Exception => - fatal("Unable to establish connection to server " + - hostName + ":" + port + "; exiting") + try new Socket(hostName, port) catch { + case e @ (_: IOException | _: SecurityException) => + fatal("Unable to establish connection to server %s:%d; exiting".format(hostName, port)) } def getPassword(port: Int): String = { - val ff = portFile(port) - val f = new BufferedReader(new FileReader(ff)) + val ff = scala.io.File(portFile(port)) + val f = ff.bufferedReader() + // allow some time for the server to start up - var retry = 50 - while (ff.length() == 0 && retry > 0) { - Thread.sleep(100) - retry -= 1 + def check = { + Thread sleep 100 + ff.file.length() } - if (ff.length() == 0) { + if (Iterator continually check take 50 find (_ > 0) isEmpty) { ff.delete() fatal("Unable to establish connection to server.") } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 1f2c0a21aa..315d09d54f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -268,7 +268,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable if (forMSIL) inform("[AssemRefs = " + settings.assemrefs.value + "]") } - def getSourceFile(f: AbstractFile): SourceFile = + def getSourceFile(f: AbstractFile): BatchSourceFile = new BatchSourceFile(f, reader.read(f)) def getSourceFile(name: String): SourceFile = { diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index e31dcd38f9..0a7b0aeeec 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -6,12 +6,19 @@ package scala.tools.nsc -import java.io.{BufferedReader, File, FileInputStream, FileOutputStream, - FileReader, InputStreamReader, PrintWriter, - FileWriter, IOException} +import java.io.{ + InputStream, OutputStream, + BufferedReader, FileInputStream, FileOutputStream, + FileReader, InputStreamReader, PrintWriter, FileWriter, + IOException +} +import scala.io.File +// import scala.io.arm.ManagedResource +import java.io.{ File => JFile } import java.lang.reflect.InvocationTargetException import java.net.URL -import java.util.jar.{JarEntry, JarOutputStream} +import java.util.jar.{ JarEntry, JarOutputStream } +import java.util.regex.Pattern import scala.tools.nsc.io.PlainFile import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} @@ -43,136 +50,123 @@ 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 { +object ScriptRunner +{ + /* While I'm chasing down the fsc and script bugs. */ + def DBG(msg: Any) { + System.err.println(msg.toString) + System.err.flush() + } + /** 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) = - 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 filename = - if (scriptFile.matches(".*\\.[^.\\\\/]*")) - scriptFile.replaceFirst("\\.[^.\\\\/]*$", ".jar") - else - scriptFile + ".jar" - - new File(filename) + 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. */ + private def jarFileFor(scriptFile: String): JFile = { + val name = + if (scriptFile endsWith ".jar") scriptFile + else scriptFile + ".jar" + + File(name).file + } + + 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 + } + + loop } /** Try to create a jar file out of all the contents * of the directory <code>sourcePath</code>. */ - 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 + "/") - } - } + private def tryMakeJar(jarFile: JFile, sourcePath: JFile) = { + def addFromDir(jar: JarOutputStream, dir: JFile, prefix: String) { + def addFileToJar(entry: JFile) = { + jar putNextEntry new JarEntry(prefix + entry.getName) + copyStreams(new FileInputStream(entry), jar) + jar.closeEntry } - addFromDir(sourcePath, "") + dir.listFiles foreach { entry => + if (entry.isFile) addFileToJar(entry) + else addFromDir(jar, entry, prefix + entry.getName + "/") + } + } + + try { + val jar = new JarOutputStream(File(jarFile).outputStream()) + addFromDir(jar, 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): 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") - } + private def contentsOfFile(filename: String) = File(filename).toSource().mkString /** 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 = { - import java.util.regex._ - + val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE) val fileContents = contentsOfFile(filename) + def isValid = List("#!", "::#!") exists (fileContents startsWith _) - 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 + 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 ::!#") + } } /** Split a fully qualified object name into a * package and an unqualified object name */ - 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)) - } + 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)) + } /** Code that is added to the beginning of a script file to make * it a complete Scala compilation unit. */ - 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") + 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) } /** Code that is added to the end of a script file to make * it a complete Scala compilation unit. */ - val endCode = "\n} \n} }\n" - + val endCode = """ + | } + | } + | } + |""".stripMargin /** Wrap a script file into a runnable object named * <code>scala.scripting.Main</code>. @@ -180,20 +174,12 @@ object ScriptRunner { def wrappedScript( objectName: String, filename: String, - getSourceFile: PlainFile => SourceFile): SourceFile = + getSourceFile: PlainFile => BatchSourceFile): SourceFile = { - val preamble = - new BatchSourceFile("<script preamble>", - preambleCode(objectName).toCharArray) - + val preamble = new BatchSourceFile("<script preamble>", preambleCode(objectName).toCharArray) val middle = { - 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 bsf = getSourceFile(PlainFile fromPath filename) + new SourceFileFragment(bsf, headerLength(filename), bsf.length) } val end = new BatchSourceFile("<script trailer>", endCode.toCharArray) @@ -210,53 +196,42 @@ object ScriptRunner { settings: GenericRunnerSettings, scriptFileIn: String): Boolean = { - val scriptFile = CompileClient.absFileName(scriptFileIn) - for (setting <- List( - settings.classpath, - settings.sourcepath, - settings.bootclasspath, - settings.extdirs, - settings.outdir)) - setting.value = CompileClient.absFileNames(setting.value) - - val compSettingNames = - (new Settings(error)).allSettings.map(_.name) - - 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())) + val scriptFile = CompileClient absFileName scriptFileIn - 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 + { + import settings._ + for (setting <- List(classpath, sourcepath, bootclasspath, extdirs, outdir)) { + // DBG("%s = %s".format(setting.name, setting.value)) + setting.value = CompileClient absFileName setting.value + } + } - fromServer = in.readLine() + 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() } - in.close() - out.close() - socket.close() compok } @@ -269,101 +244,82 @@ object ScriptRunner { * * @returns true if compilation and the handler succeeds, false otherwise. */ - private def withCompiledScript - (settings: GenericRunnerSettings, scriptFile: String) - (handler: String => Boolean) - : Boolean = { + 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 + /** Compiles the script file, and returns the directory with the compiled + * class files, if the compilation succeeded. + */ + def compile: Option[JFile] = { + val compiledPath = File tempdir "scalascript" // delete the directory after the user code has finished - Runtime.getRuntime.addShutdownHook(new Thread { - override def run { deleteRecursively(compiledPath) }}) + addShutdownHook(deleteRecursively(compiledPath.file)) - settings.outdir.value = compiledPath.getPath + settings.outdir.value = compiledPath.path 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) - Some(compiledPath) - else - None - } else { - if (compileWithDaemon(settings, scriptFile)) - Some(compiledPath) - else - None + val wrapped = wrappedScript(scriptMain(settings), scriptFile, compiler getSourceFile _) + + cr compileSources List(wrapped) + if (reporter.hasErrors) None else Some(compiledPath.file) } + else if (compileWithDaemon(settings, scriptFile)) Some(compiledPath.file) + else None } if (settings.savecompiled.value) { - val jarFile = jarFileFor(scriptFile) - - def jarOK = (jarFile.canRead && - (jarFile.lastModified > new File(scriptFile).lastModified)) + val jarFile = File(jarFileFor(scriptFile)) + def jarOK = jarFile.canRead && (jarFile isFresher File(scriptFile)) - if (jarOK) { - // pre-compiled jar is current - handler(jarFile.getAbsolutePath) - } else { - // The pre-compiled jar is old. Recompile the script. + def recompile() = { jarFile.delete compile match { case Some(compiledPath) => - tryMakeJar(jarFile, compiledPath) + tryMakeJar(jarFile.file, compiledPath) if (jarOK) { - deleteRecursively(compiledPath) // may as well do it now - handler(jarFile.getAbsolutePath) - } else { - // jar failed; run directly from the class files - handler(compiledPath.getPath) + deleteRecursively(compiledPath) + handler(jarFile.absolutePath) } - case None => false + // jar failed; run directly from the class files + else handler(compiledPath.getPath) + case _ => false } } - } 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 - } + + if (jarOK) handler(jarFile.absolutePath) // pre-compiled jar is current + else recompile() // jar old - recompile the script. } + // don't use a cache jar at all--just use the class files + else compile map (cp => handler(cp.getPath)) 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: File): Option[URL] = - try { Some(f.toURL) } - catch { case e => Console.err.println(e); None } + 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 } def paths(str: String, expandStar: Boolean): List[URL] = - for ( - file <- ClassPath.expandPath(str, expandStar) map (new File(_)) if file.exists; - val url = fileToURL(file); if !url.isEmpty - ) yield url.get + for { + file <- ClassPath.expandPath(str, expandStar) map (new JFile(_)) + if file.exists + url <- fileToURL(file) + } yield url val classpath = (paths(settings.bootclasspath.value, true) ::: @@ -376,64 +332,47 @@ object ScriptRunner { scriptMain(settings), scriptArgs.toArray) true - } catch { - case e: ClassNotFoundException => - Console.println(e) - false - case e: NoSuchMethodException => - Console.println(e) + } + catch { + case e @ (_: ClassNotFoundException | _: NoSuchMethodException) => + Console println e false - case e:InvocationTargetException => + 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 = { - 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 - } - } + scriptArgs: List[String]): Boolean = + { + if (File(scriptFile).isFile) + withCompiledScript(settings, scriptFile) { runCompiled(settings, _, scriptArgs) } + else + throw new IOException("no such file: " + scriptFile) } /** 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.createTempFile("scalacmd", ".scala") - + def runCommand( + settings: GenericRunnerSettings, + command: String, + scriptArgs: List[String]) : Boolean = + { + val scriptFile = File.tempfile("scalacmd", ".scala") // save the command to the file - { - val str = new FileWriter(scriptFile) - str.write(command) - str.close() - } + scriptFile writeAll List(command) - 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 + try withCompiledScript(settings, scriptFile.path) { runCompiled(settings, _, scriptArgs) } + finally scriptFile.delete() // in case there was a compilation error } } diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index d99644303d..af0e0293fe 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -25,8 +25,9 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { protected def classpathDefault = syspropopt("env.classpath") orElse syspropopt("java.class.path") getOrElse "" - protected def bootclasspathDefault = - concatPath(syspropopt("sun.boot.class.path"), guessedScalaBootClassPath) + protected def bootclasspathDefault = syspropopt("sun.boot.class.path") getOrElse "" + // XXX scala-library.jar was being added to both boot and regular classpath until 8/18/09 + // concatPath(syspropopt("sun.boot.class.path"), guessedScalaBootClassPath) protected def extdirsDefault = concatPath(syspropopt("java.ext.dirs"), guessedScalaExtDirs) @@ -216,6 +217,9 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { lazy val PhasesSetting = untupled(tupled(phase _) andThen add[PhasesSetting]) lazy val DefinesSetting = add(defines()) lazy val OutputSetting = untupled(tupled(output _) andThen add[OutputSetting]) + + override def toString() = + "Settings(\n%s)" format (settingSet filter (s => !s.isDefault) map (" " + _ + "\n") mkString) } object Settings { @@ -403,6 +407,7 @@ object Settings { def eqValues: List[Any] = List(name, value) def isEq(other: Setting) = eqValues == other.eqValues override def hashCode() = name.hashCode + override def toString() = "%s = %s".format(name, value) } /** A setting represented by a positive integer */ diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala index a52ec203dc..23082f92fb 100644 --- a/src/compiler/scala/tools/nsc/io/PlainFile.scala +++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala @@ -10,14 +10,16 @@ package io import java.io.{File, FileInputStream, FileOutputStream, IOException} -object PlainFile { +object PlainFile +{ /** * If the specified File exists, returns an abstract file backed * by it. Otherwise, returns null. */ - def fromFile(file: File): AbstractFile = + 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. diff --git a/src/compiler/scala/tools/util/SocketServer.scala b/src/compiler/scala/tools/util/SocketServer.scala index 79c081bdc8..1a1815f02a 100644 --- a/src/compiler/scala/tools/util/SocketServer.scala +++ b/src/compiler/scala/tools/util/SocketServer.scala @@ -45,12 +45,10 @@ abstract class SocketServer { // some cleanup, if any def timeout() {} - val serverSocket = try { - new ServerSocket(0) - } catch { - case e: IOException => - fatal("Could not listen on any port; exiting.") - } + val serverSocket = + try new ServerSocket(0) + catch { case e: IOException => fatal("Could not listen on any port; exiting.") } + val port: Int = serverSocket.getLocalPort() def run() { diff --git a/src/library/scala/io/File.scala b/src/library/scala/io/File.scala index 6c15152921..6cc37d3825 100644 --- a/src/library/scala/io/File.scala +++ b/src/library/scala/io/File.scala @@ -22,6 +22,29 @@ object File def apply(fileName: String) = new File(new JFile(fileName)) def apply(file: JFile) = new File(file) + + private def randomPrefix = { + import scala.util.Random.nextInt + import Character.isJavaIdentifierPart + + (Iterator continually nextInt) + . map (x => ((x % 60) + 'A').toChar) + . filter (isJavaIdentifierPart) + . take (6) + . mkString + } + // Create a temporary file + def tempfile(prefix: String = randomPrefix, suffix: String = null, dir: JFile = null) = + apply(JFile.createTempFile(prefix, suffix, dir)) + + // Like tempfile but creates a directory instead + def tempdir(prefix: String = randomPrefix, suffix: String = null, dir: JFile = null) = { + val file = tempfile(prefix, suffix, dir) + file.delete() + file.mkdirs() + file + } + } import File._ @@ -33,6 +56,16 @@ import File._ */ class File(val file: JFile)(implicit val codec: Codec = Codec.default) extends collection.Iterable[File] { + def path = file.getPath() + def absolutePath = file.getAbsolutePath() + def delete() = file.delete() + def mkdirs() = file.mkdirs() + def isFile = file.isFile() + def canRead = file.canRead() + def canWrite = file.canWrite() + + def isFresher(other: File) = file.lastModified > other.file.lastModified + /** If file is a directory, an iterator over its contents. * If not, an empty iterator. */ |