diff options
author | Paul Phillips <paulp@improving.org> | 2010-02-10 19:51:38 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-02-10 19:51:38 +0000 |
commit | 6e76af56f708d345bda2fff580634107945ef3fb (patch) | |
tree | 563058a03d54463fbe9139e8f9f74db23a944400 /src/compiler/scala | |
parent | 06ae221de943d7258dfa2ffcbc6c59fe9493497f (diff) | |
download | scala-6e76af56f708d345bda2fff580634107945ef3fb.tar.gz scala-6e76af56f708d345bda2fff580634107945ef3fb.tar.bz2 scala-6e76af56f708d345bda2fff580634107945ef3fb.zip |
More work on classpaths.
to have command line options following source files, at the price of
temporarily breaking tools/pathResolver. Working my way through all the
usages of classpath in trunk zeroing in on fully consistent handling.
Review by community.
Diffstat (limited to 'src/compiler/scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/CompileClient.scala | 56 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/CompileSocket.scala | 56 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/MainGenericRunner.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ScriptRunner.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/JavaPlatform.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/AbstractFile.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Path.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Socket.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Streamable.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ClassPath.scala | 134 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/MsilClassPath.scala | 110 | ||||
-rw-r--r-- | src/compiler/scala/tools/util/PathResolver.scala | 86 | ||||
-rw-r--r-- | src/compiler/scala/tools/util/StringOps.scala | 8 |
14 files changed, 268 insertions, 242 deletions
diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index d8c8caac05..4b387298f4 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -76,36 +76,40 @@ class StandardCompileClient { val (vmArgs, serverAdr) = normalize(args) if (version) { - Console.println(versionMsg) + Console println versionMsg return 0 } if (verbose) { - Console.println("[Server arguments: " + args.mkString("", " ", "]")) - Console.println("[VM arguments: " + vmArgs + "]") + Console println args.mkString("[Server arguments: ", " ", "]") + Console println "[VM arguments: %s]".format(vmArgs) } - val socket = if (serverAdr == "") compileSocket.getOrCreateSocket(vmArgs, !shutdown) - else compileSocket.getSocket(serverAdr) - var sawerror = false - if (socket eq null) { - if (shutdown) { - Console.println("[No compilation server running.]") - } else { - Console.println("Compilation failed.") - sawerror = true - } - } else { - val out = new PrintWriter(socket.getOutputStream(), true) - val in = new BufferedReader(new InputStreamReader(socket.getInputStream())) - out.println(compileSocket.getPassword(socket.getPort())) - out.println(args.mkString("", "\0", "")) - var fromServer = in.readLine() - while (fromServer ne null) { - if (compileSocket.errorPattern.matcher(fromServer).matches) - sawerror = true - Console.println(fromServer) - fromServer = in.readLine() - } - in.close ; out.close ; socket.close + val socket = + if (serverAdr == "") compileSocket.getOrCreateSocket(vmArgs, !shutdown) + else Some(compileSocket.getSocket(serverAdr)) + + val sawerror: Boolean = socket match { + case None => + val msg = if (shutdown) "[No compilation server running.]" else "Compilation failed." + Console println msg + !shutdown + + case Some(sock) => + var wasError = false + + sock.applyReaderAndWriter { (in, out) => + out println compileSocket.getPassword(sock.getPort()) + out println args.mkString("\0") + def loop: Unit = in.readLine() match { + case null => () + case fromServer => + if (compileSocket.errorPattern matcher fromServer matches) + wasError = true + + Console println fromServer + loop + } + } + wasError } if (sawerror) 1 else 0 } diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index bad1cc9d1c..305c4e211d 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -96,13 +96,13 @@ class CompileSocket { def portFile(port: Int) = portsDir / File(port.toString) /** Poll for a server port number; return -1 if none exists yet */ - private def pollPort(): Int = - portsDir.list.toList match { - case Nil => -1 - case p :: xs => - xs forall (_.delete()) - p.name.toInt - } + private def pollPort(): Int = portsDir.list match { + case it if !it.hasNext => -1 + case it => + val ret = it.next.name.toInt + it foreach (_.delete()) + ret + } /** Get the port number to which a scala compile server is connected; * If no server is running yet, then create one. @@ -140,36 +140,36 @@ class CompileSocket { def deletePort(port: Int) = portFile(port).delete() /** Get a socket connected to a daemon. If create is true, then - * create a new daemon if necessary. Returns null if the connection + * create a new daemon if necessary. Returns None if the connection * cannot be established. */ - def getOrCreateSocket(vmArgs: String, create: Boolean = true): Socket = { - val nAttempts = 49 // try for about 5 seconds - def getsock(attempts: Int): Socket = - if (attempts == 0) { - error("Unable to establish connection to compilation daemon") - null - } - else { - val port = if(create) getPort(vmArgs) else pollPort() - if(port < 0) return null - val hostAdr = InetAddress.getLocalHost() - Socket(hostAdr, port).either match { - case Right(res) => + def getOrCreateSocket(vmArgs: String, create: Boolean = true): Option[Socket] = { + // try for 5 seconds + val retryDelay = 100 + val maxAttempts = (5 * 1000) / retryDelay + + def getsock(attempts: Int): Option[Socket] = attempts match { + case 0 => error("Unable to establish connection to compilation daemon") ; None + case num => + val port = if (create) getPort(vmArgs) else pollPort() + if (port < 0) return None + + Socket(InetAddress.getLocalHost(), port).either match { + case Right(socket) => info("[Connected to compilation daemon at port %d]" format port) - res - case Left(e) => - info(e.toString) + Some(socket) + case Left(err) => + info(err.toString) info("[Connecting to compilation daemon at port %d failed; re-trying...]" format port) if (attempts % 2 == 0) - portFile(port).delete // 50% chance to stop trying on this port + deletePort(port) // 50% chance to stop trying on this port - Thread.sleep(100) // delay before retrying + Thread sleep retryDelay // delay before retrying getsock(attempts - 1) } - } - getsock(nAttempts) + } + getsock(maxAttempts) } // XXX way past time for this to be central diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index 834f4d1742..0b93be582c 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -33,7 +33,11 @@ object MainGenericRunner { return errorFn("%s\n%s".format(command.usageMsg, sampleCompiler.pluginOptionsHelp)) // append the jars in ${scala.home}/lib to the classpath, as well as "." if none was given. - settings appendToClasspath PathResolver.basicScalaClassPath(settings.classpath.value == "") + val needDot = settings.classpath.value == "" + settings appendToClasspath PathResolver.genericRunnerClassPath + if (needDot) + settings appendToClasspath "." + settings.defines.applyToCurrentJVM if (settings.version.value) diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 0657a61133..72533f76b5 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -210,15 +210,8 @@ object ScriptRunner 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()))) - } { + val socket = CompileSocket getOrCreateSocket "" getOrElse (return false) + socket.applyReaderAndWriter { (in, out) => out println (CompileSocket getPassword socket.getPort) out println (compArgs mkString "\0") @@ -227,8 +220,7 @@ object ScriptRunner if (CompileSocket.errorPattern matcher fromServer matches) compok = false } - // XXX temp until managed resource is available - in.close() ; out.close() ; socket.close() + socket.close() } compok diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index a2176a48ea..3c24d86a99 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -13,6 +13,7 @@ import util.SourceFile import Settings._ import annotation.elidable import scala.tools.util.PathResolver +import scala.collection.mutable.ListBuffer class Settings(errorFn: String => Unit) extends ScalacSettings { def this() = this(Console.println) @@ -24,6 +25,7 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { */ def processArguments(arguments: List[String]): (Boolean, List[String]) = { var args = arguments + val residualArgs = new ListBuffer[String] while (args.nonEmpty) { if (args.head startsWith "-") { @@ -37,10 +39,17 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { else if (args.head == "") { // discard empties, sometimes they appear because of ant or etc. args = args.tail } - else return (checkDependencies, args) + else { + // XXX have to rework MainGenericRunner. If we return early we break + // the ability to have command line options follow source files, but if + // we don't the command line is processed too early. + // return (checkDependencies, args) + residualArgs += args.head + args = args.tail + } } - (checkDependencies, args) + (checkDependencies, residualArgs.toList) } def processArgumentString(params: String) = processArguments(splitParams(params)) diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index 0d2f9a13d1..a62b8e5e58 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -19,11 +19,7 @@ trait JavaPlatform extends Platform[AbstractFile] { if (isInlinerOn) new JavaContext else DefaultJavaContext - new JavaClassPath( - settings.bootclasspath.value, settings.extdirs.value, - settings.classpath.value, settings.sourcepath.value, - settings.Xcodebase.value, context - ) + PathResolver.fromSettings(settings, context) } def rootLoader = new loaders.JavaPackageLoader(classPath) diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 15a05aa3fc..af93cafb68 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -109,6 +109,9 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { if (file ne null) file.exists else true + /** Does this abstract file represent something which can contain classfiles? */ + def isClassContainer = isDirectory || Path.isJarOrZip(sfile) + /** Create a file on disk, if one does not exist already. */ def create: Unit diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala index 39fba8bcb2..2b7f2620d6 100644 --- a/src/compiler/scala/tools/nsc/io/Path.scala +++ b/src/compiler/scala/tools/nsc/io/Path.scala @@ -141,6 +141,8 @@ class Path private[io] (val jfile: JFile) } // compares against extension in a CASE INSENSITIVE way. def hasExtension(other: String) = extension.toLowerCase == other.toLowerCase + // returns the filename without the extension. + def stripExtension: String = name stripSuffix ("." + extension) // conditionally execute def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None diff --git a/src/compiler/scala/tools/nsc/io/Socket.scala b/src/compiler/scala/tools/nsc/io/Socket.scala index 18ccbda7a2..e883c71b8e 100644 --- a/src/compiler/scala/tools/nsc/io/Socket.scala +++ b/src/compiler/scala/tools/nsc/io/Socket.scala @@ -6,7 +6,7 @@ package scala.tools.nsc package io -import java.io.{ IOException } +import java.io.{ IOException, InputStreamReader, BufferedReader, PrintWriter } import java.net.{ URL, MalformedURLException } import java.net.{ InetAddress, Socket => JSocket } import scala.util.control.Exception._ @@ -31,4 +31,16 @@ class Socket(jsocket: JSocket) { def getInputStream() = jsocket.getInputStream() def getPort() = jsocket.getPort() def close() = jsocket.close() + + /** Creates an InputStream and applies the closure, automatically closing it on completion. + */ + def applyReaderAndWriter[T](f: (BufferedReader, PrintWriter) => T): T = { + val out = new PrintWriter(getOutputStream(), true) + val in = new BufferedReader(new InputStreamReader(getInputStream())) + try f(in, out) + finally { + in.close() + out.close() + } + } }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/io/Streamable.scala b/src/compiler/scala/tools/nsc/io/Streamable.scala index a55028bc25..ff4520e3ca 100644 --- a/src/compiler/scala/tools/nsc/io/Streamable.scala +++ b/src/compiler/scala/tools/nsc/io/Streamable.scala @@ -101,7 +101,7 @@ object Streamable */ def bufferedReader(codec: Codec = getCodec()) = new BufferedReader(reader(codec)) - /** Creates an InputStream and applies the closure, automatically closing it on completion. + /** Creates a BufferedReader and applies the closure, automatically closing it on completion. */ def applyReader[T](f: BufferedReader => T): T = { val in = bufferedReader() diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 6be887396a..3f6bed5227 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -14,6 +14,7 @@ import java.net.URL import scala.collection.mutable.{ListBuffer, ArrayBuffer, HashSet => MutHashSet} import io.{ File, Directory, Path, AbstractFile } import scala.tools.util.StringOps.splitWhere +import Path.isJarOrZip /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as @@ -53,16 +54,10 @@ object ClassPath { if (expandStar) splitPath(path) flatMap expandS else splitPath(path) - /** Expand dir out to contents */ + /** Expand dir out to contents, a la extdir */ def expandDir(extdir: String): List[String] = { - for { - dir <- Option(AbstractFile getDirectory extdir).toList - file <- dir - if file.isDirectory || (file hasExtension "jar") || (file hasExtension "zip") - } - yield { - (dir.sfile / file.name).path - } + val dir = Option(AbstractFile getDirectory extdir) getOrElse (return Nil) + dir filter (_.isClassContainer) map (dir.sfile / _.name path) toList } /** A useful name filter. */ @@ -85,6 +80,35 @@ object ClassPath { /** From the representation to its identifier. */ def toBinaryName(rep: T): String + + /** Create a new classpath based on the abstract file. + */ + def newClassPath(file: AbstractFile): ClassPath[T] + + /** Creators for sub classpaths which preserve this context. + */ + def sourcesInPath(path: String): List[ClassPath[T]] = + for (file <- expandPath(path, false) ; dir <- Option(AbstractFile getDirectory file)) yield + new SourcePath[T](dir, this) + + def contentsOfDirsInPath(path: String): List[ClassPath[T]] = + for (dir <- expandPath(path, false) ; name <- expandDir(dir) ; entry <- Option(AbstractFile getDirectory name)) yield + newClassPath(entry) + + def classesAtAllURLS(path: String): List[ClassPath[T]] = + (path split " ").toList flatMap classesAtURL + + def classesAtURL(spec: String) = + for (url <- specToURL(spec).toList ; location <- Option(AbstractFile getURL url)) yield + newClassPath(location) + + def classesInExpandedPath(path: String) = classesInPathImpl(path, true) + def classesInPath(path: String) = classesInPathImpl(path, false) + + // Internal + private def classesInPathImpl(path: String, expand: Boolean) = + for (file <- expandPath(path, expand) ; dir <- Option(AbstractFile getDirectory file)) yield + newClassPath(dir) } class JavaContext extends ClassPathContext[AbstractFile] { @@ -92,6 +116,7 @@ object ClassPath { assert(rep.name endsWith ".class", rep.name) rep.name dropRight 6 } + def newClassPath(dir: AbstractFile) = new DirectoryClassPath(dir, this) } object DefaultJavaContext extends JavaContext { @@ -133,10 +158,6 @@ abstract class ClassPath[T] { val packages: List[ClassPath[T]] val sourcepaths: List[AbstractFile] - /** Creation controlled so context is retained. - */ - def createSourcePath(dir: AbstractFile) = new SourcePath[T](dir, context) - /** * Represents classes which can be loaded with a ClassfileLoader/MSILTypeLoader * and / or a SourcefileLoader. @@ -180,25 +201,21 @@ abstract class ClassPath[T] { } } -trait AbstractFileClassPath extends ClassPath[AbstractFile] { - def createDirectoryPath(dir: AbstractFile): DirectoryClassPath = new DirectoryClassPath(dir, context) -} - /** * A Classpath containing source files */ class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends ClassPath[T] { def name = dir.name + val sourcepaths: List[AbstractFile] = List(dir) lazy val classes: List[ClassRep] = dir partialMap { case f if !f.isDirectory && validSourceFile(f.name) => ClassRep(None, Some(f)) } toList lazy val packages: List[SourcePath[T]] = dir partialMap { - case f if f.isDirectory && validPackage(f.name) => createSourcePath(f) + case f if f.isDirectory && validPackage(f.name) => new SourcePath[T](f, context) } toList - val sourcepaths: List[AbstractFile] = List(dir) override def toString() = "sourcepath: "+ dir.toString() } @@ -206,18 +223,18 @@ class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends /** * A directory (or a .jar file) containing classfiles and packages */ -class DirectoryClassPath(dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends AbstractFileClassPath { +class DirectoryClassPath(dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] { def name = dir.name + val sourcepaths: List[AbstractFile] = Nil lazy val classes: List[ClassRep] = dir partialMap { case f if !f.isDirectory && validClassFile(f.name) => ClassRep(Some(f), None) } toList lazy val packages: List[DirectoryClassPath] = dir partialMap { - case f if f.isDirectory && validPackage(f.name) => createDirectoryPath(f) + case f if f.isDirectory && validPackage(f.name) => new DirectoryClassPath(f, context) } toList - val sourcepaths: List[AbstractFile] = Nil override def toString() = "directory classpath: "+ dir.toString() } @@ -225,12 +242,13 @@ class DirectoryClassPath(dir: AbstractFile, val context: ClassPathContext[Abstra /** * A classpath unifying multiple class- and sourcepath entries. */ -abstract class MergedClassPath[T] extends ClassPath[T] { - outer => - - protected val entries: List[ClassPath[T]] +class MergedClassPath[T]( + protected val entries: List[ClassPath[T]], + val context: ClassPathContext[T]) +extends ClassPath[T] { def name = entries.head.name + lazy val sourcepaths: List[AbstractFile] = entries flatMap (_.sourcepaths) lazy val classes: List[AnyClassRep] = { val cls = new ListBuffer[AnyClassRep] @@ -264,18 +282,13 @@ abstract class MergedClassPath[T] extends ClassPath[T] { pkg.toList } - lazy val sourcepaths: List[AbstractFile] = entries flatMap (_.sourcepaths) - - private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = newMergedClassPath(to match { - case cp: MergedClassPath[_] => cp.entries :+ pkg - case _ => List(to, pkg) - }) - - private def newMergedClassPath(entrs: List[ClassPath[T]]): MergedClassPath[T] = - new MergedClassPath[T] { - protected val entries = entrs - val context = outer.context + private def addPackage(to: ClassPath[T], pkg: ClassPath[T]) = { + val newEntries = to match { + case cp: MergedClassPath[_] => cp.entries :+ pkg + case _ => List(to, pkg) } + new MergedClassPath[T](newEntries, context) + } override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")") } @@ -285,47 +298,6 @@ abstract class MergedClassPath[T] extends ClassPath[T] { * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories. */ class JavaClassPath( - boot: String, - ext: String, - user: String, - source: String, - Xcodebase: String, - val context: JavaContext -) extends MergedClassPath[AbstractFile] with AbstractFileClassPath { - - protected val entries: List[ClassPath[AbstractFile]] = assembleEntries() - - private def assembleEntries(): List[ClassPath[AbstractFile]] = { - import ClassPath._ - val etr = new ListBuffer[ClassPath[AbstractFile]] - - def addFilesInPath(path: String, expand: Boolean, ctr: AbstractFile => ClassPath[AbstractFile]): Unit = - for (fileName <- expandPath(path, expand) ; file <- Option(AbstractFile getDirectory fileName)) yield - etr += ctr(file) - - def addContentsOfDir(path: String): Unit = - for (name <- expandDir(path) ; archive <- Option(AbstractFile getDirectory name)) - etr += createDirectoryPath(archive) - - def addContentsOfURL(spec: String): Unit = - for (url <- specToURL(spec) ; archive <- Option(AbstractFile getURL url)) - etr += createDirectoryPath(archive) - - // 1. Boot classpath - addFilesInPath(boot, false, createDirectoryPath) - - // 2. Ext classpath - addContentsOfDir(ext) - - // 3. User classpath - addFilesInPath(user, true, createDirectoryPath) - - // 4. Codebase entries (URLs) - Xcodebase.trim split " " foreach addContentsOfURL - - // 5. Source path - addFilesInPath(source, false, createSourcePath) - - etr.toList - } -} + containers: List[List[ClassPath[AbstractFile]]], + context: JavaContext) +extends MergedClassPath[AbstractFile](containers.flatten, context) { } diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index aacaf1b7ad..2de334c370 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -37,9 +37,58 @@ object MsilClassPath { class MsilContext extends ClassPathContext[MSILType] { def toBinaryName(rep: MSILType) = rep.Name + def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this) + } + + private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MSILType]] = { + import ClassPath._ + val etr = new ListBuffer[ClassPath[MSILType]] + val names = new MutHashSet[String] + + // 1. Assemblies from -Xassem-extdirs + for (dirName <- expandPath(ext, expandStar = false)) { + val dir = AbstractFile.getDirectory(dirName) + if (dir ne null) { + for (file <- dir) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += context.newClassPath(file) + } + } + } + } + + // 2. Assemblies from -Xassem-path + for (fileName <- expandPath(user, expandStar = false)) { + val file = AbstractFile.getFile(fileName) + if (file ne null) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += context.newClassPath(file) + } + } + } + + def check(n: String) { + if (!names.contains(n)) + throw new AssertionError("Cannot find assembly "+ n + + ". Use -Xassem-extdirs or -Xassem-path to specify its location") + } + check("mscorlib.dll") + check("scalaruntime.dll") + + // 3. Source path + for (dirName <- expandPath(source, expandStar = false)) { + val file = AbstractFile.getDirectory(dirName) + if (file ne null) etr += new SourcePath[MSILType](file, context) + } + + etr.toList } } -import MsilClassPath.MsilContext +import MsilClassPath._ /** * A assembly file (dll / exe) containing classes and namespaces @@ -102,57 +151,8 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: * The classpath when compiling with target:msil. Binary files are represented as * MSILType values. */ -class MsilClassPath(ext: String, user: String, source: String, val context: MsilContext) extends MergedClassPath[MSILType] { - protected val entries: List[ClassPath[MSILType]] = assembleEntries() - - def createAssemblyPath(assemFile: AbstractFile) = - new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", context) - - private def assembleEntries(): List[ClassPath[MSILType]] = { - import ClassPath._ - val etr = new ListBuffer[ClassPath[MSILType]] - val names = new MutHashSet[String] - - // 1. Assemblies from -Xassem-extdirs - for (dirName <- expandPath(ext, expandStar = false)) { - val dir = AbstractFile.getDirectory(dirName) - if (dir ne null) { - for (file <- dir) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += createAssemblyPath(file) - } - } - } - } - - // 2. Assemblies from -Xassem-path - for (fileName <- expandPath(user, expandStar = false)) { - val file = AbstractFile.getFile(fileName) - if (file ne null) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += createAssemblyPath(file) - } - } - } - - def check(n: String) { - if (!names.contains(n)) - throw new AssertionError("Cannot find assembly "+ n + - ". Use -Xassem-extdirs or -Xassem-path to specify its location") - } - check("mscorlib.dll") - check("scalaruntime.dll") - - // 3. Source path - for (dirName <- expandPath(source, expandStar = false)) { - val file = AbstractFile.getDirectory(dirName) - if (file ne null) etr += new SourcePath[MSILType](file, context) - } - - etr.toList - } -}
\ No newline at end of file +class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) + extends MergedClassPath[MSILType]( + MsilClassPath.assembleEntries(ext, user, source, context), + context + ) diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 3aca9c3ee0..72dcac36fe 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -10,7 +10,7 @@ import java.net.{ URL, MalformedURLException } import nsc.{ Settings } import nsc.util.{ ClassPath, JavaClassPath, ScalaClassLoader } import nsc.io.{ File, Directory, Path } -import ClassPath.DefaultJavaContext +import ClassPath.{ JavaContext, DefaultJavaContext } import File.{ pathSeparator } import PartialFunction.condOpt @@ -51,6 +51,7 @@ object PathResolver { def javaExtDirs = propOrElse("java.ext.dirs", "") def userHome = propOrElse("user.home", "") def scalaHome = propOrElse("scala.home", "") + def scalaExtDirs = propOrElse("scala.ext.dirs", "") // XXX not in spec def classPath = List(classPathProp, classPathEnv) find (_ != "") getOrElse "." @@ -64,8 +65,8 @@ object PathResolver { | userHome = %s | scalaHome = %s |}""".trim.stripMargin.format( - classPathEnv, toolPathEnv, ppcp(classPathProp), ppcp(javaBootClassPath), - javaExtDirs, userHome, scalaHome + ppcp(classPathEnv), ppcp(toolPathEnv), ppcp(classPathProp), ppcp(javaBootClassPath), + ppcp(javaExtDirs), userHome, scalaHome ) } @@ -91,13 +92,15 @@ object PathResolver { if (scalaLibJar.isFile) Some(scalaLibDir) else if (scalaLibClassDir.isDirectory) Some(scalaClassesDir) else None - def scalaLibPath = scalaLibFound map (_.path) getOrElse "" - def scalaExtDirs = scalaLibFound map (_.path) getOrElse "" - def expandedScalaExtDirs = if (scalaExtDirs == "") "" else expandToContents(scalaExtDirs) - def expandedClassPath = expandToPath(Environment.classPath) + def scalaBootClassPath = scalaLibFound map expandToContents getOrElse "" + def scalaExtDirs = Environment.scalaExtDirs + def scalaToolPath = Environment.toolPathEnv match { + case "" => scalaBootClassPath + case x => expandToPath(x.replaceAll("""\$\{SCALA_HOME\}""", scalaHome)) + } - val pluginSearchPath = List("misc", "scala-devel", "plugins") + def pluginSearchPath = List("misc", "scala-devel", "plugins") def scalaPluginDir = pluginSearchPath map (scalaHomeDir / _) find (_.isDirectory) map (_.path) getOrElse "" // The class path that a runner script uses to interpret a program is called the “execution class path”. @@ -114,21 +117,17 @@ object PathResolver { // This path may contain absolute locations, or locations relative to Scala's home by using // the shell variable ${SCALA_HOME} in the path. // * The class path formed by all JAR and ZIP files and all folders in Scala's home lib folder. - Environment.toolPathEnv match { - case "" => Defaults.expandedScalaExtDirs - case x => expandToPath(translateScalaHome(x)) - } + scalaToolPath ) override def toString = """ |object Defaults { | scalaHome = %s - | scalaLibFound = %s + | scalaLibFound = %s + | scalaBootClassPath = %s | scalaPluginDir = %s - | expandedClassPath = %s |}""".trim.stripMargin.format( - scalaHome, scalaLibFound, scalaPluginDir, - ppcp(expandedScalaExtDirs), ppcp(expandedClassPath) + scalaHome, scalaLibFound, ppcp(scalaBootClassPath), scalaPluginDir ) } @@ -136,28 +135,53 @@ object PathResolver { /** The original logic of MainGenericRunner. */ - def basicScalaClassPath(includeCwd: Boolean): String = { + def genericRunnerClassPath: String = { // this is to make the interpreter work when running without the scala script // (e.g. from eclipse). Before, "java.class.path" was added to the user classpath - // in Settings; this was changed to match the behavior of Sun's javac. - def maincp = - if (Environment.scalaHome == "") Defaults.expandedClassPath - else Defaults.expandedScalaExtDirs - def dotcp = if (includeCwd) "." else "" + // in Settings; this was changed to match the behavior of Sun's javac. So the + // classpath generated here consist of only the scala lib/* jars if scalaHome + // can be found, and the whole user classpath otherwise. + if (Environment.scalaHome == "") Environment.classPath + else Defaults.scalaBootClassPath + } + + private def contextFromSettings(s: Settings) = + if (s.inline.value) new JavaContext else DefaultJavaContext + + def fromArgumentString(argString: String): JavaClassPath = + fromArgumentList(argString.trim split """\s+""" toList) - joincp(Seq(maincp, dotcp)) + def fromArgumentList(args: List[String]): JavaClassPath = { + val settings = new Settings() + settings processArguments args + fromSettings(settings, contextFromSettings(settings)) } - /** XXX not yet used. - */ - def toJavaClassPath(settings: Settings): JavaClassPath = { - new JavaClassPath( - settings.bootclasspath.value, settings.extdirs.value, - settings.classpath.value, settings.sourcepath.value, - settings.Xcodebase.value, DefaultJavaContext + def fromSettings(settings: Settings): JavaClassPath = + fromSettings(settings, contextFromSettings(settings)) + + def fromSettings(settings: Settings, context: JavaContext): JavaClassPath = { + import context._ + import settings._ + + val sources = List( + classesInPath(bootclasspath.value), // -bootclasspath multiple entries, no expansion + contentsOfDirsInPath(extdirs.value), // -extdirs multiple dirs, each expands to contents + classesInExpandedPath(classpath.value), // -classpath multiple entries, first expanding *s + classesAtAllURLS(Xcodebase.value), // -Xcodebase multiple URLs + sourcesInPath(sourcepath.value) // -sourcepath multiple source entries, no expansion ) + + if (Ylogcp.value) + Console.println("Created JavaClassPath from:\n" + (new PathResolver(settings)).Calculated) + + new JavaClassPath(sources, context) } + def fromPathString(path: String): JavaClassPath = fromPathString(path, DefaultJavaContext) + def fromPathString(path: String, context: JavaContext): JavaClassPath = + new JavaClassPath(List(context.classesInExpandedPath(path)), context) + /** With no arguments, show the interesting values in Environment and Defaults. * If there are arguments, show those in Calculated as if those options had been * given to a scala runner. @@ -266,7 +290,7 @@ class PathResolver(settings: Settings) { object Calculated { def javaBootClassPath = cmdLineOrElse("javabootclasspath", Environment.javaBootClassPath) def javaExtDirs = cmdLineOrElse("javaextdirs", Environment.javaExtDirs) - def scalaBootClassPath = cmdLineOrElse("bootclasspath", Defaults.scalaLibPath) + def scalaBootClassPath = cmdLineOrElse("bootclasspath", Defaults.scalaBootClassPath) def scalaExtDirs = cmdLineOrElse("extdirs", Defaults.scalaExtDirs) def sourcePath = cmdLineOrElse("sourcepath", "") def codeBase = cmdLineOrElse("Ycodebase", "") // XXX diff --git a/src/compiler/scala/tools/util/StringOps.scala b/src/compiler/scala/tools/util/StringOps.scala index 21ece6490f..77fc6f8700 100644 --- a/src/compiler/scala/tools/util/StringOps.scala +++ b/src/compiler/scala/tools/util/StringOps.scala @@ -33,6 +33,14 @@ object StringOps { def words(str: String): List[String] = decompose(str, ' ') + def stripPrefixOpt(str: String, prefix: String): Option[String] = + if (str startsWith prefix) Some(str drop prefix.length) + else None + + def stripSuffixOpt(str: String, suffix: String): Option[String] = + if (str endsWith suffix) Some(str dropRight suffix.length) + else None + def splitWhere(str: String, f: Char => Boolean, doDropIndex: Boolean = false): Option[(String, String)] = splitAt(str, str indexWhere f, doDropIndex) |