diff options
author | Paul Phillips <paulp@improving.org> | 2010-02-18 18:49:21 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-02-18 18:49:21 +0000 |
commit | 388a0c0d1db3e41e3acbebd6e1e4c79f7d176ca3 (patch) | |
tree | f1f5df26496c614446cea6b970f48c6659ad803d /src/compiler/scala/tools/util/PathResolver.scala | |
parent | 23e5428008fc88377e59a1a5c20d5476c586d62e (diff) | |
download | scala-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.scala | 251 |
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 } |