From 730720552b80eacd2581f860fbd861098e54fa7e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 14 Feb 2010 01:00:37 +0000 Subject: Reducing the amount of low-level classpath mani... Reducing the amount of low-level classpath manipulation going on around town. No review. --- src/compiler/scala/tools/nsc/CompileClient.scala | 9 +++---- src/compiler/scala/tools/nsc/Interpreter.scala | 2 +- .../scala/tools/nsc/MainGenericRunner.scala | 1 - src/compiler/scala/tools/nsc/Settings.scala | 25 +++++++++++-------- .../scala/tools/nsc/backend/JavaPlatform.scala | 6 ++++- src/compiler/scala/tools/nsc/util/ClassPath.scala | 28 +++++++++++++++------ src/compiler/scala/tools/util/PathResolver.scala | 29 ++++++++++------------ .../scala/tools/partest/nest/CompileManager.scala | 6 +++-- .../tools/partest/nest/ReflectiveRunner.scala | 5 ++-- 9 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index 71f7ea811e..00e3d4d37f 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -6,8 +6,9 @@ package scala.tools.nsc -import java.io.{BufferedReader, File, InputStreamReader, PrintWriter} +import java.io.{ BufferedReader, File, InputStreamReader, PrintWriter } import Properties.fileEndings +import util.ClassPath /** The client part of the fsc offline compiler. Instead of compiling * things itself, it send requests to a CompileServer. @@ -26,11 +27,7 @@ class StandardCompileClient { /** Convert a sequence of filenames, separated by File.pathSeparator, * into absolute filenames. */ - def absFileNames(paths: String) = { - val sep = File.pathSeparator - val pathsList = paths.split(sep).toList - pathsList map absFileName mkString sep - } + def absFileNames(paths: String) = ClassPath.map(paths, absFileName) protected def normalize(args: Array[String]): (String, String) = { var i = 0 diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 9dfc7d2a5d..dc2f9082d4 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -171,7 +171,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { val classpathPart = ClassPath.expandPath(settings.classpath.value) map (s => new File(s).toURI.toURL) val codebasePart = - (settings.Xcodebase.value split " ").toList flatMap parseURL + (settings.Ycodebase.value split " ").toList flatMap parseURL classpathPart ::: codebasePart } diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index 80af84e857..f2871b1646 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -15,7 +15,6 @@ import scala.tools.util.PathResolver import io.{ File } import util.{ ClassPath, ScalaClassLoader } -import File.pathSeparator import Properties.{ versionString, copyrightString } /** An object that runs Scala code. It has three possible diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index e5fd9299eb..b773da38b3 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -776,21 +776,31 @@ trait ScalacSettings { Console.println("Updated classpath from '%s' to '%s'".format(oldClasspath, classpath.value)) } + /** + * Classpath related settings + */ + + 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 extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", "") + val javabootclasspath = StringSetting ("-javabootclasspath", "path", "Override java boot classpath.", "") + val javaextdirs = StringSetting ("-javaextdirs", "path", "Override java extdirs classpath.", "") + 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.") + /** * Standard settings */ // argfiles is only for the help message val argfiles = BooleanSetting ("@", "A text file containing compiler arguments (options and source files)") - 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 outdir = OutputSetting (outputDirs, ".") 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) val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail") - val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", "") val debuginfo = DebugSetting ("-g", "Specify level of generated debugging info", List("none", "source", "line", "vars", "notailcalls"), "vars", "vars") val help = BooleanSetting ("-help", "Print a synopsis of standard options") val make = ChoiceSetting ("-make", "Specify recompilation detection strategy", List("all", "changed", "immediate", "transitive", "transitivenocp"), "all") . @@ -799,7 +809,6 @@ trait ScalacSettings { val XO = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program").withAbbreviation("-optimize") . withPostSetHook(_ => List(inline, Xcloselim, Xdce) foreach (_.value = true)) val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed") - val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "") val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "msil"), "jvm-1.5") val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked warnings") val uniqid = BooleanSetting ("-uniqid", "Print identifiers with unique names for debugging") @@ -807,8 +816,6 @@ trait ScalacSettings { val version = BooleanSetting ("-version", "Print product version and exit") /** New to classpaths */ - val javabootclasspath = StringSetting ("-javabootclasspath", "path", "Override java boot classpath.", "") - val javaextdirs = StringSetting ("-javaextdirs", "path", "Override java extdirs classpath.", "") /** * -X "Advanced" settings @@ -853,7 +860,6 @@ trait ScalacSettings { val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after") val check = PhasesSetting ("-Ycheck", "Check the tree at the end of") val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination") - val Xcodebase = StringSetting ("-Ycodebase", "codebase", "Specify the URL containing the Scala libraries", "") val Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees") val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL") val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination") @@ -891,7 +897,6 @@ trait ScalacSettings { val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible..") val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.") val Yjenkins = BooleanSetting ("-Yjenkins-hashCodes", "Use jenkins hash algorithm for case class generated hashCodes.") - val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.") // Warnings val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics") diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index a62b8e5e58..b6dd06f83f 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -19,7 +19,11 @@ trait JavaPlatform extends Platform[AbstractFile] { if (isInlinerOn) new JavaContext else DefaultJavaContext - PathResolver.fromSettings(settings, context) + val cp = PathResolver.fromSettings(settings, context) + if (settings.Ylogcp.value) + Console.println("Created Global has classpath: " + cp.asClasspathString) + + cp } def rootLoader = new loaders.JavaPackageLoader(classPath) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index c0c1f7a417..25b5b83a23 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -15,6 +15,7 @@ import scala.collection.mutable.{ListBuffer, ArrayBuffer, HashSet => MutHashSet} import io.{ File, Directory, Path, AbstractFile } import scala.tools.util.StringOps.splitWhere import Path.isJarOrZip +import File.pathSeparator /**

