summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-03-16 07:49:16 +0000
committerPaul Phillips <paulp@improving.org>2011-03-16 07:49:16 +0000
commiteb0b73b1160c7e62e2ae0e338a9664b8b53ddbde (patch)
treed1836661a909a33fc805d302183741868582876f /src/compiler
parentf80801c67545a28f61abd1a36a5ef8b5bc337d87 (diff)
downloadscala-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.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerCommand.scala62
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerSettings.scala19
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala52
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Directory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/File.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Fileish.scala1
-rw-r--r--src/compiler/scala/tools/nsc/io/Jar.scala77
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/SourceJar.scala23
-rw-r--r--src/compiler/scala/tools/nsc/io/SourceReader.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Sources.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Streamable.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/package.scala19
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsSettings.scala8
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala135
20 files changed, 216 insertions, 202 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`.