summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-08-31 15:46:46 +0000
committerPaul Phillips <paulp@improving.org>2009-08-31 15:46:46 +0000
commitd227d486fdb94ef3bffcfe048a3069db3d9c14e1 (patch)
tree26968c7974e11cd24a527cf466c2a40275447e6e /src
parent09ba9ab65e4e10ce05f099e4bf28a16341dac70c (diff)
downloadscala-d227d486fdb94ef3bffcfe048a3069db3d9c14e1.tar.gz
scala-d227d486fdb94ef3bffcfe048a3069db3d9c14e1.tar.bz2
scala-d227d486fdb94ef3bffcfe048a3069db3d9c14e1.zip
Modernizing bits of scala.tools.nsc.io and incr...
Modernizing bits of scala.tools.nsc.io and incrementally introducing some of scala.io to further flesh out what the File interface will require.
Diffstat (limited to 'src')
-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 = _