* This module provides star expansion of '-classpath' option arguments, behaves the same as @@ -45,14 +46,19 @@ object ClassPath { else List(pattern) } - /** Split path using platform-dependent path separator */ - private def splitPath(path: String): List[String] = - path split File.pathSeparator toList + /** Split classpath using platform-dependent path separator */ + def split(path: String): List[String] = path split pathSeparator filterNot (_ == "") toList + + /** Join classpath using platform-dependent path separator */ + def join(path: Seq[String]): String = path filterNot (_ == "") mkString pathSeparator + + /** Split the classpath, apply a transformation function, and reassemble it. */ + def map(cp: String, f: String => String): String = join(split(cp) map f) /** Expand path and possibly expanding stars */ def expandPath(path: String, expandStar: Boolean = true): List[String] = - if (expandStar) splitPath(path) flatMap expandS - else splitPath(path) + if (expandStar) split(path) flatMap expandS + else split(path) /** Expand dir out to contents, a la extdir */ def expandDir(extdir: String): List[String] = { @@ -228,7 +234,7 @@ 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 ClassPath[AbstractFile] { +class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] { def name = dir.name def asURLs = List(dir.sfile.toURL) val sourcepaths: List[AbstractFile] = Nil @@ -297,6 +303,11 @@ extends ClassPath[T] { new MergedClassPath[T](newEntries, context) } + def asClasspathString: String = ClassPath.join(entries partialMap { + case x: DirectoryClassPath => x.dir.path + case x: MergedClassPath[_] => x.asClasspathString + }) + override def toString() = "merged classpath "+ entries.mkString("(", "\n", ")") } @@ -305,6 +316,7 @@ extends ClassPath[T] { * as AbstractFile. nsc.io.ZipArchive is used to view zip/jar archives as directories. */ class JavaClassPath( - containers: List[List[ClassPath[AbstractFile]]], + containers: List[ClassPath[AbstractFile]], context: JavaContext) -extends MergedClassPath[AbstractFile](containers.flatten, context) { } +extends MergedClassPath[AbstractFile](containers, context) { +} diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index a7ccc0f240..658ca48d0e 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -10,8 +10,7 @@ import java.net.{ URL, MalformedURLException } import nsc.{ Settings } import nsc.util.{ ClassPath, JavaClassPath, ScalaClassLoader } import nsc.io.{ File, Directory, Path } -import ClassPath.{ JavaContext, DefaultJavaContext } -import File.{ pathSeparator } +import ClassPath.{ JavaContext, DefaultJavaContext, join, split } import PartialFunction.condOpt // Mostly based on the specification at: @@ -24,13 +23,11 @@ object PathResolver { private def fileOpt(f: Path): Option[String] = f ifFile (_.path) private def dirOpt(d: Path): Option[String] = d ifDirectory (_.path) - private def expandToPath(p: Path) = joincp(ClassPath.expandPath(p.path, true)) - private def expandToContents(p: Path) = joincp(ClassPath.expandDir(p.path)) - private def joincp(xs: Seq[String]): String = xs filterNot (_ == "") mkString pathSeparator - private def splitcp(cp: String): Seq[String] = cp split pathSeparator filterNot (_ == "") toSeq + private def expandToPath(p: Path) = join(ClassPath.expandPath(p.path, true)) + private def expandToContents(p: Path) = join(ClassPath.expandDir(p.path)) /** pretty print class path */ - def ppcp(s: String) = splitcp(s) match { + def ppcp(s: String) = split(s) match { case Nil => "" case Seq(x) => x case xs => xs map ("\n" + _) mkString @@ -104,7 +101,7 @@ object PathResolver { } def scalaPluginDirs = List("misc", "scala-devel", "plugins") - def scalaPluginPath = joincp(scalaPluginDirs map (scalaHomeDir / _ path)) + 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. @@ -134,7 +131,7 @@ object PathResolver { ) } - def executionPath = joincp(Defaults.executionPath) + def executionPath = join(Defaults.executionPath) /** The original logic of MainGenericRunner. */ @@ -160,18 +157,18 @@ object PathResolver { contentsOfDirsInPath(javaExtDirs), // -javaextdirs multiple dirs, each expands to contents contentsOfDirsInPath(scalaExtDirs), // -extdirs ??? classesInExpandedPath(classPath), // -classpath multiple entries, first expanding *s - classesAtAllURLS(codeBase), // -Xcodebase ??? multiple URLs + 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 + sources.flatten } def urlsFromSettings(settings: Settings): List[URL] = urlsFromSettings(settings, DefaultJavaContext) def urlsFromSettings(settings: Settings, context: JavaContext): List[URL] = - classPathContainersFromSettings(settings, context).flatten flatMap (_.asURLs) + classPathContainersFromSettings(settings, context) flatMap (_.asURLs) private def contextFromSettings(s: Settings) = if (s.inline.value) new JavaContext else DefaultJavaContext @@ -195,7 +192,7 @@ object PathResolver { def fromPathString(path: String): JavaClassPath = fromPathString(path, DefaultJavaContext) def fromPathString(path: String, context: JavaContext): JavaClassPath = - new JavaClassPath(List(context.classesInExpandedPath(path)), context) + new JavaClassPath(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 @@ -279,7 +276,7 @@ object PathResolver { } else Nil } } -import PathResolver.{ Defaults, Environment, joincp, splitcp, ppcp } +import PathResolver.{ Defaults, Environment, ppcp } class PathResolver(settings: Settings) { private def cmdLineOrElse(name: String, alt: String) = { @@ -296,7 +293,7 @@ class PathResolver(settings: Settings) { case "extdirs" => settings.extdirs.value case "classpath" | "cp" => settings.classpath.value case "sourcepath" => settings.sourcepath.value - case "Ycodebase" => settings.Xcodebase.value + case "Ycodebase" => settings.Ycodebase.value } /** Calculated values based on any given command line options, falling back on @@ -347,5 +344,5 @@ class PathResolver(settings: Settings) { ) } - def referencePath = joincp(Calculated.referencePath) + def referencePath = join(Calculated.referencePath) } diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 8d440b398f..ecf8b07b8e 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -10,6 +10,7 @@ package nest import scala.tools.nsc.{Global, Settings, CompilerCommand, FatalError} import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} +import scala.tools.nsc.util.ClassPath import scala.tools.util.PathResolver import java.io.{File, BufferedReader, PrintWriter, FileReader, FileWriter, StringWriter} @@ -27,8 +28,9 @@ abstract class SimpleCompiler { } class TestSettings(fileMan: FileManager) extends Settings(x => ()) { - javabootclasspath.value = - PathResolver.Environment.javaBootClassPath + (pathSeparator + fileMan.LATEST_LIB) + javabootclasspath.value = ClassPath.join( + List(PathResolver.Environment.javaBootClassPath, fileMan.LATEST_LIB) + ) } class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index bcedaa38be..2ae67db566 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -8,6 +8,8 @@ package scala.tools.partest package nest +import scala.tools.nsc.util.ClassPath + /* This class is used to load an instance of DirectRunner using * a custom class loader. * The purpose is to "auto-detect" a good classpath for the @@ -21,7 +23,6 @@ class ReflectiveRunner extends RunnerUtils { // was used to start the runner. import java.net.URLClassLoader - import java.io.File.pathSeparator import utils.Properties.{ sysprop, syspropset } val sepRunnerClassName = "scala.tools.partest.nest.ConsoleRunner" @@ -54,7 +55,7 @@ class ReflectiveRunner extends RunnerUtils { println("Loading classes from:\n" + sepUrls.mkString("\n")) val paths = (if (classPath.isEmpty) files.slice(0, 4) else files) map { _.getPath } - val newClasspath = paths mkString pathSeparator + val newClasspath = ClassPath join paths syspropset("java.class.path", newClasspath) syspropset("scala.home", "") -- cgit v1.2.3