From 3e5cd92cbb455f046f70552f1dd127404b32f4b2 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 26 Mar 2011 19:42:25 +0000 Subject: Some accumulated work and polish on classpath a... Some accumulated work and polish on classpath and jars. No review. --- .../scala/tools/nsc/io/ClassAndJarInfo.scala | 39 ++++++++++++++++++++ src/compiler/scala/tools/nsc/io/Jar.scala | 41 ++++++++++++++-------- src/compiler/scala/tools/nsc/io/Sources.scala | 26 ++++---------- .../tools/nsc/settings/AestheticSettings.scala | 2 +- .../scala/tools/nsc/settings/ScalaSettings.scala | 4 ++- src/compiler/scala/tools/nsc/util/ClassPath.scala | 12 +++++-- 6 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/io/ClassAndJarInfo.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/io/ClassAndJarInfo.scala b/src/compiler/scala/tools/nsc/io/ClassAndJarInfo.scala new file mode 100644 index 0000000000..88efe1e0b5 --- /dev/null +++ b/src/compiler/scala/tools/nsc/io/ClassAndJarInfo.scala @@ -0,0 +1,39 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package io + +import java.net.URL +import collection.JavaConverters._ + +/** A convenience class for finding the jar with the bytecode for + * a given Class object and similar common tasks. + */ +class ClassAndJarInfo[T: ClassManifest] { + val man = classManifest[T] + def clazz = man.erasure + + def baseOfPath(path: String) = path indexOf '!' match { + case -1 => path stripSuffix internalClassName + case idx => path take idx + } + + def classUrl = clazz getResource simpleClassName + ".class" + def codeSource = protectionDomain.getCodeSource() + def internalClassName = internalName + ".class" + def internalName = clazz.getName.replace('.', '/') + def jarManifest = new JManifest(jarManifestUrl.openStream()) + def jarManifestMainAttrs = jarManifest.getMainAttributes().asScala + def jarManifestUrl = new URL(baseOfPath("" + classUrl) + "!/META-INF/MANIFEST.MF") + def locationFile = File(locationUrl.toURI.getPath()) + def locationUrl = if (codeSource == null) new URL("file:///") else codeSource.getLocation() + def protectionDomain = clazz.getProtectionDomain() + def rootClasspath = rootPossibles find (_.exists) + def rootFromLocation = Path(locationUrl.toURI.getPath()) + def rootFromResource = Path(baseOfPath(classUrl.getPath) stripPrefix "file:") + def rootPossibles = Iterator(rootFromResource, rootFromLocation) + def simpleClassName = clazz.getName split """[$.]""" last +} diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index a9f0acaa00..bd7dbde5ec 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -1,3 +1,8 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + package scala.tools.nsc package io @@ -5,6 +10,27 @@ import java.io.{ InputStream, OutputStream, IOException, FileNotFoundException, import java.util.jar._ import collection.JavaConverters._ import Attributes.Name +import util.ClassPath + +// Attributes.Name instances: +// +// static Attributes.Name CLASS_PATH +// static Attributes.Name CONTENT_TYPE +// static Attributes.Name EXTENSION_INSTALLATION +// static Attributes.Name EXTENSION_LIST +// static Attributes.Name EXTENSION_NAME +// static Attributes.Name IMPLEMENTATION_TITLE +// static Attributes.Name IMPLEMENTATION_URL +// static Attributes.Name IMPLEMENTATION_VENDOR +// static Attributes.Name IMPLEMENTATION_VENDOR_ID +// static Attributes.Name IMPLEMENTATION_VERSION +// static Attributes.Name MAIN_CLASS +// static Attributes.Name MANIFEST_VERSION +// static Attributes.Name SEALED +// static Attributes.Name SIGNATURE_VERSION +// static Attributes.Name SPECIFICATION_TITLE +// static Attributes.Name SPECIFICATION_VENDOR +// static Attributes.Name SPECIFICATION_VERSION class Jar(file: File) extends Iterable[JarEntry] { def this(path: String) = this(File(path)) @@ -74,21 +100,6 @@ object Jar { def isJarOrZip(f: Path, examineFile: Boolean): Boolean = f.hasExtension("zip", "jar") || (examineFile && magicNumberIsZip(f)) - def locateByClass(clazz: Class[_]): Option[File] = { - try Some(File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())) - catch { case _: Exception => None } - } - /** Walks upward from wherever the scala library jar is searching for - * the given jar name. This approach finds the scala library jar in the - * release layout and in trunk builds going up from pack. - */ - def locateByName(name: String): Option[File] = { - def toSrc(d: Directory) = d.dirs.toList map (_ / name) - def walk(d: Directory) = d.parents flatMap toSrc find (_.isFile) map (_.toFile) - - locateByClass(classOf[ScalaObject]) flatMap (x => walk(x.parent)) - } - def create(file: File, sourceDir: Directory, mainClass: String): File = { val writer = new Jar(file).jarWriter() writer.manifest(Name.MANIFEST_VERSION) = "1.0" diff --git a/src/compiler/scala/tools/nsc/io/Sources.scala b/src/compiler/scala/tools/nsc/io/Sources.scala index c763b04511..35c7a504a5 100644 --- a/src/compiler/scala/tools/nsc/io/Sources.scala +++ b/src/compiler/scala/tools/nsc/io/Sources.scala @@ -4,7 +4,6 @@ package io import util.ClassPath import java.util.concurrent.{ Future, ConcurrentHashMap, ExecutionException } import java.util.zip.ZipException -import Jar.{ isJarOrZip, locateByClass } import collection.JavaConverters._ import Properties.{ envOrElse, propOrElse } @@ -20,7 +19,7 @@ class Sources(val path: String) { private val partitioned = ClassPath toPaths expandedPath partition (_.isDirectory) val dirs = partitioned._1 map (_.toDirectory) - val jars = partitioned._2 filter isJarOrZip map (_.toFile) + val jars = partitioned._2 filter Jar.isJarOrZip map (_.toFile) val (isDone, force) = { val f1 = spawn(calculateDirs()) val f2 = spawn(calculateJars()) @@ -63,25 +62,12 @@ trait LowPrioritySourcesImplicits { } object Sources extends LowPrioritySourcesImplicits { - // Examples of what libraryJar might be, each of which we'd like to find - // the source files automatically: - // - // /scala/trunk/build/pack/lib/scala-library.jar - // /scala/trunk/build/quick/classes/library - // /scala/inst/scala-2.9.0.r24213-b20110206233447/lib/scala-library.jar - private def libraryJar = locateByClass(classOf[ScalaObject]) map (_.toAbsolute.path) - private def autoSourcePaths: List[String] = libraryJar.toList flatMap { lib => - val markers = List("build/pack/lib", "build/quick/classes", "scala-library.jar") - markers filter (lib contains _) flatMap { m => - val dir = Path(lib take lib.indexOf(m)) / "src" - - if (dir.exists) ClassPath.expandDir(dir.path) - else Nil - } - } + private def libraryInits = ClassPath.scalaLibrary.toList flatMap (_.toAbsolute.parents) + private def librarySourceDir = libraryInits map (_ / "src") find (_.isDirectory) + private def expandedSourceDir = librarySourceDir.toList flatMap (ClassPath expandDir _.path) - val sourcePathEnv = envOrElse("SOURCEPATH", "") - val defaultSources = apply(autoSourcePaths :+ sourcePathEnv: _*) + val sourcePathProp = sys.props.traceSourcePath.value + val defaultSources = apply(expandedSourceDir :+ sourcePathProp: _*) def apply(paths: String*): Sources = new Sources(ClassPath.join(paths: _*)) } diff --git a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala index d7bec764b3..0908ea60b6 100644 --- a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala @@ -25,7 +25,7 @@ trait AestheticSettings { def fatalWarnings = settings.Xwarnfatal.value def logClasspath = settings.Ylogcp.value def printStats = settings.Ystatistics.value - def richExes = settings.YrichExes.value + def richExes = settings.YrichExes.value || sys.props.traceSourcePath.isSet def target = settings.target.value def unchecked = settings.unchecked.value def verbose = settings.verbose.value diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 7405ca0b3d..14915da9ba 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -134,7 +134,9 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.") - val YrichExes = BooleanSetting ("-Yrich-exceptions", "More revealing exceptions. Set SOURCEPATH to java/scala source jars.") + val YrichExes = BooleanSetting ("-Yrich-exceptions", + "Fancier exceptions. Set source search path with -D" + + sys.SystemProperties.traceSourcePath.key) val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.") val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") val Ybuildmanagerdebug = diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index bb404480a9..962062eb2d 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -9,9 +9,9 @@ package util import java.net.URL import scala.collection.mutable.ListBuffer -import io.{ File, Directory, Path, AbstractFile } +import io.{ File, Directory, Path, Jar, AbstractFile, ClassAndJarInfo } import scala.tools.util.StringOps.splitWhere -import Path.isJarOrZip +import Jar.isJarOrZip import File.pathSeparator /**

@@ -22,6 +22,14 @@ import File.pathSeparator * @author Stepan Koltsov */ object ClassPath { + def scalaLibrary = locate[ScalaObject] + def scalaCompiler = locate[Global] + + def info[T: ClassManifest] = new ClassAndJarInfo[T] + def locate[T: ClassManifest] = info[T] rootClasspath + def locateJar[T: ClassManifest] = info[T].rootPossibles find (x => isJarOrZip(x)) map (x => File(x)) + def locateDir[T: ClassManifest] = info[T].rootPossibles find (_.isDirectory) map (_.toDirectory) + /** Expand single path entry */ private def expandS(pattern: String): List[String] = { val wildSuffix = File.separator + "*" -- cgit v1.2.3