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 | |
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')
12 files changed, 197 insertions, 258 deletions
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index 76cb8e608b..6697146a5a 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -38,6 +38,4 @@ extends Settings(error) { BooleanSetting( "-nocompdaemon", "do not use the fsc compilation daemon") - - val defines = DefinesSetting } diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 3b6b7a1a7f..6e06518a7a 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -192,7 +192,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** the compiler's classpath, as URL's */ /** XXX ignoring codebase for now, but it used to be appended here. */ /** (And one would think it ought to be prepended. */ - lazy val compilerClasspath: List[URL] = new PathResolver(settings) minimalPathAsURLs + lazy val compilerClasspath: List[URL] = new PathResolver(settings) asURLs /* A single class loader is used for all commands interpreted by this Interpreter. It would also be possible to create a new class loader for each command diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 7060c14ea2..c04feb9efd 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -112,8 +112,8 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** Create a new interpreter. */ def createInterpreter() { - if (!addedClasspath.isEmpty) - addedClasspath foreach (settings appendToClasspath _) + // if (!addedClasspath.isEmpty) + // addedClasspath foreach (settings appendToClasspath _) interpreter = new Interpreter(settings, out) { override protected def parentClassLoader = classOf[InterpreterLoop].getClassLoader diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index 719425c40c..bb373c69e4 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -13,7 +13,7 @@ import java.lang.reflect.InvocationTargetException import java.net.{ URL, MalformedURLException } import scala.tools.util.PathResolver -import io.{ File } +import io.{ File, Process } import util.{ ClassPath, ScalaClassLoader } import Properties.{ versionString, copyrightString } @@ -43,7 +43,7 @@ object MainGenericRunner { def dashi = settings.loadfiles.value def slurp = dashi map (file => File(file).slurp()) mkString "\n" - val classpath: List[URL] = PathResolver urlsFromSettings settings + val classpath: List[URL] = new PathResolver(settings) asURLs /** Was code given in a -e argument? */ if (!settings.execute.isDefault) { diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 5d5e4c8c43..0cd5fe1f6a 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -300,8 +300,8 @@ object ScriptRunner compiledLocation: String, scriptArgs: List[String]): Boolean = { - val classpath = - (PathResolver urlsFromSettings settings) ::: (PathResolver fromPathString compiledLocation asURLs) + val pr = new PathResolver(settings) + val classpath = pr.asURLs :+ new URL(compiledLocation) try { ObjectRunner.run( diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index 9585db7c64..39ea8f62c6 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -12,20 +12,13 @@ import io.AbstractFile import util.{ ClassPath, SourceFile } import Settings._ import annotation.elidable -import scala.tools.util.PathResolver +import scala.tools.util.{ PathResolver, StringOps } import scala.collection.mutable.ListBuffer import scala.collection.immutable.TreeSet class Settings(errorFn: String => Unit) extends ScalacSettings { def this() = this(Console.println) - /** It's a hacky situation but there's not much to be done in the - * face of settings which mutate and semantic significance to the - * originally given classpath. - */ - private var _userSuppliedClassPath: String = null - def userSuppliedClassPath = if (_userSuppliedClassPath == null) "" else _userSuppliedClassPath - /** Iterates over the arguments applying them to settings where applicable. * Then verifies setting dependencies are met. * @@ -47,23 +40,13 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { var args = arguments val residualArgs = new ListBuffer[String] - /** First time through here we take note of the classpath, if any. - */ - def finish[T](x: T): T = { - /** "lazy var" */ - if (_userSuppliedClassPath == null) - _userSuppliedClassPath = if (classpath.isDefault) "" else classpath.value - - x - } - while (args.nonEmpty) { if (args.head startsWith "-") { val args0 = args args = this parseParams args if (args eq args0) { errorFn("bad option: '" + args.head + "'") - return finish((false, args)) + return ((false, args)) } } else if (args.head == "") { // discard empties, sometimes they appear because of ant or etc. @@ -71,14 +54,14 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { } else { if (!processAll) - return finish((checkDependencies, args)) + return ((checkDependencies, args)) residualArgs += args.head args = args.tail } } - finish((checkDependencies, residualArgs.toList)) + ((checkDependencies, residualArgs.toList)) } def processArgumentString(params: String) = processArguments(splitParams(params), true) @@ -124,7 +107,7 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { /** Split the given line into parameters. */ - def splitParams(line: String) = PathResolver.splitParams(line, errorFn) + def splitParams(line: String) = StringOps.splitParams(line, errorFn) /** Returns any unprocessed arguments. */ @@ -145,19 +128,18 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { // if arg is of form -Xfoo:bar,baz,quux def parseColonArg(s: String): Option[List[String]] = { - val idx = s indexWhere (_ == ':') - val (p, args) = (s.substring(0, idx), s.substring(idx+1).split(",").toList) + val (p, args) = StringOps.splitWhere(s, _ == ':', true) getOrElse (return None) // any non-Nil return value means failure and we return s unmodified - tryToSetIfExists(p, args, (s: Setting) => s.tryToSetColon _) + tryToSetIfExists(p, args split "," toList, (s: Setting) => s.tryToSetColon _) } // if arg is of form -Dfoo=bar or -Dfoo (name = "-D") - def isPropertyArg(s: String) = lookupSetting(s.substring(0, 2)) match { + def isPropertyArg(s: String) = lookupSetting(s take 2) match { case Some(x: DefinesSetting) => true case _ => false } def parsePropertyArg(s: String): Option[List[String]] = { - val (p, args) = (s.substring(0, 2), s.substring(2)) + val (p, args) = (s take 2, s drop 2) tryToSetIfExists(p, List(args), (s: Setting) => s.tryToSetProperty _) } @@ -258,8 +240,8 @@ class Settings(errorFn: String => Unit) extends ScalacSettings { lazy val ChoiceSetting = untupled((choice _).tupled andThen add[ChoiceSetting]) lazy val DebugSetting = untupled((sdebug _).tupled andThen add[DebugSetting]) lazy val PhasesSetting = untupled((phase _).tupled andThen add[PhasesSetting]) - lazy val DefinesSetting = add(defines()) lazy val OutputSetting = untupled((output _).tupled andThen add[OutputSetting]) + lazy val DefinesSetting = () => add(new DefinesSetting()) override def toString() = "Settings(\n%s)" format (userSetSettings map (" " + _ + "\n") mkString) @@ -408,8 +390,6 @@ object Settings { def phase(name: String, descr: String) = new PhasesSetting(name, descr) - def defines() = new DefinesSetting() - def output(outputDirs: OutputDirs, default: String) = new OutputSetting(outputDirs, default) } @@ -653,7 +633,7 @@ object Settings { extends Setting(descr + choices.mkString(" (", ",", ")")) { type T = String protected var v: String = default - protected def argument: String = name.substring(1) + protected def argument: String = name drop 1 def tryToSet(args: List[String]) = { value = default ; Some(args) } override def tryToSetColon(args: List[String]) = args match { @@ -747,12 +727,10 @@ object Settings { // given foo=bar returns Some(foo, bar), or None if parse fails def parseArg(s: String): Option[(String, String)] = { if (s == "") return None - val regexp = """^(.*)?=(.*)$""".r + val idx = s indexOf '=' - regexp.findAllIn(s).matchData.toList match { - case Nil => Some(s, "") - case List(md) => md.subgroups match { case List(a,b) => Some(a,b) } - } + if (idx < 0) Some(s, "") + else Some(s take idx, s drop (idx + 1)) } private[Settings] override def tryToSetProperty(args: List[String]): Option[List[String]] = @@ -815,12 +793,14 @@ trait ScalacSettings { */ val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", "") - val classpath = StringSetting ("-classpath", "path", "Specify where to find user class files", "") . - withAbbreviation("-cp") . - withPostSetHook(self => if (Ylogcp.value) Console.println("Updated classpath to '%s'".format(self.value))) + val classpath = StringSetting ("-classpath", "path", "Specify where to find user class files", "") withAbbreviation ("-cp") val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", "") val javabootclasspath = StringSetting ("-javabootclasspath", "path", "Override java boot classpath.", "") + val javabootAppend = StringSetting ("-javabootclasspath/a", "path", "Append to java boot classpath", "") + val javabootPrepend = StringSetting ("-javabootclasspath/p", "path", "Prepend to java boot classpath", "") val javaextdirs = StringSetting ("-javaextdirs", "path", "Override java extdirs classpath.", "") + + val outdir = OutputSetting (outputDirs, ".") val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "") val Ycodebase = StringSetting ("-Ycodebase", "codebase", "Specify the URL containing the Scala libraries", "") val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.") @@ -830,7 +810,7 @@ trait ScalacSettings { */ // argfiles is only for the help message val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)") - val outdir = OutputSetting (outputDirs, ".") + val defines = DefinesSetting() val dependenciesFile = StringSetting ("-dependencyfile", "file", "Specify the file in which dependencies are tracked", ".scala_dependencies") val deprecation = BooleanSetting ("-deprecation", "Output source locations where deprecated APIs are used") val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", Properties.sourceEncoding) diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index b6dd06f83f..88651220f6 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -14,17 +14,7 @@ import scala.tools.util.PathResolver trait JavaPlatform extends Platform[AbstractFile] { import global._ - lazy val classPath: JavaClassPath = { - val context = - if (isInlinerOn) new JavaContext - else DefaultJavaContext - - val cp = PathResolver.fromSettings(settings, context) - if (settings.Ylogcp.value) - Console.println("Created Global has classpath: " + cp.asClasspathString) - - cp - } + lazy val classPath = new PathResolver(settings).result def rootLoader = new loaders.JavaPackageLoader(classPath) diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala index 65a6da7c07..b62de995c2 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala @@ -53,7 +53,7 @@ import Completion._ class Completion(repl: Interpreter) { self => - private lazy val classPath = PathResolver.fromSettings(repl.settings).asURLs + private lazy val classPath = repl.compilerClasspath // the unqualified vals/defs/etc visible in the repl val ids = new IdentCompletion(repl) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 013cd89a44..0e9c4f27fa 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -213,6 +213,13 @@ abstract class ClassPath[T] { case Some(ClassRep(Some(x: AbstractFile), _)) => Some(x) case _ => None } + + def sortString = asURLs map (_.toString) sorted + override def equals(that: Any) = that match { + case x: ClassPath[_] => this.sortString == x.sortString + case _ => false + } + override def hashCode = sortString.hashCode } /** @@ -311,6 +318,10 @@ extends ClassPath[T] { case x: DirectoryClassPath => x.dir.path case x: MergedClassPath[_] => x.asClasspathString }) + def show { + println("ClassPath %s has %d entries and results in:\n".format(name, entries.size)) + asClasspathString split ':' foreach (x => println(" " + x)) + } override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")") } diff --git a/src/compiler/scala/tools/util/ClassPathSettings.scala b/src/compiler/scala/tools/util/ClassPathSettings.scala new file mode 100644 index 0000000000..49c01d19df --- /dev/null +++ b/src/compiler/scala/tools/util/ClassPathSettings.scala @@ -0,0 +1,37 @@ +/* NSC -- new Scala compiler + * Copyright 2006-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package util + +trait ClassPathSettings { + def javabootclasspath: String // -javabootclasspath + def javabootPrepend: String // -javabootclasspath/p + def javabootAppend: String // -javabootclasspath/a + def javaextdirs: String // -javaextdirs + + def bootclasspath: String // -bootclasspath + def extdirs: String // -extdirs + def classpath: String // -classpath + def sourcepath: String // -sourcepath + + def codebase: String // -Ycodebase +} + +// 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 +// } + 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 } diff --git a/src/compiler/scala/tools/util/StringOps.scala b/src/compiler/scala/tools/util/StringOps.scala index 77fc6f8700..b98ab38d89 100644 --- a/src/compiler/scala/tools/util/StringOps.scala +++ b/src/compiler/scala/tools/util/StringOps.scala @@ -11,13 +11,75 @@ package scala.tools package util -/** This objects provides methods to extract elements from - * a string according to some defined character separator. +/** This object provides utility methods to extract elements + * from Strings. * * @author Martin Odersky * @version 1.0 */ object StringOps { + /** + * 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 + } def decompose(str: String, sep: Char): List[String] = { def ws(start: Int): List[String] = |