diff options
author | Paul Phillips <paulp@improving.org> | 2009-08-31 15:46:46 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-08-31 15:46:46 +0000 |
commit | d227d486fdb94ef3bffcfe048a3069db3d9c14e1 (patch) | |
tree | 26968c7974e11cd24a527cf466c2a40275447e6e /src | |
parent | 09ba9ab65e4e10ce05f099e4bf28a16341dac70c (diff) | |
download | scala-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.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/PlainFile.scala | 80 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/ZipArchive.scala | 295 |
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 = _ |