~ubuntu-branches/debian/sid/scala/sid

« back to all changes in this revision

Viewing changes to src/reflect/scala/reflect/io/Path.scala

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg, Mehdi Dogguy, Lucas Satabin, Frank S. Thomas, Emmanuel Bourg
  • Date: 2015-06-05 23:52:59 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20150605235259-wk00vgk83dh8o19g
Tags: 2.10.5-1
* Team upload.

[ Mehdi Dogguy ]
* New upstream release (Closes: #744278).

[ Lucas Satabin ]
* Update patches
* Update the clean target
* Update paths of elements to install
* Update watch file

[ Frank S. Thomas ]
* Remove myself from Uploaders.

[ Emmanuel Bourg ]
* The package has been adopted by the Java Team (Closes: #754935)
* Patched the build to avoid downloading libraries from the Internet
* Replaced the minified JavaScript files with unobfuscated ones
* No longer build scala-partest.jar until diffutils is packaged or replaced
* debian/watch: Fixed the versions matched (x.y.z instead of x.y.z..z)
* debian/rules:
  - Added the missing get-orig-source target (Closes: #724704)
  - Improved the clean target
* debian/control:
  - Build depend on scala (>= 2.10) and bnd
  - Use canonical URLs for the Vcs-* fields
  - Standards-Version updated to 3.9.6 (no changes)
* Switch to debhelper level 9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* NSC -- new Scala compiler
 
2
 * Copyright 2005-2013 LAMP/EPFL
 
3
 * @author Paul Phillips
 
4
 */
 
5
 
 
6
package scala.reflect
 
7
package io
 
8
 
 
9
import java.io.{
 
10
  FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
 
11
  BufferedInputStream, BufferedOutputStream, RandomAccessFile }
 
12
import java.io.{ File => JFile }
 
13
import java.net.{ URI, URL }
 
14
import scala.util.Random.alphanumeric
 
15
import scala.language.implicitConversions
 
16
 
 
17
/** An abstraction for filesystem paths.  The differences between
 
18
 *  Path, File, and Directory are primarily to communicate intent.
 
19
 *  Since the filesystem can change at any time, there is no way to
 
20
 *  reliably associate Files only with files and so on.  Any Path
 
21
 *  can be converted to a File or Directory (and thus gain access to
 
22
 *  the additional entity specific methods) by calling toFile or
 
23
 *  toDirectory, which has no effect on the filesystem.
 
24
 *
 
25
 *  Also available are createFile and createDirectory, which attempt
 
26
 *  to create the path in question.
 
27
 *
 
28
 *  @author  Paul Phillips
 
29
 *  @since   2.8
 
30
 *  
 
31
 *  ''Note:  This library is considered experimental and should not be used unless you know what you are doing.''
 
32
 */
 
33
object Path {
 
34
  def isExtensionJarOrZip(jfile: JFile): Boolean = isExtensionJarOrZip(jfile.getName)
 
35
  def isExtensionJarOrZip(name: String): Boolean = {
 
36
    val ext = extension(name)
 
37
    ext == "jar" || ext == "zip"
 
38
  }
 
39
  def extension(name: String): String = {
 
40
    var i = name.length - 1
 
41
    while (i >= 0 && name.charAt(i) != '.')
 
42
      i -= 1
 
43
 
 
44
    if (i < 0) ""
 
45
    else name.substring(i + 1).toLowerCase
 
46
  }
 
47
 
 
48
  // not certain these won't be problematic, but looks good so far
 
49
  implicit def string2path(s: String): Path = apply(s)
 
50
  implicit def jfile2path(jfile: JFile): Path = apply(jfile)
 
51
 
 
52
  // java 7 style, we don't use it yet
 
53
  // object AccessMode extends Enumeration {
 
54
  //   val EXECUTE, READ, WRITE = Value
 
55
  // }
 
56
  // def checkAccess(modes: AccessMode*): Boolean = {
 
57
  //   modes foreach {
 
58
  //     case EXECUTE  => throw new Exception("Unsupported") // can't check in java 5
 
59
  //     case READ     => if (!jfile.canRead()) return false
 
60
  //     case WRITE    => if (!jfile.canWrite()) return false
 
61
  //   }
 
62
  //   true
 
63
  // }
 
64
 
 
65
  def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
 
66
  def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
 
67
  def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile)
 
68
  def onlyFiles(xs: List[Path]): List[File] = xs filter (_.isFile) map (_.toFile)
 
69
 
 
70
  def roots: List[Path] = java.io.File.listRoots().toList map Path.apply
 
71
 
 
72
  def apply(segments: Seq[String]): Path = apply(segments mkString java.io.File.separator)
 
73
  def apply(path: String): Path = apply(new JFile(path))
 
74
  def apply(jfile: JFile): Path =
 
75
    if (jfile.isFile) new File(jfile)
 
76
    else if (jfile.isDirectory) new Directory(jfile)
 
77
    else new Path(jfile)
 
78
 
 
79
  /** Avoiding any shell/path issues by only using alphanumerics. */
 
80
  private[io] def randomPrefix = alphanumeric take 6 mkString ""
 
81
  private[io] def fail(msg: String) = throw FileOperationException(msg)
 
82
}
 
83
import Path._
 
84
 
 
85
/** The Path constructor is private so we can enforce some
 
86
 *  semantics regarding how a Path might relate to the world.
 
87
 *  
 
88
 *  ''Note:  This library is considered experimental and should not be used unless you know what you are doing.''
 
89
 */
 
90
class Path private[io] (val jfile: JFile) {
 
91
  val separator = java.io.File.separatorChar
 
92
  val separatorStr = java.io.File.separator
 
93
 
 
94
  // Validation: this verifies that the type of this object and the
 
95
  // contents of the filesystem are in agreement.  All objects are
 
96
  // valid except File objects whose path points to a directory and
 
97
  // Directory objects whose path points to a file.
 
98
  def isValid: Boolean = true
 
99
 
 
100
  // conversions
 
101
  def toFile: File = new File(jfile)
 
102
  def toDirectory: Directory = new Directory(jfile)
 
103
  def toAbsolute: Path = if (isAbsolute) this else Path(jfile.getAbsolutePath())
 
104
  def toCanonical: Path = Path(jfile.getCanonicalPath())
 
105
  def toURI: URI = jfile.toURI()
 
106
  def toURL: URL = toURI.toURL()
 
107
  /** If this path is absolute, returns it: otherwise, returns an absolute
 
108
   *  path made up of root / this.
 
109
   */
 
110
  def toAbsoluteWithRoot(root: Path) = if (isAbsolute) this else root.toAbsolute / this
 
111
 
 
112
  /** Creates a new Path with the specified path appended.  Assumes
 
113
   *  the type of the new component implies the type of the result.
 
114
   */
 
115
  def /(child: Path): Path = if (isEmpty) child else new Path(new JFile(jfile, child.path))
 
116
  def /(child: Directory): Directory = /(child: Path).toDirectory
 
117
  def /(child: File): File = /(child: Path).toFile
 
118
 
 
119
  /** If this path is a container, recursively iterate over its contents.
 
120
   *  The supplied condition is a filter which is applied to each element,
 
121
   *  with that branch of the tree being closed off if it is true.  So for
 
122
   *  example if the condition is true for some subdirectory, nothing
 
123
   *  under that directory will be in the Iterator; but otherwise each
 
124
   *  file and subdirectory underneath it will appear.
 
125
   */
 
126
  def walkFilter(cond: Path => Boolean): Iterator[Path] =
 
127
    if (isFile) toFile walkFilter cond
 
128
    else if (isDirectory) toDirectory walkFilter cond
 
129
    else Iterator.empty
 
130
 
 
131
  /** Equivalent to walkFilter(_ => false).
 
132
   */
 
133
  def walk: Iterator[Path] = walkFilter(_ => true)
 
134
 
 
135
  // identity
 
136
  def name: String = jfile.getName()
 
137
  def path: String = jfile.getPath()
 
138
  def normalize: Path = Path(jfile.getAbsolutePath())
 
139
  def isRootPath: Boolean = roots exists (_ isSame this)
 
140
 
 
141
  def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other)
 
142
  def relativize(other: Path) = {
 
143
    assert(isAbsolute == other.isAbsolute, "Paths not of same type: "+this+", "+other)
 
144
 
 
145
    def createRelativePath(baseSegs: List[String], otherSegs: List[String]) : String = {
 
146
      (baseSegs, otherSegs) match {
 
147
        case (b :: bs, o :: os) if b == o => createRelativePath(bs, os)
 
148
        case (bs, os) => ((".."+separator)*bs.length)+os.mkString(separatorStr)
 
149
      }
 
150
    }
 
151
 
 
152
    Path(createRelativePath(segments, other.segments))
 
153
  }
 
154
 
 
155
  // derived from identity
 
156
  def root: Option[Path] = roots find (this startsWith _)
 
157
  def segments: List[String] = (path split separator).toList filterNot (_.length == 0)
 
158
  /**
 
159
   * @return The path of the parent directory, or root if path is already root
 
160
   */
 
161
  def parent: Directory = path match {
 
162
    case "" | "." => Directory("..")
 
163
    case _        =>
 
164
      // the only solution <-- a comment which could have used elaboration
 
165
      if (segments.nonEmpty && segments.last == "..")
 
166
        (path / "..").toDirectory
 
167
      else jfile.getParent match {
 
168
        case null =>
 
169
          if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root
 
170
          else Directory(".")         // a dir under pwd
 
171
        case x    =>
 
172
          Directory(x)
 
173
      }
 
174
  }
 
175
  def parents: List[Directory] = {
 
176
    val p = parent
 
177
    if (p isSame this) Nil else p :: p.parents
 
178
  }
 
179
  // if name ends with an extension (e.g. "foo.jpg") returns the extension ("jpg"), otherwise ""
 
180
  def extension: String = {
 
181
    var i = name.length - 1
 
182
    while (i >= 0 && name.charAt(i) != '.')
 
183
      i -= 1
 
184
 
 
185
    if (i < 0) ""
 
186
    else name.substring(i + 1)
 
187
  }
 
188
  // def extension: String = (name lastIndexOf '.') match {
 
189
  //   case -1   => ""
 
190
  //   case idx  => name drop (idx + 1)
 
191
  // }
 
192
  // compares against extensions in a CASE INSENSITIVE way.
 
193
  def hasExtension(ext: String, exts: String*) = {
 
194
    val lower = extension.toLowerCase
 
195
    ext.toLowerCase == lower || exts.exists(_.toLowerCase == lower)
 
196
  }
 
197
  // returns the filename without the extension.
 
198
  def stripExtension: String = name stripSuffix ("." + extension)
 
199
  // returns the Path with the extension.
 
200
  def addExtension(ext: String): Path = Path(path + "." + ext)
 
201
  // changes the existing extension out for a new one, or adds it
 
202
  // if the current path has none.
 
203
  def changeExtension(ext: String): Path = (
 
204
    if (extension == "") addExtension(ext)
 
205
    else Path(path.stripSuffix(extension) + ext)
 
206
  )
 
207
 
 
208
  // conditionally execute
 
209
  def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None
 
210
  def ifDirectory[T](f: Directory => T): Option[T] = if (isDirectory) Some(f(toDirectory)) else None
 
211
 
 
212
  // Boolean tests
 
213
  def canRead = jfile.canRead()
 
214
  def canWrite = jfile.canWrite()
 
215
  def exists = jfile.exists()
 
216
  def notExists = try !jfile.exists() catch { case ex: SecurityException => false }
 
217
 
 
218
  def isFile = jfile.isFile()
 
219
  def isDirectory = jfile.isDirectory()
 
220
  def isAbsolute = jfile.isAbsolute()
 
221
  def isHidden = jfile.isHidden()
 
222
  def isEmpty = path.length == 0
 
223
 
 
224
  // Information
 
225
  def lastModified = jfile.lastModified()
 
226
  def lastModified_=(time: Long) = jfile setLastModified time // should use setXXX function?
 
227
  def length = jfile.length()
 
228
 
 
229
  // Boolean path comparisons
 
230
  def endsWith(other: Path) = segments endsWith other.segments
 
231
  def startsWith(other: Path) = segments startsWith other.segments
 
232
  def isSame(other: Path) = toCanonical == other.toCanonical
 
233
  def isFresher(other: Path) = lastModified > other.lastModified
 
234
 
 
235
  // creations
 
236
  def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = {
 
237
    val res = if (force) jfile.mkdirs() else jfile.mkdir()
 
238
    if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name)
 
239
    else if (isDirectory) toDirectory
 
240
    else new Directory(jfile)
 
241
  }
 
242
  def createFile(failIfExists: Boolean = false): File = {
 
243
    val res = jfile.createNewFile()
 
244
    if (!res && failIfExists && exists) fail("File '%s' already exists." format name)
 
245
    else if (isFile) toFile
 
246
    else new File(jfile)
 
247
  }
 
248
 
 
249
  // deletions
 
250
  def delete() = jfile.delete()
 
251
  def deleteIfExists() = if (jfile.exists()) delete() else false
 
252
 
 
253
  /** Deletes the path recursively. Returns false on failure.
 
254
   *  Use with caution!
 
255
   */
 
256
  def deleteRecursively(): Boolean = deleteRecursively(jfile)
 
257
  private def deleteRecursively(f: JFile): Boolean = {
 
258
    if (f.isDirectory) f.listFiles match {
 
259
      case null =>
 
260
      case xs   => xs foreach deleteRecursively
 
261
    }
 
262
    f.delete()
 
263
  }
 
264
 
 
265
  def truncate() =
 
266
    isFile && {
 
267
      val raf = new RandomAccessFile(jfile, "rw")
 
268
      raf setLength 0
 
269
      raf.close()
 
270
      length == 0
 
271
    }
 
272
 
 
273
  def touch(modTime: Long = System.currentTimeMillis) = {
 
274
    createFile()
 
275
    if (isFile)
 
276
      lastModified = modTime
 
277
  }
 
278
 
 
279
  // todo
 
280
  // def copyTo(target: Path, options ...): Boolean
 
281
  // def moveTo(target: Path, options ...): Boolean
 
282
 
 
283
  override def toString() = path
 
284
  override def equals(other: Any) = other match {
 
285
    case x: Path  => path == x.path
 
286
    case _        => false
 
287
  }
 
288
  override def hashCode() = path.hashCode()
 
289
}