diff options
author | Paul Phillips <paulp@improving.org> | 2011-03-16 07:49:16 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-03-16 07:49:16 +0000 |
commit | eb0b73b1160c7e62e2ae0e338a9664b8b53ddbde (patch) | |
tree | d1836661a909a33fc805d302183741868582876f | |
parent | f80801c67545a28f61abd1a36a5ef8b5bc337d87 (diff) | |
download | scala-eb0b73b1160c7e62e2ae0e338a9664b8b53ddbde.tar.gz scala-eb0b73b1160c7e62e2ae0e338a9664b8b53ddbde.tar.bz2 scala-eb0b73b1160c7e62e2ae0e338a9664b8b53ddbde.zip |
Undoing some much too hacky code to implement a...
Undoing some much too hacky code to implement a -jar option and then
following wherever that led me. Tangible results include:
* much beautified scala -help, including documenting some things
never before documented in this plane of existence
* an improved Jar abstraction
* further systemization of system properties
In addition, the jars created by -savecompiled are given the right
manifest so the jar is runnable. That means you can:
scala -savecompiled bippy.scala arg1 arg2
scala -jar bippy.scala.jar arg1 arg2
And both lines should yield the same result. No review.
24 files changed, 257 insertions, 233 deletions
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 34b515cf21..fc98e30085 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -5,7 +5,7 @@ package scala.tools.nsc -import java.io.{ BufferedOutputStream, FileOutputStream, PrintStream, File => JFile } +import java.io.{ BufferedOutputStream, FileOutputStream, PrintStream } import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} import scala.tools.nsc.util.FakePos //Position import scala.tools.util.SocketServer diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala index 7f32fb3653..c8e86a752d 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala @@ -3,7 +3,6 @@ * @author Lex Spoon */ - package scala.tools.nsc /** A command for ScriptRunner */ @@ -28,40 +27,53 @@ extends CompilerCommand(args, settings) { /** thingToRun: What to run. If it is None, then the interpreter should be started * arguments: Arguments to pass to the object or script to run */ - val (thingToRun, arguments) = settings.processArguments(args, false)._2 match { - case Nil => (None, Nil) - case hd :: tl => (Some(hd), tl) + val (thingToRun, arguments) = { + val (_, remaining) = settings.processArguments(args, false) + val mainClass = + if (settings.jarfile.isDefault) None + else new io.Jar(settings.jarfile.value).mainClass + + // If there is a jar with a main class, the remaining args are passed to that. + // Otherwise, the first remaining argument is the program to run, and the rest + // of the arguments go to it. If remaining is empty, we'll start the repl. + mainClass match { + case Some(name) => (Some(name), remaining) + case _ => (remaining.headOption, remaining drop 1) + } } override def usageMsg =""" -Usage: %s <options> [<torun> <arguments>] - or %s <options> [-jar <jarfile> <arguments>] - -All options to %s are allowed. See %s -help. +Usage: @cmd@ <options> [<script|class|object> <arguments>] + or @cmd@ <options> [-jar <jarfile> <arguments>] -<torun>, if present, is an object or script file to run. +All options to @compileCmd@ are allowed. See @compileCmd@ -help. --jar <jarfile>, if present, uses the 'Main-Class' attribute -in the manifest file to determine the object to run. +The first given argument other than options to @cmd@ designates +what to run. Runnable targets are: -If neither <torun> nor -jar <jarfile> are present, run an -interactive shell. + - a file containing scala source + - the name of a compiled class + - a runnable jar file with a Main-Class attribute (if -jar is given) + - if no argument is given, the repl (interactive shell) is started -Option -howtorun allows explicitly specifying how to run <torun>: - script: it is a script file - object: it is an object name - guess: (the default) try to guess +Options to the runner which reach the java runtime: -Option -i requests that a file be pre-loaded. It is only -meaningful for interactive shells. + -Dname=prop passed directly to java to set system properties + -J<arg> -J is stripped and <arg> passed to java as-is + -nobootcp do not put the scala jars on the boot classpath (slower) -Option -e requests that its argument be executed as Scala code. +Other scala startup options: -Option -savecompiled requests that the compiled script be saved -for future use. + -howtorun specify what to run <script|object|guess> (default: guess) + -i <file> preload <file> before starting the repl + -e <string> execute <string> as if entered in the repl + -nc no compilation daemon: do not use the fsc offline compiler + -savecompiled save the compiled script in a jar for future use -Option -nocompdaemon requests that the fsc offline compiler not be used. +A file argument will be run as a scala script unless it contains only top +level classes and objects, and exactly one runnable main method. In that +case the file will be compiled and the main method invoked. This provides +a bridge between scripts and standard scala source. -Option -Dproperty=value sets a Java system property. -""".format(cmdName, cmdName, compCmdName, compCmdName) + """.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) } diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index a7c5ce4ae1..bd0ea4a4ba 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -3,17 +3,19 @@ * @author Lex Spoon */ - package scala.tools.nsc -class GenericRunnerSettings(error: String => Unit) -extends Settings(error) { +class GenericRunnerSettings(error: String => Unit) extends Settings(error) { + // A -jar option means the remainder of the command line should be + // passed to the main program in the jar. If -jar is given, jarfile + // will be set, but we also need to prepend the jar to the classpath + // since it may not be there. val jarfile = StringSetting( "-jar", "jar", "Specify the jarfile in which to look for the main class", - "") + "").stopProcessing() withPostSetHook (classpath prepend _.value) val howtorun = ChoiceSetting( @@ -41,8 +43,9 @@ extends Settings(error) { "-savecompiled", "save the compiled script (assumes the code is a script)") - val nocompdaemon = - BooleanSetting( - "-nocompdaemon", - "do not use the fsc compilation daemon") + val nc = BooleanSetting( + "-nc", + "do not use the fsc compilation daemon") withAbbreviation "-nocompdaemon" + + @deprecated("Use `nc` instead") def nocompdaemon = nc } diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 569dcfa01e..5eb6027d0a 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -11,7 +11,6 @@ import java.io.{ FileReader, InputStreamReader, PrintWriter, FileWriter, IOException } -import java.io.{ File => JFile } import io.{ Directory, File, Path, PlainFile } import java.net.URL import java.util.jar.{ JarEntry, JarOutputStream } @@ -76,44 +75,6 @@ class ScriptRunner extends HasCompileSocket { 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 - } - - loop - } - - /** 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 + "/") - } - } - - try { - val jar = new JarOutputStream(jarFile.outputStream()) - addFromDir(jar, sourcePath, "") - jar.close - } - catch { - case _: Exception => jarFile.delete() - } - } - /** Read the entire contents of a file as a String. */ private def contentsOfFile(filename: String) = File(filename).slurp() @@ -153,6 +114,8 @@ class ScriptRunner extends HasCompileSocket { scriptFile: String) (handler: String => Boolean): Boolean = { + def mainClass = scriptMain(settings) + /** Compiles the script file, and returns the directory with the compiled * class files, if the compilation succeeded. */ @@ -164,16 +127,15 @@ class ScriptRunner extends HasCompileSocket { settings.outdir.value = compiledPath.path - if (settings.nocompdaemon.value) { + if (settings.nc.value) { /** Setting settings.script.value informs the compiler this is not a * self contained compilation unit. */ - settings.script.value = scriptMain(settings) + settings.script.value = mainClass val reporter = new ConsoleReporter(settings) val compiler = newGlobal(settings, reporter) - val cr = new compiler.Run - cr compile List(scriptFile) + new compiler.Run compile List(scriptFile) if (reporter.hasErrors) None else Some(compiledPath) } else if (compileWithDaemon(settings, scriptFile)) Some(compiledPath) @@ -193,7 +155,9 @@ class ScriptRunner extends HasCompileSocket { compile match { case Some(compiledPath) => - tryMakeJar(jarFile, compiledPath) + try io.Jar.create(jarFile, compiledPath, mainClass) + catch { case _: Exception => jarFile.delete() } + if (jarOK) { compiledPath.deleteRecursively() handler(jarFile.toAbsolute.path) diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 77c7ad0147..54f74beb2c 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package io -import java.io.{ File => JFile, FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream } +import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream } import java.net.URL import PartialFunction._ diff --git a/src/compiler/scala/tools/nsc/io/Directory.scala b/src/compiler/scala/tools/nsc/io/Directory.scala index ebd6edc8d8..b4ceba682a 100644 --- a/src/compiler/scala/tools/nsc/io/Directory.scala +++ b/src/compiler/scala/tools/nsc/io/Directory.scala @@ -9,8 +9,6 @@ package scala.tools.nsc package io -import java.io.{ File => JFile } - object Directory { import scala.util.Properties.{ tmpDir, userHome, userDir } diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala index d7967d5c07..60d9a0f169 100644 --- a/src/compiler/scala/tools/nsc/io/File.scala +++ b/src/compiler/scala/tools/nsc/io/File.scala @@ -12,7 +12,7 @@ package io import java.io.{ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter, - BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, File => JFile, Closeable => JCloseable } + BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable } import java.nio.channels.{ Channel, FileChannel } import scala.io.Codec diff --git a/src/compiler/scala/tools/nsc/io/Fileish.scala b/src/compiler/scala/tools/nsc/io/Fileish.scala index 0c00c96e0b..e12fcedc39 100644 --- a/src/compiler/scala/tools/nsc/io/Fileish.scala +++ b/src/compiler/scala/tools/nsc/io/Fileish.scala @@ -28,7 +28,6 @@ class Fileish(val path: Path, val input: () => InputStream) extends Streamable.C object Fileish { def apply(f: File): Fileish = new Fileish(f, () => f.inputStream()) - def apply(f: JarEntry, in: () => InputStream): Fileish = new Fileish(Path(f.getName), in) def apply(path: String, in: () => InputStream): Fileish = new Fileish(Path(path), in) } diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala new file mode 100644 index 0000000000..0796742fb6 --- /dev/null +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -0,0 +1,77 @@ +package scala.tools.nsc +package io + +import java.io.{ InputStream, OutputStream, IOException, FileNotFoundException, FileInputStream } +import java.util.jar._ +import collection.JavaConverters._ +import Attributes.Name + +class Jar(file: File) extends Iterable[JarEntry] { + def this(path: String) = this(File(path)) + protected def errorFn(msg: String): Unit = Console println msg + + lazy val jarFile = new JarFile(file.jfile) + lazy val manifest = withJarInput(s => Option(s.getManifest)) + def mainClass = manifest map (f => f(Name.MAIN_CLASS)) + + def withJarInput[T](f: JarInputStream => T): T = { + val in = new JarInputStream(file.inputStream()) + try f(in) + finally in.close() + } + def jarWriter() = new JarWriter(file) + + override def foreach[U](f: JarEntry => U): Unit = withJarInput { in => + Iterator continually in.getNextJarEntry() takeWhile (_ != null) foreach f + } + override def iterator: Iterator[JarEntry] = this.toList.iterator + def fileishIterator: Iterator[Fileish] = jarFile.entries.asScala map (x => Fileish(x, () => getEntryStream(x))) + + private def getEntryStream(entry: JarEntry) = jarFile getInputStream entry match { + case null => errorFn("No such entry: " + entry) ; null + case x => x + } + override def toString = "" + file +} + +class JarWriter(file: File, val manifest: Manifest = new Manifest()) { + private lazy val out = new JarOutputStream(file.outputStream(), manifest) + def writeAllFrom(dir: Directory) = { + try dir.list foreach (x => addEntry(x, "")) + finally out.close() + + file + } + private def addFile(entry: File, prefix: String) { + out putNextEntry new JarEntry(prefix + entry.name) + try transfer(entry.inputStream(), out) + finally out.closeEntry() + } + private def addEntry(entry: Path, prefix: String) { + if (entry.isFile) addFile(entry.toFile, prefix) + else addDirectory(entry.toDirectory, prefix + entry.name + "/") + } + private def addDirectory(entry: Directory, prefix: String) { + entry.list foreach (p => addEntry(p, prefix)) + } + private def transfer(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 + } +} + +object Jar { + // CLASS_PATH + // CONTENT_TYPE + + def create(file: File, sourceDir: Directory, mainClass: String): File = { + val writer = new Jar(file).jarWriter() + writer.manifest(Name.MANIFEST_VERSION) = "1.0" + writer.manifest(Name.MAIN_CLASS) = mainClass + writer writeAllFrom sourceDir + } +} diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala index 3e52731c62..68e9867dd7 100644 --- a/src/compiler/scala/tools/nsc/io/Path.scala +++ b/src/compiler/scala/tools/nsc/io/Path.scala @@ -8,7 +8,7 @@ package io import java.io.{ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter, - BufferedInputStream, BufferedOutputStream, RandomAccessFile, File => JFile } + BufferedInputStream, BufferedOutputStream, RandomAccessFile } import java.net.{ URI, URL } import scala.util.Random.alphanumeric diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala index 2fb63559e9..9e7b6d6655 100644 --- a/src/compiler/scala/tools/nsc/io/PlainFile.scala +++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package io -import java.io.{ File => JFile, FileInputStream, FileOutputStream, IOException } +import java.io.{ FileInputStream, FileOutputStream, IOException } import PartialFunction._ object PlainFile { diff --git a/src/compiler/scala/tools/nsc/io/SourceJar.scala b/src/compiler/scala/tools/nsc/io/SourceJar.scala deleted file mode 100644 index 6be77963cb..0000000000 --- a/src/compiler/scala/tools/nsc/io/SourceJar.scala +++ /dev/null @@ -1,23 +0,0 @@ -package scala.tools.nsc -package io - -import java.io.IOException -import Properties.{ javaHome } -import Path.isJarOrZip -import java.util.concurrent.ExecutionException -import java.util.jar._ -import java.util.zip.ZipException -import scala.util.matching.Regex -import collection.JavaConverters._ - -class SourceJar(jarfile: File) { - private def fail(entry: JarEntry) = throw new IOException("No such entry: " + entry) - - val jarFile = new JarFile(jarfile.jfile) - def iterator: Iterator[Fileish] = jarFile.entries.asScala map (x => Fileish(x, () => getStream(x))) - def toList: List[Fileish] = iterator.toList - def getStream(entry: JarEntry) = Option(jarFile getInputStream entry) getOrElse fail(entry) - def filesNamed(name: String) = iterator filter (_.name == name) - - override def toString = jarfile.toString -} diff --git a/src/compiler/scala/tools/nsc/io/SourceReader.scala b/src/compiler/scala/tools/nsc/io/SourceReader.scala index 86c986763e..7c9b776eb3 100644 --- a/src/compiler/scala/tools/nsc/io/SourceReader.scala +++ b/src/compiler/scala/tools/nsc/io/SourceReader.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package io -import java.io.{ FileInputStream, InputStream, IOException, File => JFile } +import java.io.{ FileInputStream, InputStream, IOException } import java.nio.{ByteBuffer, CharBuffer} import java.nio.channels.{FileChannel, ReadableByteChannel, Channels} import java.nio.charset.{CharsetDecoder, CoderResult} diff --git a/src/compiler/scala/tools/nsc/io/Sources.scala b/src/compiler/scala/tools/nsc/io/Sources.scala index 317701b3c4..48682e4ad4 100644 --- a/src/compiler/scala/tools/nsc/io/Sources.scala +++ b/src/compiler/scala/tools/nsc/io/Sources.scala @@ -39,7 +39,7 @@ class Sources(val path: String) { dirs foreach { d => dbg(d) ; catchZip(addSources(d.deepFiles map (x => Fileish(x)))) } private def calculateJars() = - jars foreach { j => dbg(j) ; catchZip(addSources(new SourceJar(j).iterator)) } + jars foreach { j => dbg(j) ; catchZip(addSources(new Jar(j).fileishIterator)) } private def addSources(fs: TraversableOnce[Fileish]) = fs foreach { f => if (f.isSourceFile) add(f.name, f) } diff --git a/src/compiler/scala/tools/nsc/io/Streamable.scala b/src/compiler/scala/tools/nsc/io/Streamable.scala index 6edca13b42..03318674ee 100644 --- a/src/compiler/scala/tools/nsc/io/Streamable.scala +++ b/src/compiler/scala/tools/nsc/io/Streamable.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package io import java.net.{ URI, URL } -import java.io.{ BufferedInputStream, InputStream, PrintStream, File => JFile } +import java.io.{ BufferedInputStream, InputStream, PrintStream } import java.io.{ BufferedReader, InputStreamReader, Closeable => JCloseable } import scala.io.{ Codec, BufferedSource, Source } import collection.mutable.ArrayBuffer diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala index 666c4e5ebc..d7176364c0 100644 --- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala +++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package io -import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream, File => JFile } +import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream } import PartialFunction._ /** This class implements an in-memory file. diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala index 6e3d1d9f12..cba92d813f 100644 --- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala +++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala @@ -9,7 +9,7 @@ package io import java.net.URL import java.util.Enumeration -import java.io.{ File => JFile, IOException, InputStream, BufferedInputStream, ByteArrayInputStream } +import java.io.{ IOException, InputStream, BufferedInputStream, ByteArrayInputStream } import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream } import PartialFunction._ diff --git a/src/compiler/scala/tools/nsc/io/package.scala b/src/compiler/scala/tools/nsc/io/package.scala index 9f5eb74ab6..29174b161f 100644 --- a/src/compiler/scala/tools/nsc/io/package.scala +++ b/src/compiler/scala/tools/nsc/io/package.scala @@ -7,8 +7,27 @@ package scala.tools.nsc import java.util.concurrent.{ Future, Callable, Executors, ThreadFactory } import java.util.{ Timer, TimerTask } +import java.util.jar.{ Attributes } package object io { + type JManifest = java.util.jar.Manifest + private[io] type JFile = java.io.File + // grimly bulldozing through #4338 + private[io] object JFile { + import java.io.{ File => JJFile } // the irony of JFile being ambiguous is not overlooked + val createTempFile = JJFile.createTempFile(_: String, _: String, _: JFile) + def pathSeparator = JJFile.pathSeparator + def separator = JJFile.separator + def separatorChar = JJFile.separatorChar + def listRoots() = JJFile.listRoots() + } + private[io] implicit def installManifestOps(m: JManifest) = new ManifestOps(m) + class ManifestOps(manifest: JManifest) { + def attrs = manifest.getMainAttributes() + def apply(name: Attributes.Name) = "" + attrs.get(name) + def update(key: Attributes.Name, value: String) = attrs.put(key, value) + } + def runnable(body: => Unit): Runnable = new Runnable { override def run() = body } def callable[T](body: => T): Callable[T] = new Callable[T] { override def call() = body } def spawn[T](body: => T): Future[T] = Executors.newSingleThreadExecutor() submit callable[T](body) diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index 59794764fe..f70e6dc7d3 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -89,6 +89,14 @@ trait AbsSettings { this } + /** If the appearance of the setting should halt argument processing. */ + private var isTerminatorSetting = false + def shouldStopProcessing = isTerminatorSetting + def stopProcessing(): this.type = { + isTerminatorSetting = true + this + } + /** Issue error and return */ def errorAndValue[T](msg: String, x: T): T = { errorFn(msg) ; x } diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index 65874cb5bb..f67a9a84dc 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -36,31 +36,30 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal * Returns (success, List of unprocessed arguments) */ def processArguments(arguments: List[String], processAll: Boolean): (Boolean, List[String]) = { - var args = arguments - val residualArgs = new ListBuffer[String] - - while (args.nonEmpty) { - if (args.head startsWith "-") { - val args0 = args - args = this parseParams args - if (args eq args0) { - errorFn("bad option: '" + args.head + "'") - return ((false, args)) + def loop(args: List[String], residualArgs: List[String]): (Boolean, List[String]) = args match { + case Nil => + (checkDependencies, residualArgs) + case "--" :: xs => + (checkDependencies, xs) + case x :: xs => + val isOpt = x startsWith "-" + if (isOpt) { + val newArgs = parseParams(args) + if (args eq newArgs) { + errorFn("bad option: '" + x + "'") + (false, args) + } + else lookupSetting(x) match { + case Some(s) if s.shouldStopProcessing => (checkDependencies, newArgs) + case _ => loop(newArgs, residualArgs) + } + } + else { + if (processAll) loop(xs, residualArgs :+ x) + else (checkDependencies, args) } - } - else if (args.head == "") { // discard empties, sometimes they appear because of ant or etc. - args = args.tail - } - else { - if (!processAll) - return ((checkDependencies, args)) - - residualArgs += args.head - args = args.tail - } } - - ((checkDependencies, residualArgs.toList)) + loop(arguments filterNot (_ == ""), Nil) } def processArgumentString(params: String) = processArguments(splitParams(params), true) @@ -112,76 +111,34 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal def parseNormalArg(p: String, args: List[String]): Option[List[String]] = tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _) - def getMainClass(jarName: String): Option[String] = { - import java.io._, java.util.jar._ - try { - val in = new JarInputStream(new FileInputStream(jarName)) - val mf = in.getManifest - val res = if (mf != null) { - val name = mf.getMainAttributes getValue Attributes.Name.MAIN_CLASS - if (name != null) Some(name) - else { - errorFn("Unable to get attribute 'Main-Class' from jarfile "+jarName) - None - } - } else { - errorFn("Unable to find manifest in jarfile "+jarName) - None - } - in.close() - res - } catch { - case e: FileNotFoundException => - errorFn("Unable to access jarfile "+jarName); None - case e: IOException => - errorFn(e.getMessage); None - } - } - - def doArgs(args: List[String]): List[String] = { - if (args.isEmpty) return Nil - val arg :: rest = args - if (arg == "") { - // it looks like Ant passes "" sometimes - rest - } - else if (!arg.startsWith("-")) { - errorFn("Argument '" + arg + "' does not start with '-'.") - args - } - else if (arg == "-") { - errorFn("'-' is not a valid argument.") - args - } - else if (arg == "-jar") { - parseNormalArg("-cp", rest) match { - case Some(xs) => - getMainClass(rest.head) match { - case Some(mainClass) => mainClass :: xs - case None => args - } - case None => args + args match { + case Nil => Nil + case arg :: rest => + if (!arg.startsWith("-")) { + errorFn("Argument '" + arg + "' does not start with '-'.") + args } - } - else - // we dispatch differently based on the appearance of p: - // 1) If it has a : it is presumed to be -Xfoo:bar,baz - // 2) If the first two chars are the name of a command, -Dfoo=bar - // 3) Otherwise, the whole string should be a command name - // - // Internally we use Option[List[String]] to discover error, - // but the outside expects our arguments back unchanged on failure - if (arg contains ":") parseColonArg(arg) match { - case Some(_) => rest - case None => args + else if (arg == "-") { + errorFn("'-' is not a valid argument.") + args } - else parseNormalArg(arg, rest) match { - case Some(xs) => xs - case None => args + else { + // we dispatch differently based on the appearance of p: + // 1) If it has a : it is presumed to be -Xfoo:bar,baz + // 2) Otherwise, the whole string should be a command name + // + // Internally we use Option[List[String]] to discover error, + // but the outside expects our arguments back unchanged on failure + if (arg contains ":") parseColonArg(arg) match { + case Some(_) => rest + case None => args + } + else parseNormalArg(arg, rest) match { + case Some(xs) => xs + case None => args + } } } - - doArgs(args) } /** Initializes these settings for embedded use by type `T`. diff --git a/src/library/scala/sys/BooleanProp.scala b/src/library/scala/sys/BooleanProp.scala new file mode 100644 index 0000000000..0f04d1f45e --- /dev/null +++ b/src/library/scala/sys/BooleanProp.scala @@ -0,0 +1,34 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.sys + +/** A few additional conveniences for Boolean properties. + */ +trait BooleanProp extends Prop[Boolean] { + /** The default implementation of `value` adheres to java's definition + * of truth, which means it is true only if there is a value in the map and + * that value, once converted to all lower case, is equal to "true". + * + * @return true if the current String is considered true, false otherwise + */ + def value: Boolean + + /** Alter this property so that `value` will be true. */ + def enable(): Unit + + /** Alter this property so that `value` will be false. */ + def disable(): Unit + + /** Toggle the property between enabled and disabled states. */ + def toggle(): Unit +} + +object BooleanProp { + implicit def booleanPropAsBoolean(b: BooleanProp): Boolean = b.value +} diff --git a/src/library/scala/sys/Prop.scala b/src/library/scala/sys/Prop.scala index 8444976826..1ac63ebc71 100644 --- a/src/library/scala/sys/Prop.scala +++ b/src/library/scala/sys/Prop.scala @@ -60,27 +60,6 @@ trait Prop[T] { protected def zero: T } -/** A few additional conveniences for Boolean properties. - */ -trait BooleanProp extends Prop[Boolean] { - /** The default implementation of `value` adheres to java's definition - * of truth, which means it is true only if there is a value in the map and - * that value, once converted to all lower case, is equal to "true". - * - * @return true if the current String is considered true, false otherwise - */ - def value: Boolean - - /** Alter this property so that `value` will be true. */ - def enable(): Unit - - /** Alter this property so that `value` will be false. */ - def disable(): Unit - - /** Toggle the property between enabled and disabled states. */ - def toggle(): Unit -} - object Prop extends PropCompanion { /** A creator of property instances. For any type `T`, if an implicit * parameter of type Creator[T] is in scope, a Prop[T] can be created diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index cc8131220f..de3f9598f0 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -48,6 +48,8 @@ object SystemProperties { // Todo: bring some sanity to the intersection of system properties aka "mutable // state shared by everyone and everything" and the reality that there is no other // mechanism for accomplishing some things on the jvm. - lazy val headless = bool("java.awt.headless", "system should not utilize a display device") - lazy val preferIPv4 = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets") + lazy val headless = bool("java.awt.headless", "system should not utilize a display device") + lazy val preferIPv4 = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets") + lazy val noTraceSupression = bool("scala.control.no-trace-suppression", "scala should not suppress any stack trace creation") } + diff --git a/src/library/scala/util/control/NoStackTrace.scala b/src/library/scala/util/control/NoStackTrace.scala index d8cd36aa02..f33e8cd013 100644 --- a/src/library/scala/util/control/NoStackTrace.scala +++ b/src/library/scala/util/control/NoStackTrace.scala @@ -10,19 +10,14 @@ package scala.util.control /** A trait for exceptions which, for efficiency reasons, do not * fill in the stack trace. Stack trace suppression can be disabled - * on a global basis by setting the system property named at - * NoStackTrace.DisableProperty. + * on a global basis via a system property wrapper in + * [[ scala.sys.SystemProperties ]]. * * @author Paul Phillips * @since 2.8 */ trait NoStackTrace extends Throwable { override def fillInStackTrace(): Throwable = - if (sys.props contains NoStackTrace.DisableProperty) super.fillInStackTrace() + if (sys.SystemProperties.noTraceSupression) super.fillInStackTrace() else this } - -object NoStackTrace { - // TODO: systematic naming scheme. - final val DisableProperty = "scala.control.no-trace-suppression" -} |