summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala7
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala80
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala295
3 files changed, 169 insertions, 213 deletions
diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
index eaa3091eee..2e26c07d88 100644
--- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala
+++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
@@ -10,6 +10,7 @@ package io
import java.io.{File, FileOutputStream, IOException, InputStream, OutputStream}
import java.net.URL
+import scala.io.{ File => SFile }
import scala.collection.mutable.ArrayBuffer
@@ -17,8 +18,8 @@ import scala.collection.mutable.ArrayBuffer
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
-object AbstractFile {
-
+object AbstractFile
+{
/** Returns "getFile(new File(path))". */
def getFile(path: String): AbstractFile = getFile(new File(path))
@@ -46,7 +47,7 @@ object AbstractFile {
if (file.isFile() && file.exists()) {
val path = file.getPath()
if (path.endsWith(".jar") || path.endsWith(".zip"))
- return ZipArchive.fromFile(file);
+ return ZipArchive fromFile SFile(file)
}
null
}
diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala
index 0394a16a93..7e5e8576b1 100644
--- a/src/compiler/scala/tools/nsc/io/PlainFile.scala
+++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala
@@ -8,7 +8,9 @@
package scala.tools.nsc
package io
-import java.io.{File, FileInputStream, FileOutputStream, IOException}
+import java.io.{ File => JFile, FileInputStream, FileOutputStream, IOException }
+import scala.io.{ File, Path }
+import PartialFunction._
object PlainFile
{
@@ -16,56 +18,46 @@ object PlainFile
* If the specified File exists, returns an abstract file backed
* by it. Otherwise, returns null.
*/
- def fromFile(file: File): PlainFile =
- if (file.exists()) new PlainFile(file) else null
-
- def fromPath(path: String): PlainFile = fromFile(new File(path))
+ def fromPath(file: Path): PlainFile =
+ if (file.exists) new PlainFile(file) else null
}
/** This class implements an abstract file backed by a File.
*/
-class PlainFile(val file: File) extends AbstractFile {
- private val fpath = try { file.getCanonicalPath }
- catch { case _: IOException => file.getAbsolutePath }
+class PlainFile(val givenPath: Path) extends AbstractFile {
+ assert(path ne null)
- assert(file ne null)
-// assert(file.exists(), "non-existent file: " + file)
+ val file = givenPath.jfile
+ private val fpath = try givenPath.normalize catch { case _: IOException => givenPath.toAbsolute }
/** Returns the name of this abstract file. */
- def name = file.getName()
+ def name = givenPath.name
/** Returns the path of this abstract file. */
- def path = file.getPath()
+ def path = givenPath.path
/** The absolute file. */
- def absolute = new PlainFile(file.getCanonicalFile())
-
- override def container : AbstractFile = new PlainFile(file.getParentFile)
+ def absolute = new PlainFile(givenPath.normalize)
- override def input = new FileInputStream(file)
- override def output = new FileOutputStream(file)
-
- override def sizeOption = Some(file.length.toInt)
+ override def container: AbstractFile = new PlainFile(givenPath.parent.get)
+ override def input = givenPath.toFile.inputStream()
+ override def output = givenPath.toFile.outputStream()
+ override def sizeOption = Some(givenPath.length.toInt)
override def hashCode(): Int = fpath.hashCode
-
override def equals(that: Any): Boolean =
- that.isInstanceOf[PlainFile] &&
- fpath.equals(that.asInstanceOf[PlainFile].fpath)
+ cond(that) { case other: PlainFile => fpath == other.fpath }
/** Is this abstract file a directory? */
- def isDirectory: Boolean = file.isDirectory()
+ def isDirectory: Boolean = givenPath.isDirectory
/** Returns the time that this abstract file was last modified. */
- def lastModified: Long = file.lastModified()
+ def lastModified: Long = givenPath.lastModified
/** Returns all abstract subfiles of this abstract directory. */
def iterator: Iterator[AbstractFile] = {
- assert(isDirectory, "not a directory '" + this + "'")
- val names: Array[String] = file.list()
- if ((names eq null) || names.length == 0) Iterator.empty
- else names.iterator.map { name: String => new File(file, name) }
- .filter(_.exists).map(file => new PlainFile(file))
+ assert(isDirectory, "not a directory '%s'" format this)
+ givenPath.toDirectory.list filter (_.exists) map (new PlainFile(_))
}
/**
@@ -79,34 +71,22 @@ class PlainFile(val file: File) extends AbstractFile {
* @return ...
*/
def lookupName(name: String, directory: Boolean): AbstractFile = {
- //assert(isDirectory, "not a directory '" + this + "'")
- val child = new File(file, name)
- if (!child.exists() || (directory != child.isDirectory) ||
- directory == child.isFile()) null
- else new PlainFile(child)
+ val child = givenPath / name
+ if ((child.isDirectory && directory) || (child.isFile && !directory)) new PlainFile(child)
+ else null
}
/** Does this abstract file denote an existing file? */
- def create {
- if (!exists)
- file.createNewFile()
- }
+ def create: Unit = if (!exists) givenPath.createFile()
/** Delete the underlying file or directory (recursively). */
- def delete {
- if (file.isFile) file.delete
- else if (file.isDirectory) {
- iterator.foreach(_.delete)
- file.delete
- }
- }
+ def delete: Unit =
+ if (givenPath.isFile) givenPath.delete()
+ else if (givenPath.isDirectory) givenPath.toDirectory.deleteRecursively()
/** Returns a plain file with the given name. It does not
* check that it exists.
*/
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = {
- val f = new File(file, name)
- new PlainFile(f)
- }
-
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainFile(givenPath / name)
}
diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
index 9d322af889..7951f7802d 100644
--- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala
+++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
@@ -8,12 +8,16 @@
package scala.tools.nsc
package io
-import java.io.{File, IOException, InputStream}
+import scala.io.File
import java.net.URL
import java.util.Enumeration
-import java.util.zip.{ZipEntry, ZipFile, ZipInputStream}
+import java.io.{ File => JFile, IOException, InputStream, BufferedInputStream }
+import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
+import PartialFunction._
-import scala.collection.mutable.{Map, HashMap}
+import scala.collection.mutable.{ Map, HashMap }
+import scala.collection.immutable.{ StringVector => SV }
+import scala.collection.JavaConversions.asIterator
/**
* @author Philippe Altherr
@@ -29,7 +33,7 @@ object ZipArchive {
* @param path ...
* @return ...
*/
- def fromPath(path: String): AbstractFile = fromFile(new File(path))
+ def fromPath(path: String): AbstractFile = fromFile(File(path))
/**
* If the specified file <code>file</code> exists and is a readable
@@ -40,7 +44,7 @@ object ZipArchive {
* @return ...
*/
def fromFile(file: File): AbstractFile =
- try { new ZipArchive(file, new ZipFile(file)) }
+ try { new ZipArchive(file, new ZipFile(file.jfile)) }
catch { case _: IOException => null }
/**
@@ -50,7 +54,7 @@ object ZipArchive {
* @return ...
*/
def fromArchive(archive: ZipFile): AbstractFile =
- new ZipArchive(new File(archive.getName()), archive)
+ new ZipArchive(File(archive.getName()), archive)
/**
* Returns an abstract directory backed by the specified archive.
@@ -62,6 +66,28 @@ object ZipArchive {
new URLZipArchive(url)
}
+private[io] trait ZipFileCommon
+{
+ import SV.{ splitAt }
+
+ protected def splitPath(path: String): (String, String) = {
+ (path lastIndexOf '/') match {
+ case -1 => ("/", path)
+ case idx => splitAt(path, idx + 1)
+ }
+ }
+
+ protected def byteInputStream(in: InputStream): InputStream = {
+ val buf = new BufferedInputStream(in)
+ val bytes = Iterator continually in.read().toByte takeWhile (_ != -1)
+ new java.io.ByteArrayInputStream(bytes.toSequence.toArray)
+ }
+
+ protected def zipEntryIterator(zis: ZipInputStream): Iterator[ZipEntry] = {
+ Iterator continually zis.getNextEntry() takeWhile (_ != null)
+ }
+}
+
/**
* This class implements an abstract directory backed by a zip
* archive. We let the encoding be <code>null</code>, because we behave like
@@ -70,26 +96,40 @@ object ZipArchive {
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
-final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) {
-
+final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) with ZipFileCommon
+{
assert(archive ne null)
- //########################################################################
- // Private Fields
- /** The root directory or null if not yet initialized */
- private var root: DirEntry = _
+ /** The root directory */
+ private lazy val root = {
+ val root = new DirEntry(this, "<root>", "/")
- //########################################################################
- // Public Methods
+ // A path to DirEntry map
+ val dirs: Map[String, DirEntry] = new HashMap()
+ dirs("/") = root
+ val entries = asIterator(archive.entries())
+
+ entries foreach { case entry: ZipEntry =>
+ val path = entry.getName
+ if (entry.isDirectory) {
+ val dir: DirEntry = getDir(dirs, path)
+ if (dir.entry == null) dir.entry = entry
+ }
+ else {
+ val (home, name) = splitPath(path)
+ val parent: DirEntry = getDir(dirs, home)
+ parent.entries.update(name, new FileEntry(parent, name, path, entry))
+ }
+ }
+
+ root
+ }
/** Returns true. */
override def isDirectory = true
/** Returns all abstract subfiles of this abstract directory. */
- override def iterator: Iterator[AbstractFile] = {
- if (root eq null) load()
- root.iterator
- }
+ override def iterator: Iterator[AbstractFile] = root.iterator
/**
* Returns the abstract file in this abstract directory with the
@@ -97,10 +137,8 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file)
* argument "directory" tells whether to look for a directory or
* or a regular file.
*/
- override def lookupName(name: String, directory: Boolean): AbstractFile = {
- if (root eq null) load()
+ override def lookupName(name: String, directory: Boolean): AbstractFile =
root.lookupName(name, directory)
- }
/** Returns an abstract file with the given name. It does not
* check that it exists.
@@ -108,86 +146,54 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file)
override def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
throw new UnsupportedOperationException()
- //########################################################################
- // Private Methods
-
- /** Loads the archive and creates the root directory. */
- private def load() {
- this.root = new DirEntry(this, "<root>", "/")
- // A path to DirEntry map
- val dirs: Map[String, DirEntry] = new HashMap()
- dirs.update("/", root)
- val entries = archive.entries()
- while (entries.hasMoreElements()) {
- val entry = entries.nextElement().asInstanceOf[ZipEntry]
- val path = entry.getName()
- assert(entry.isDirectory() == path.endsWith("/"),
- this.toString() + " - " + path);
- if (entry.isDirectory()) {
- val dir: DirEntry = getDir(dirs, path)
- // this assertion causes an unnecessary bomb if a directory is twice listed in the jar
- // assert(dir.entry eq null, this.toString() + " - " + path)
- if (dir.entry eq null) dir.entry = entry
- } else {
- val index = path.lastIndexOf('/')
- val name = if (index < 0) path else path.substring(index + 1)
- val home = if (index < 0) "/" else path.substring(0, index + 1)
- val parent: DirEntry = getDir(dirs, home)
- // OLD: assert(!parent.entries.contains(path))
- // MAYBE: assert(!parent.entries.contains(name))
- //if (parent.entries.contains(name))
- // Console.println("XXX: " + this.toString() + " - " + home + "/" + name)
- parent.entries.update(name, new FileEntry(parent, name, path, entry))
- }
- }
- }
-
/**
* Lookups the specified table for a DirEntry with the specified
* path. If successful, returns the found DirEntry. Otherwise
* creates a new DirEntry, enters it into the table and in the
* table of its parent ZipDir and returns it.
*/
- private def getDir(dirs: Map[String,DirEntry], path: String): DirEntry =
- dirs.get(path) match {
- case Some(dir) => dir
- case None =>
- val index = path.lastIndexOf('/', path.length() - 2);
- val name = if (index < 0) path else path.substring(index + 1);
- val home = if (index < 0) "/" else path.substring(0, index + 1);
- val parent: DirEntry = getDir(dirs, home);
- val dir = new DirEntry(parent, name.substring(0, name.length() - 1), path);
- parent.entries.update(name, dir);
- dirs.update(path, dir);
- dir
- }
+ private def getDir(dirs: Map[String, DirEntry], path: String): DirEntry =
+ (dirs get path) getOrElse {
+ val (home, name) = splitPath(SV.dropRight(path, 1))
+ val parent: DirEntry = getDir(dirs, home)
+ val dir = new DirEntry(parent, name, path)
+ parent.entries.update(name + SV.last(path), dir)
+ dirs.update(path, dir)
+ dir
+ }
//########################################################################
// Private Class - Entry
/** Superclass of archive entries */
- abstract class Entry(override val container : AbstractFile, name: String, path: String)
- extends VirtualFile(name, path) {
- final override def path = ZipArchive.this.toString() + "(" + pathInArchive + ")"
+ abstract class Entry(
+ override val container: AbstractFile,
+ name: String,
+ path: String
+ ) extends VirtualFile(name, path)
+ {
+ final override def path = "%s(%s)".format(ZipArchive.this, pathInArchive)
final def getArchive = ZipArchive.this.archive
def pathInArchive = super.path
+
override def hashCode = super.hashCode + container.hashCode
- override def equals(that : Any) = super.equals(that) && (that match {
- case entry : Entry => container == entry.container
- case _ => false
- })
+ override def equals(that : Any) =
+ super.equals(that) && (cond(that) {
+ case e: Entry => container == e.container
+ })
}
//########################################################################
// Private Class - DirEntry
/** A directory archive entry */
- private final class DirEntry(container : AbstractFile, name: String, path: String)
- extends Entry(container, name, path)
+ private final class DirEntry(
+ container: AbstractFile,
+ name: String,
+ path: String
+ ) extends Entry(container, name, path)
{
-
val entries: Map[String, Entry] = new HashMap()
-
var entry: ZipEntry = _
override def isDirectory = true
@@ -198,19 +204,20 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file)
override def iterator: Iterator[AbstractFile] = entries.valuesIterator
- override def lookupName(name: String, directory: Boolean): AbstractFile =
- entries.get(if (directory) name + "/" else name) match {
- case Some(dir) => dir
- case None => null
+ override def lookupName(name: String, directory: Boolean): AbstractFile = {
+ def slashName = if (directory) name + "/" else name
+ entries.getOrElse(slashName, null)
}
}
- //########################################################################
- // Private Class - FileEntry
-
/** A regular file archive entry */
- final class FileEntry(container : AbstractFile, name: String, path: String, val entry: ZipEntry)
- extends Entry(container, name, path) {
+ final class FileEntry(
+ container: AbstractFile,
+ name: String,
+ path: String,
+ val entry: ZipEntry
+ ) extends Entry(container, name, path)
+ {
def archive = ZipArchive.this.archive
override def lastModified: Long = entry.getTime()
override def input = archive.getInputStream(entry)
@@ -225,75 +232,18 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file)
* @author Stephane Micheloud
* @version 1.0, 29/05/2007
*/
-final class URLZipArchive(url: URL) extends AbstractFile {
+final class URLZipArchive(url: URL) extends AbstractFile with ZipFileCommon {
assert(url ne null)
- private var root: DirEntry = _
-
- def container = throw new Error("unsupported")
-
- def name: String = url.getFile()
-
- def path: String = url.getPath()
-
- def file: File = null
-
- def absolute: AbstractFile = this
-
- def isDirectory: Boolean = true
-
- def lastModified: Long =
- try { url.openConnection().getLastModified() }
- catch { case _ => 0 }
-
- /** Does this abstract file denote an existing file? */
- def create {
- throw new UnsupportedOperationException
- }
-
- /** Delete the underlying file or directory (recursively). */
- def delete {
- throw new UnsupportedOperationException
- }
-
- def input: InputStream = url.openStream()
-
- def output = throw new Error("unsupported")
+ private lazy val root: DirEntry = {
+ val root = new DirEntry("<root>", "/")
- override def iterator: Iterator[AbstractFile] = {
- if (root eq null) load()
- root.iterator
- }
-
- override def lookupName(name: String, directory: Boolean): AbstractFile = {
- if (root eq null) load()
- root.lookupName(name, directory)
- }
-
- /** Returns an abstract file with the given name. It does not
- * check that it exists.
- */
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
- throw new UnsupportedOperationException()
-
- private def load() {
- def getEntryInputStream(in: InputStream): InputStream = {
- val buf = new scala.collection.mutable.ArrayBuffer[Byte]
- val data = new Array[Byte](1024)
- var n = in.read(data)
- while (n > 0) {
- buf.++=(data, 0, n)
- n = in.read(data)
- }
- new java.io.ByteArrayInputStream(buf.toArray)
- }
- this.root = new DirEntry("<root>", "/")
// A path to DirEntry map
val dirs: Map[String, DirEntry] = new HashMap()
- dirs.update("/", root)
+ dirs("/") = root
+
val zis = new ZipInputStream(input)
- var entry = zis.getNextEntry()
- while (entry ne null) {
+ zipEntryIterator(zis) foreach { case entry =>
val path = entry.getName()
assert(entry.isDirectory() == path.endsWith("/"),
this.toString() + " - " + path);
@@ -307,14 +257,43 @@ final class URLZipArchive(url: URL) extends AbstractFile {
val home = if (index < 0) "/" else path.substring(0, index + 1)
val parent: DirEntry = getDir(dirs, home)
assert(!parent.entries.contains(path), this.toString() + " - " + path)
- val in = getEntryInputStream(zis)
+ val in = byteInputStream(zis)
parent.entries.update(name, new FileEntry(name, path, entry, in))
}
zis.closeEntry()
- entry = zis.getNextEntry()
}
+ root
}
+ def container = throw new Error("unsupported")
+
+ def name: String = url.getFile()
+ def path: String = url.getPath()
+ def file: JFile = null
+ def absolute: AbstractFile = this
+ def isDirectory: Boolean = true
+
+ def lastModified: Long =
+ try url.openConnection().getLastModified()
+ catch { case _: IOException => 0 }
+
+ def create: Unit = throw new UnsupportedOperationException
+ def delete: Unit = throw new UnsupportedOperationException
+
+ def input: InputStream = url.openStream()
+ def output = throw new Error("unsupported")
+
+ override def iterator: Iterator[AbstractFile] = root.iterator
+
+ override def lookupName(name: String, directory: Boolean): AbstractFile =
+ root.lookupName(name, directory)
+
+ /** Returns an abstract file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ throw new UnsupportedOperationException()
+
private def getDir(dirs: Map[String, DirEntry], path: String): DirEntry =
dirs.get(path) match {
case Some(dir) => dir
@@ -330,16 +309,12 @@ final class URLZipArchive(url: URL) extends AbstractFile {
}
/** Superclass of archive entries */
- abstract class Entry(name: String, path: String)
- extends VirtualFile(name, path) {
- final override def path = URLZipArchive.this.toString() + "(" + super.path + ")"
- //final def getArchive = URLZipArchive.this.archive
+ abstract class Entry(name: String, path: String) extends VirtualFile(name, path) {
+ final override def path = "%s(%s)".format(URLZipArchive.this, super.path)
}
/** A directory archive entry */
- private final class DirEntry(name: String, path: String)
- extends Entry(name, path)
- {
+ private final class DirEntry(name: String, path: String) extends Entry(name, path) {
val entries: Map[String, Entry] = new HashMap()
var entry: ZipEntry = _