summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/io/Path.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-09-11 18:12:33 +0000
committerPaul Phillips <paulp@improving.org>2009-09-11 18:12:33 +0000
commite604abb25c1c95aa75b969519aea3a915ba11798 (patch)
tree05081680122b722e0d62c2b34cbc18cc7c5019ed /src/compiler/scala/tools/nsc/io/Path.scala
parentf9394a4d472887c4563e768467170a9b1677d5c1 (diff)
downloadscala-e604abb25c1c95aa75b969519aea3a915ba11798.tar.gz
scala-e604abb25c1c95aa75b969519aea3a915ba11798.tar.bz2
scala-e604abb25c1c95aa75b969519aea3a915ba11798.zip
Resurrected the former contents of scala.io in ...
Resurrected the former contents of scala.io in their new home, scala.tools.nsc.io, and equipped them with fake beards and handlebar moustaches. Also restored the reverted bits of the compiler which had been taking advantage of them.
Diffstat (limited to 'src/compiler/scala/tools/nsc/io/Path.scala')
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala
new file mode 100644
index 0000000000..40b6a3a4ad
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/Path.scala
@@ -0,0 +1,169 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ */
+
+package scala.tools.nsc
+package io
+
+import java.io.{
+ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
+ BufferedInputStream, BufferedOutputStream, File => JFile }
+import java.net.{ URI, URL }
+import collection.{ Sequence, Traversable }
+import collection.immutable.{ StringVector => SV }
+import PartialFunction._
+import scala.util.Random.nextASCIIString
+
+/** An abstraction for filesystem paths. The differences between
+ * Path, File, and Directory are primarily to communicate intent.
+ * Since the filesystem can change at any time, there is no way to
+ * reliably associate Files only with files and so on. Any Path
+ * can be converted to a File or Directory (and thus gain access to
+ * the additional entity specific methods) by calling toFile or
+ * toDirectory, which has no effect on the filesystem.
+ *
+ * Also available are createFile and createDirectory, which attempt
+ * to create the path in question.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+
+object Path
+{
+ // not certain these won't be problematic, but looks good so far
+ implicit def string2path(s: String): Path = apply(s)
+ implicit def jfile2path(jfile: JFile): Path = apply(jfile)
+
+ // java 7 style, we don't use it yet
+ // object AccessMode extends Enumeration("AccessMode") {
+ // val EXECUTE, READ, WRITE = Value
+ // }
+ // def checkAccess(modes: AccessMode*): Boolean = {
+ // modes foreach {
+ // case EXECUTE => throw new Exception("Unsupported") // can't check in java 5
+ // case READ => if (!jfile.canRead()) return false
+ // case WRITE => if (!jfile.canWrite()) return false
+ // }
+ // true
+ // }
+
+ def roots: List[Path] = JFile.listRoots().toList map Path.apply
+
+ def apply(path: String): Path = apply(new JFile(path))
+ def apply(jfile: JFile): Path =
+ if (jfile.isFile) new File(jfile)
+ else if (jfile.isDirectory) new Directory(jfile)
+ else new Path(jfile)
+
+ private[io] def randomPrefix = nextASCIIString(6)
+ private[io] def fail(msg: String) = throw FileOperationException(msg)
+}
+import Path._
+
+/** The Path constructor is private so we can enforce some
+ * semantics regarding how a Path might relate to the world.
+ */
+class Path private[io] (val jfile: JFile)
+{
+ val separator = JFile.separatorChar
+
+ // Validation: this verifies that the type of this object and the
+ // contents of the filesystem are in agreement. All objects are
+ // valid except File objects whose path points to a directory and
+ // Directory objects whose path points to a file.
+ def isValid: Boolean = true
+
+ // conversions
+ def toFile: File = new File(jfile)
+ def toDirectory: Directory = new Directory(jfile)
+ def toAbsolute: Path = if (isAbsolute) this else Path(jfile.getAbsolutePath())
+ def toURI: URI = jfile.toURI()
+ def toURL: URL = toURI.toURL()
+
+ /** Creates a new Path with the specified path appended. Assumes
+ * the type of the new component implies the type of the result.
+ */
+ def /(child: Path): Path = new Path(new JFile(jfile, child.path))
+ def /(child: Directory): Directory = /(child: Path).toDirectory
+ def /(child: File): File = /(child: Path).toFile
+
+ // identity
+ def name: String = jfile.getName()
+ def path: String = jfile.getPath()
+ def normalize: Path = Path(jfile.getCanonicalPath())
+ // todo -
+ // def resolve(other: Path): Path
+ // def relativize(other: Path): Path
+
+ // derived from identity
+ def root: Option[Path] = roots find (this startsWith _)
+ def segments: List[String] = (path split separator).toList filterNot (_.isEmpty)
+ def parent: Option[Path] = Option(jfile.getParent()) map Path.apply
+ def parents: List[Path] = parent match {
+ case None => Nil
+ case Some(p) => p :: p.parents
+ }
+ // if name ends with an extension (e.g. "foo.jpg") returns the extension ("jpg")
+ def extension: Option[String] =
+ condOpt(SV.lastIndexWhere(name, _ == '.')) {
+ case idx if idx != -1 => SV.drop(name, idx + 1)
+ }
+ // Alternative approach:
+ // (Option fromReturnValue SV.lastIndexWhere(name, _ == '.') map (x => SV.drop(name, x + 1))
+
+ // Boolean tests
+ def canRead = jfile.canRead()
+ def canWrite = jfile.canWrite()
+ def exists = jfile.exists()
+ def notExists = try !jfile.exists() catch { case ex: SecurityException => false }
+
+ def isFile = jfile.isFile()
+ def isDirectory = jfile.isDirectory()
+ def isAbsolute = jfile.isAbsolute()
+ def isHidden = jfile.isHidden()
+ def isSymlink = parent.isDefined && {
+ val x = parent.get / name
+ x.normalize != x.toAbsolute
+ }
+
+ // Information
+ def lastModified = jfile.lastModified()
+ def lastModified_=(time: Long) = jfile setLastModified time // should use setXXX function?
+ def length = jfile.length()
+
+ // Boolean path comparisons
+ def endsWith(other: Path) = segments endsWith other.segments
+ def startsWith(other: Path) = segments startsWith other.segments
+ def isSame(other: Path) = toAbsolute == other.toAbsolute
+ def isFresher(other: Path) = lastModified > other.lastModified
+
+ // creations
+ def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = {
+ val res = if (force) jfile.mkdirs() else jfile.mkdir()
+ if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name)
+ else if (isDirectory) toDirectory
+ else new Directory(jfile)
+ }
+ def createFile(failIfExists: Boolean = false): File = {
+ val res = jfile.createNewFile()
+ if (!res && failIfExists && exists) fail("File '%s' already exists." format name)
+ else if (isFile) toFile
+ else new File(jfile)
+ }
+
+ // deletions
+ def delete() = jfile.delete()
+ def deleteIfExists() = if (jfile.exists()) delete() else false
+
+ // todo
+ // def copyTo(target: Path, options ...): Boolean
+ // def moveTo(target: Path, options ...): Boolean
+
+ override def toString() = "Path(%s)".format(path)
+ override def equals(other: Any) = other match {
+ case x: Path => path == x.path
+ case _ => false
+ }
+ override def hashCode() = path.hashCode()
+}