Skip to content

Commit

Permalink
Merge pull request #2238 from adriaanm/pr-2206-rebased
Browse files Browse the repository at this point in the history
[rebase of #2206] l JSR-223 compliance for the interpreter
  • Loading branch information
adriaanm committed Mar 12, 2013
2 parents a41c79b + 3a30af1 commit 5262cd5
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 44 deletions.
2 changes: 2 additions & 0 deletions build.xml
Expand Up @@ -1511,9 +1511,11 @@ PACKED QUICK BUILD (PACK)
<copy file="META-INF/MANIFEST.MF" toDir="${build-pack.dir}/META-INF"/>
<manifest file="${build-pack.dir}/META-INF/MANIFEST.MF" mode="update">
<attribute name="Bundle-Version" value="${version.number}"/>
<attribute name="Class-Path" value="scala-reflect.jar scala-library.jar"/>
</manifest>
<mkdir dir="${build-pack.dir}/lib"/>
<jar destfile="${build-pack.dir}/lib/scala-compiler.jar" manifest="${build-pack.dir}/META-INF/MANIFEST.MF">
<service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.IMain$Factory"/>
<fileset dir="${build-quick.dir}/classes/compiler"/>
<fileset dir="${build-quick.dir}/classes/scaladoc"/>
<fileset dir="${build-quick.dir}/classes/interactive"/>
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Expand Up @@ -248,11 +248,11 @@ class MutableSettings(val errorFn: String => Unit)
private def checkDir(dir: AbstractFile, name: String, allowJar: Boolean = false): AbstractFile = (
if (dir != null && dir.isDirectory)
dir
// was: else if (allowJar && dir == null && Path.isJarOrZip(name, false))
else if (allowJar && dir == null && Jar.isJarOrZip(name, examineFile = false))
new PlainFile(Path(name))
else
throw new FatalError(name + " does not exist or is not a directory")
// throw new FatalError(name + " does not exist or is not a directory")
dir
)

/** Set the single output directory. From now on, all files will
Expand Down
Expand Up @@ -45,6 +45,7 @@ trait StandardScalaSettings {
val unchecked = BooleanSetting ("-unchecked", "Enable additional warnings where generated code depends on assumptions.")
val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.")
val usemanifestcp = BooleanSetting ("-usemanifestcp", "Utilize the manifest in classpath resolution.")
val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing.")
val version = BooleanSetting ("-version", "Print product version and exit.")
}
15 changes: 14 additions & 1 deletion src/compiler/scala/tools/nsc/util/AbstractFileClassLoader.scala
Expand Up @@ -6,6 +6,9 @@ package scala.tools.nsc
package util

import scala.tools.nsc.io.AbstractFile
import java.security.cert.Certificate
import java.security.{ ProtectionDomain, CodeSource }
import util.ScalaClassLoader
import java.net.{ URL, URLConnection, URLStreamHandler }
import scala.collection.{ mutable, immutable }

Expand Down Expand Up @@ -82,7 +85,17 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
if (bytes.length == 0)
throw new ClassNotFoundException(name)
else
defineClass(name, bytes, 0, bytes.length)
defineClass(name, bytes, 0, bytes.length, protectionDomain)
}

lazy val protectionDomain = {
val cl = Thread.currentThread().getContextClassLoader()
val resource = cl.getResource("scala/runtime/package.class")
if (resource == null) null else {
val s = resource.getPath
val path = s.substring(0, s.lastIndexOf('!'))
new ProtectionDomain(new CodeSource(new URL(path), null.asInstanceOf[Array[Certificate]]), null, this, null)
}
}

private val packages = mutable.Map[String, Package]()
Expand Down
8 changes: 7 additions & 1 deletion src/compiler/scala/tools/nsc/util/ClassPath.scala
Expand Up @@ -13,6 +13,7 @@ import io.{ File, Directory, Path, Jar, AbstractFile }
import scala.reflect.internal.util.StringOps.splitWhere
import Jar.isJarOrZip
import File.pathSeparator
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator
import java.net.MalformedURLException
import java.util.regex.PatternSyntaxException

Expand Down Expand Up @@ -121,8 +122,13 @@ object ClassPath {
private def classesInPathImpl(path: String, expand: Boolean) =
for (file <- expandPath(path, expand) ; dir <- Option(AbstractFile getDirectory file)) yield
newClassPath(dir)

def classesInManifest(used: Boolean) =
if (used) for (url <- manifests) yield newClassPath(AbstractFile getResources url) else Nil
}

def manifests = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF").filter(_.getProtocol() == "jar").toList

class JavaContext extends ClassPathContext[AbstractFile] {
def toBinaryName(rep: AbstractFile) = {
val name = rep.name
Expand Down Expand Up @@ -267,7 +273,7 @@ class SourcePath[T](dir: AbstractFile, val context: ClassPathContext[T]) extends
class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[AbstractFile]) extends ClassPath[AbstractFile] {
def name = dir.name
override def origin = dir.underlyingSource map (_.path)
def asURLs = if (dir.file == null) Nil else List(dir.toURL)
def asURLs = if (dir.file == null) List(new URL(name)) else List(dir.toURL)
def asClasspathString = dir.path
val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()

Expand Down
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/util/PathResolver.scala
Expand Up @@ -170,6 +170,7 @@ class PathResolver(settings: Settings, context: JavaContext) {
object Calculated {
def scalaHome = Defaults.scalaHome
def useJavaClassPath = settings.usejavacp.value || Defaults.useJavaClassPath
def useManifestClassPath= settings.usemanifestcp.value
def javaBootClassPath = cmdLineOrElse("javabootclasspath", Defaults.javaBootClassPath)
def javaExtDirs = cmdLineOrElse("javaextdirs", Defaults.javaExtDirs)
def javaUserClassPath = if (useJavaClassPath) Defaults.javaUserClassPath else ""
Expand Down Expand Up @@ -209,6 +210,7 @@ class PathResolver(settings: Settings, context: JavaContext) {
classesInPath(scalaBootClassPath), // 4. The Scala boot class path.
contentsOfDirsInPath(scalaExtDirs), // 5. The Scala extension class path.
classesInExpandedPath(userClassPath), // 6. The Scala application class path.
classesInManifest(useManifestClassPath), // 8. The Manifest class path.
sourcesInPath(sourcePath) // 7. The Scala source path.
)

Expand Down
34 changes: 24 additions & 10 deletions src/reflect/scala/reflect/io/AbstractFile.scala
Expand Up @@ -7,7 +7,7 @@
package scala.reflect
package io

import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream }
import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream, ByteArrayOutputStream }
import java.io.{ File => JFile }
import java.net.URL
import scala.collection.mutable.ArrayBuffer
Expand Down Expand Up @@ -54,6 +54,8 @@ object AbstractFile {
if (url == null || !Path.isExtensionJarOrZip(url.getPath)) null
else ZipArchive fromURL url
}

def getResources(url: URL): AbstractFile = ZipArchive fromManifestURL url
}

/**
Expand Down Expand Up @@ -156,16 +158,28 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
@throws(classOf[IOException])
def toByteArray: Array[Byte] = {
val in = input
var rest = sizeOption.getOrElse(0)
val arr = new Array[Byte](rest)
while (rest > 0) {
val res = in.read(arr, arr.length - rest, rest)
if (res == -1)
throw new IOException("read error")
rest -= res
sizeOption match {
case Some(size) =>
var rest = size
val arr = new Array[Byte](rest)
while (rest > 0) {
val res = in.read(arr, arr.length - rest, rest)
if (res == -1)
throw new IOException("read error")
rest -= res
}
in.close()
arr
case None =>
val out = new ByteArrayOutputStream()
var c = in.read()
while(c != -1) {
out.write(c)
c = in.read()
}
in.close()
out.toByteArray()
}
in.close()
arr
}

/** Returns all abstract subfiles of this abstract directory. */
Expand Down
9 changes: 5 additions & 4 deletions src/reflect/scala/reflect/io/Path.scala
Expand Up @@ -56,10 +56,11 @@ object Path {
def roots: List[Path] = java.io.File.listRoots().toList map Path.apply

def apply(path: String): Path = apply(new JFile(path))
def apply(jfile: JFile): Path =
def apply(jfile: JFile): Path = try {
if (jfile.isFile) new File(jfile)
else if (jfile.isDirectory) new Directory(jfile)
else new Path(jfile)
} catch { case ex: SecurityException => new Path(jfile) }

/** Avoiding any shell/path issues by only using alphanumerics. */
private[io] def randomPrefix = alphanumeric take 6 mkString ""
Expand Down Expand Up @@ -186,10 +187,10 @@ class Path private[io] (val jfile: JFile) {
// Boolean tests
def canRead = jfile.canRead()
def canWrite = jfile.canWrite()
def exists = jfile.exists()
def exists = try jfile.exists() catch { case ex: SecurityException => false }

def isFile = jfile.isFile()
def isDirectory = jfile.isDirectory()
def isFile = try jfile.isFile() catch { case ex: SecurityException => false }
def isDirectory = try jfile.isDirectory() catch { case ex: SecurityException => false }
def isAbsolute = jfile.isAbsolute()
def isEmpty = path.length == 0

Expand Down
62 changes: 61 additions & 1 deletion src/reflect/scala/reflect/io/ZipArchive.scala
Expand Up @@ -7,10 +7,12 @@ package scala.reflect
package io

import java.net.URL
import java.io.{ IOException, InputStream, ByteArrayInputStream }
import java.io.{ IOException, InputStream, ByteArrayInputStream, FilterInputStream }
import java.io.{ File => JFile }
import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
import java.util.jar.Manifest
import scala.collection.{ immutable, mutable }
import scala.collection.convert.WrapAsScala.asScalaIterator
import scala.annotation.tailrec

/** An abstraction for zip files and streams. Everything is written the way
Expand Down Expand Up @@ -39,6 +41,8 @@ object ZipArchive {
*/
def fromURL(url: URL): URLZipArchive = new URLZipArchive(url)

def fromManifestURL(url: URL): AbstractFile = new ManifestResources(url)

private def dirName(path: String) = splitPath(path, front = true)
private def baseName(path: String) = splitPath(path, front = false)
private def splitPath(path0: String, front: Boolean): String = {
Expand Down Expand Up @@ -227,3 +231,59 @@ final class URLZipArchive(val url: URL) extends ZipArchive(null) {
case _ => false
}
}

final class ManifestResources(val url: URL) extends ZipArchive(null) {
def iterator = {
val root = new DirEntry("/")
val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
val manifest = new Manifest(input)
val iter = manifest.getEntries().keySet().iterator().filter(_.endsWith(".class")).map(new ZipEntry(_))

while (iter.hasNext) {
val zipEntry = iter.next()
val dir = getDir(dirs, zipEntry)
if (zipEntry.isDirectory) dir
else {
class FileEntry() extends Entry(zipEntry.getName) {
override def lastModified = zipEntry.getTime()
override def input = resourceInputStream(path)
override def sizeOption = None
}
val f = new FileEntry()
dir.entries(f.name) = f
}
}

try root.iterator
finally dirs.clear()
}

def name = path
def path: String = url.getPath() match { case s => s.substring(0, s.lastIndexOf('!')) }
def input = url.openStream()
def lastModified =
try url.openConnection().getLastModified()
catch { case _: IOException => 0 }

override def canEqual(other: Any) = other.isInstanceOf[ManifestResources]
override def hashCode() = url.hashCode
override def equals(that: Any) = that match {
case x: ManifestResources => url == x.url
case _ => false
}

private def resourceInputStream(path: String): InputStream = {
new FilterInputStream(null) {
override def read(): Int = {
if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
if(in == null) throw new RuntimeException(path + " not found")
super.read();
}

override def close(): Unit = {
super.close();
in = null;
}
}
}
}

0 comments on commit 5262cd5

Please sign in to comment.