summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-02-10 19:51:38 +0000
committerPaul Phillips <paulp@improving.org>2010-02-10 19:51:38 +0000
commit6e76af56f708d345bda2fff580634107945ef3fb (patch)
tree563058a03d54463fbe9139e8f9f74db23a944400 /src/compiler/scala
parent06ae221de943d7258dfa2ffcbc6c59fe9493497f (diff)
downloadscala-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.scala56
-rw-r--r--src/compiler/scala/tools/nsc/CompileSocket.scala56
-rw-r--r--src/compiler/scala/tools/nsc/MainGenericRunner.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala14
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala6
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala3
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/Socket.scala14
-rw-r--r--src/compiler/scala/tools/nsc/io/Streamable.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala134
-rw-r--r--src/compiler/scala/tools/nsc/util/MsilClassPath.scala110
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala86
-rw-r--r--src/compiler/scala/tools/util/StringOps.scala8
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)