summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/util/PathResolver.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-02-18 18:49:21 +0000
committerPaul Phillips <paulp@improving.org>2010-02-18 18:49:21 +0000
commit388a0c0d1db3e41e3acbebd6e1e4c79f7d176ca3 (patch)
treef1f5df26496c614446cea6b970f48c6659ad803d /src/compiler/scala/tools/util/PathResolver.scala
parent23e5428008fc88377e59a1a5c20d5476c586d62e (diff)
downloadscala-388a0c0d1db3e41e3acbebd6e1e4c79f7d176ca3.tar.gz
scala-388a0c0d1db3e41e3acbebd6e1e4c79f7d176ca3.tar.bz2
scala-388a0c0d1db3e41e3acbebd6e1e4c79f7d176ca3.zip
The first reasonably satisfying classpath commit.
there with this one. Documentation to come. Review by community.
Diffstat (limited to 'src/compiler/scala/tools/util/PathResolver.scala')
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala251
1 files changed, 56 insertions, 195 deletions
diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala
index 9feb61e0a3..c86c6ffe74 100644
--- a/src/compiler/scala/tools/util/PathResolver.scala
+++ b/src/compiler/scala/tools/util/PathResolver.scala
@@ -13,29 +13,13 @@ import nsc.io.{ File, Directory, Path }
import ClassPath.{ JavaContext, DefaultJavaContext, join, split }
import PartialFunction.condOpt
-// Mostly based on the specification at:
+// Loosely based on the draft specification at:
// https://lampsvn.epfl.ch/trac/scala/wiki/Classpath
-//
object PathResolver {
- // val debugLogger = {
- // val f = File("/tmp/path-resolve-log.txt")
- // if (f.exists) f.truncate()
- // else f.createFile()
- //
- // val res = f.bufferedWriter()
- // res write ("Started debug log: %s\n".format(new java.util.Date))
- // res
- // }
- // def log(msg: Any) = {
- // Console println msg
- // debugLogger.write(msg.toString + "\n")
- // debugLogger flush
- // }
-
- private def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
- private def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
- private def firstNonEmpty(xs: String*) = xs find (_ != "") getOrElse ""
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def firstNonEmpty(xs: String*) = xs find (_ != "") getOrElse ""
private def fileOpt(f: Path): Option[String] = f ifFile (_.path)
private def dirOpt(d: Path): Option[String] = d ifDirectory (_.path)
@@ -60,15 +44,21 @@ object PathResolver {
import scala.collection.JavaConversions._
System.getProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse ""
}
+ private def searchForScalaHome = {
+ for (url <- ScalaClassLoader originOfClass classOf[ScalaObject] ; if url.getProtocol == "file") yield
+ File(url.getFile).parent.path
+ } getOrElse ""
def classPathEnv = envOrElse("CLASSPATH", "")
def sourcePathEnv = envOrElse("SOURCEPATH", "") // not used
+ def scalaHomeEnv = envOrElse("SCALA_HOME", "") // not used
def javaBootClassPath = propOrElse("sun.boot.class.path", searchForBootClasspath)
def javaUserClassPath = propOrElse("java.class.path", "")
def javaExtDirs = propOrElse("java.ext.dirs", "")
def userHome = propOrElse("user.home", "")
def scalaHome = propOrElse("scala.home", "")
def scalaExtDirs = propOrElse("scala.ext.dirs", "")
+ def scalaHomeGuessed = searchForScalaHome
override def toString = """
|object Environment {
@@ -88,17 +78,13 @@ object PathResolver {
* to the path resolution specification.
*/
object Defaults {
- private lazy val guessedScalaHome = {
- for (url <- ScalaClassLoader originOfClass classOf[ScalaObject] ; if url.getProtocol == "file") yield
- File(url.getFile).parent.path
- } getOrElse ""
-
- // XXX review these semantics
- def javaBootClassPath = join(Seq(Environment.javaBootClassPath, Environment.javaUserClassPath)) // ... ignoring Environment.classPathEnv
+ def javaBootClassPath = Environment.javaBootClassPath
+ def javaUserClassPath = firstNonEmpty(Environment.javaUserClassPath, Environment.classPathEnv)
def javaExtDirs = Environment.javaExtDirs
- def scalaHome = firstNonEmpty(Environment.scalaHome, guessedScalaHome)
+ def scalaHome = Environment.scalaHome
def scalaHomeDir = Directory(scalaHome)
+ def scalaHomeExists = scalaHomeDir.isDirectory
def scalaLibDir = Directory(scalaHomeDir / "lib")
def scalaClassesDir = Directory(scalaHomeDir / "classes")
@@ -115,31 +101,15 @@ object PathResolver {
else if (scalaLibAsDir.isDirectory) scalaLibAsDir.path
else ""
- // This attempt to duplicate the original logic of MainGenericRunner
- // was causing the issue described in r20878. Obviously it's past time
- // to establish with certainty what each of these paths should contain.
- def scalaBootClassPath = ""
- // scalaLibDirFound match {
- // case Some(dir) => join(ClassPath expandDir dir.path)
- // case _ => ""
- // }
+ def scalaBootClassPath = scalaLibDirFound match {
+ case Some(dir) if scalaHomeExists => join(ClassPath expandDir dir.path)
+ case _ => ""
+ }
def scalaExtDirs = Environment.scalaExtDirs
def scalaPluginDirs = List("misc", "scala-devel", "plugins")
def scalaPluginPath = join(scalaPluginDirs map (scalaHomeDir / _ path))
- // The class path that a runner script uses to interpret a program is called the “execution class path”.
- // The execution class path is the concatenation of the following sub-path.
- // If a class is available in multiple locations, it must be loaded from that with the lowest number.
- def executionPath = List(
- // 1. The Java bootstrap class path.
- javaBootClassPath,
- // 2. The Java extension class path.
- javaExtDirs,
- // 3. The class path formed by all JAR and ZIP files and all folders in Scala's home lib folder.
- scalaBootClassPath
- )
-
override def toString = """
|object Defaults {
| javaBootClassPath = %s
@@ -155,60 +125,10 @@ object PathResolver {
)
}
- def executionPath = join(Defaults.executionPath)
- def executionPathURLs = fromPathString(executionPath).asURLs
-
- private def classPathContainersFromSettings(settings: Settings, context: JavaContext) = {
- val pr = new PathResolver(settings)
- import context._
- import pr.Calculated._
-
- // XXX how should the contents of lib/* break down between bootclasspath and extdirs?
- // XXX what exactly is codebase for?
- val sources = List(
- classesInPath(javaBootClassPath), // -javabootclasspath multiple entries, no expansion
- contentsOfDirsInPath(scalaBootClassPath), // -bootclasspath ???
- contentsOfDirsInPath(javaExtDirs), // -javaextdirs multiple dirs, each expands to contents
- contentsOfDirsInPath(scalaExtDirs), // -extdirs ???
- classesInExpandedPath(userClassPath), // -classpath multiple entries, first expanding *s
- classesAtAllURLS(codeBase), // -Ycodebase ??? multiple URLs
- sourcesInPath(sourcePath) // -sourcepath multiple source entries, no expansion
- )
-
- if (settings.Ylogcp.value)
- Console.println("PathResolver calculated classpath:\n" + pr.Calculated)
-
- sources.flatten
- }
- def urlsFromSettings(settings: Settings): List[URL] = urlsFromSettings(settings, DefaultJavaContext)
- def urlsFromSettings(settings: Settings, context: JavaContext): List[URL] =
- classPathContainersFromSettings(settings, context) flatMap (_.asURLs) distinct
-
- private def contextFromSettings(s: Settings) =
- if (s.inline.value) new JavaContext else DefaultJavaContext
-
- def fromArgumentString(argString: String): JavaClassPath =
- fromArgumentList(splitParams(argString, _ => ()))
-
- def fromArgumentList(args: List[String]): JavaClassPath = {
- val settings = new Settings()
- settings.processArguments(args, false)
- fromSettings(settings, contextFromSettings(settings))
- }
-
- def fromSettings(settings: Settings): JavaClassPath =
- fromSettings(settings, contextFromSettings(settings))
-
- def fromSettings(settings: Settings, context: JavaContext): JavaClassPath = {
- val containers = classPathContainersFromSettings(settings, context)
- new JavaClassPath(containers, context)
- }
-
- def fromPathString(path: String): JavaClassPath = fromPathString(path, DefaultJavaContext)
- def fromPathString(path: String, context: JavaContext): JavaClassPath = {
+ def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = {
val s = new Settings()
s.classpath.value = path
- fromSettings(s, context)
+ new PathResolver(s, context) result
}
/** With no arguments, show the interesting values in Environment and Defaults.
@@ -226,76 +146,15 @@ object PathResolver {
val pr = new PathResolver(settings)
println(" COMMAND: 'scala %s'".format(args.mkString(" ")))
println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" ")))
- println(pr.Calculated)
+ pr.result.show
}
}
-
- /**
- * Split command line parameters by space, properly process quoted parameter
- */
- def splitParams(line: String, errorFn: String => Unit): List[String] = {
- def parse(from: Int, i: Int, args: List[String]): List[String] = {
- if (i < line.length) {
- line.charAt(i) match {
- case ' ' =>
- val args1 = fetchArg(from, i) :: args
- val j = skipS(i + 1)
- if (j >= 0) {
- parse(j, j, args1)
- } else args1
- case '"' =>
- val j = skipTillQuote(i + 1)
- if (j > 0) {
- parse(from, j + 1, args)
- } else {
- errorFn("Parameters '" + line + "' with unmatched quote at " + i + ".")
- Nil
- }
- case _ => parse(from, i + 1, args)
- }
- } else { // done
- if (i > from) {
- fetchArg(from, i) :: args
- } else args
- }
- }
-
- def fetchArg(from: Int, until: Int) = {
- if (line.charAt(from) == '"') {
- line.substring(from + 1, until - 1)
- } else {
- line.substring(from, until)
- }
- }
-
- def skipTillQuote(i: Int): Int = {
- if (i < line.length) {
- line.charAt(i) match {
- case '"' => i
- case _ => skipTillQuote(i + 1)
- }
- } else -1
- }
-
- def skipS(i: Int): Int = {
- if (i < line.length) {
- line.charAt(i) match {
- case ' ' => skipS(i + 1)
- case _ => i
- }
- } else -1
- }
-
- // begin split
- val j = skipS(0)
- if (j >= 0) {
- parse(j, j, Nil).reverse
- } else Nil
- }
}
import PathResolver.{ Defaults, Environment, firstNonEmpty, ppcp }
-class PathResolver(settings: Settings) {
+class PathResolver(settings: Settings, context: JavaContext) {
+ def this(settings: Settings) = this(settings, if (settings.inline.value) new JavaContext else DefaultJavaContext)
+
private def cmdLineOrElse(name: String, alt: String) = {
(commandLineFor(name) match {
case Some("") => None
@@ -319,56 +178,58 @@ class PathResolver(settings: Settings) {
object Calculated {
def scalaHome = Defaults.scalaHome
def javaBootClassPath = cmdLineOrElse("javabootclasspath", Defaults.javaBootClassPath)
- def scalaBootClassPath = cmdLineOrElse("bootclasspath", Defaults.scalaBootClassPath)
def javaExtDirs = cmdLineOrElse("javaextdirs", Defaults.javaExtDirs)
+ def javaUserClassPath = Defaults.javaUserClassPath
+ def scalaBootClassPath = cmdLineOrElse("bootclasspath", Defaults.scalaBootClassPath)
def scalaExtDirs = cmdLineOrElse("extdirs", Defaults.scalaExtDirs)
- def userClassPath = cmdLineOrElse("classpath", "")
+ def userClassPath = cmdLineOrElse("classpath", ".")
def sourcePath = cmdLineOrElse("sourcepath", "")
def codeBase = cmdLineOrElse("Ycodebase", "")
- def dotPath = if (settings.userSuppliedClassPath == "") "." else ""
- def referencePath = List(
- // 1. The value of -javabootclasspath if it is set, or the Java bootstrap class path.
- javaBootClassPath,
- // 2. The value of -bootclasspath if it is set,
- // or the lib/scala-library.jar file of Scala's home if it is available,
- // or the classes/library folder of Scala's home if it is available.
- scalaBootClassPath,
- // 3. All JAR and ZIP files present in any folder listed by the value of -javaextdirs, if it is set,
- // or the Java extension class path.
- javaExtDirs,
- // 4. All JAR and ZIP files present in any folder listed by the value of -extdirs, if it is set.
- scalaExtDirs,
- // 5. The first available path below.
- // * The value of -classpath or -cp.
- // * ---> XXX what about java.class.path?
- // * The value of the CLASSPATH environment variable.
- // * The current directory (that is the location of ".").
- userClassPath,
- dotPath
+ import context._
+
+ // Assemble the elements!
+ def basis = List(
+ classesInPath(javaBootClassPath), // 1. The Java bootstrap class path.
+ contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path.
+ classesInExpandedPath(javaUserClassPath), // 3. The Java application class path.
+ classesInPath(scalaBootClassPath), // 4. The Scala boot class path.
+ contentsOfDirsInPath(scalaExtDirs), // 5. The Scala extension class path.
+ classesInExpandedPath(userClassPath), // 6. The Scala application class path.
+ sourcesInPath(sourcePath) // 7. The Scala source path.
)
+ lazy val containers = basis.flatten.distinct
+
override def toString = """
|object Calculated {
| scalaHome = %s
| javaBootClassPath = %s
+ | javaUserClassPath = %s
| scalaBootClassPath = %s
| javaExtDirs = %s
| scalaExtDirs = %s
| userClassPath = %s
| sourcePath = %s
- | referencePath = %s
|}""".trim.stripMargin.format(
scalaHome,
- ppcp(javaBootClassPath), ppcp(scalaBootClassPath),
+ ppcp(javaBootClassPath), ppcp(javaUserClassPath), ppcp(scalaBootClassPath),
ppcp(javaExtDirs), ppcp(scalaExtDirs),
- ppcp(userClassPath), ppcp(sourcePath),
- ppcp(PathResolver.this.referencePath)
+ ppcp(userClassPath), ppcp(sourcePath)
)
}
- def referencePath = join(Calculated.referencePath)
- def referencePathAsURLs = ClassPath toURLs referencePath
- def minimalPath = join(Seq(Calculated.scalaBootClassPath, Calculated.userClassPath))
- def minimalPathAsURLs = ClassPath toURLs minimalPath
+ def containers = Calculated.containers
+
+ lazy val result = {
+ val cp = new JavaClassPath(containers, context)
+ if (settings.Ylogcp.value) {
+ Console.println("Classpath built from settings: " + settings)
+ Console.println("And Environment: " + PathResolver.Environment)
+ cp.show
+ }
+ cp
+ }
+
+ def asURLs = result.asURLs
}