aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/io/PlainFile.scala
blob: 53474e7781d624b401fece3d6effed32c824d79a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* NSC -- new Scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package dotty.tools
package io

/** ''Note:  This library is considered experimental and should not be used unless you know what you are doing.'' */
class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
  override def isDirectory = true
  override def iterator = givenPath.list filter (_.exists) map (x => new PlainFile(x))
  override def delete(): Unit = givenPath.deleteRecursively()
}

/** This class implements an abstract file backed by a File.
 *
 * ''Note:  This library is considered experimental and should not be used unless you know what you are doing.''
 */
class PlainFile(val givenPath: Path) extends AbstractFile {
  assert(path ne null)

  val file = givenPath.jfile
  override def underlyingSource = Some(this)

  private val fpath = givenPath.toAbsolute

  /** Returns the name of this abstract file. */
  def name = givenPath.name

  /** Returns the path of this abstract file. */
  def path = givenPath.path

  /** The absolute file. */
  def absolute = new PlainFile(givenPath.toAbsolute)

  override def container: AbstractFile = new PlainFile(givenPath.parent)
  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 match {
    case x: PlainFile => fpath == x.fpath
    case _            => false
  }

  /** Is this abstract file a directory? */
  def isDirectory: Boolean = givenPath.isDirectory

  /** Returns the time that this abstract file was last modified. */
  def lastModified: Long = givenPath.lastModified

  /** Returns all abstract subfiles of this abstract directory. */
  def iterator: Iterator[AbstractFile] = {
    // Optimization: Assume that the file was not deleted and did not have permissions changed
    // between the call to `list` and the iteration. This saves a call to `exists`.
    def existsFast(path: Path) = path match {
      case (_: Directory | _: io.File) => true
      case _                           => path.exists
    }
    if (!isDirectory) Iterator.empty
    else givenPath.toDirectory.list filter existsFast map (new PlainFile(_))
  }

  /**
   * Returns the abstract file in this abstract directory with the
   * specified name. If there is no such file, returns null. The
   * argument "directory" tells whether to look for a directory or
   * or a regular file.
   */
  def lookupName(name: String, directory: Boolean): AbstractFile = {
    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(): Unit = if (!exists) givenPath.createFile()

  /** Delete the underlying file or directory (recursively). */
  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 =
    new PlainFile(givenPath / name)
}

private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile {
  import java.nio.file._

  assert(nioPath ne null)

  /** Returns the underlying File if any and null otherwise. */
  override def file: java.io.File = try {
    nioPath.toFile
  } catch {
    case _: UnsupportedOperationException => null
  }

  override def underlyingSource  = Some(this)

  private val fpath = nioPath.toAbsolutePath.toString

  /** Returns the name of this abstract file. */
  def name = nioPath.getFileName.toString

  /** Returns the path of this abstract file. */
  def path = nioPath.toString

  /** The absolute file. */
  def absolute = new PlainNioFile(nioPath.toAbsolutePath)

  override def container: AbstractFile = new PlainNioFile(nioPath.getParent)
  override def input = Files.newInputStream(nioPath)
  override def output = Files.newOutputStream(nioPath)
  override def sizeOption = Some(Files.size(nioPath).toInt)
  override def hashCode(): Int = fpath.hashCode()
  override def equals(that: Any): Boolean = that match {
    case x: PlainNioFile => fpath == x.fpath
    case _               => false
  }

  /** Is this abstract file a directory? */
  def isDirectory: Boolean = Files.isDirectory(nioPath)

  /** Returns the time that this abstract file was last modified. */
  def lastModified: Long = Files.getLastModifiedTime(nioPath).toMillis

  /** Returns all abstract subfiles of this abstract directory. */
  def iterator: Iterator[AbstractFile] = {
    try {
      import scala.collection.JavaConverters._
      val it = Files.newDirectoryStream(nioPath).iterator()
      it.asScala.map(new PlainNioFile(_))
    } catch {
      case _: NotDirectoryException => Iterator.empty
    }
  }

  /**
    * Returns the abstract file in this abstract directory with the
    * specified name. If there is no such file, returns null. The
    * argument "directory" tells whether to look for a directory or
    * or a regular file.
    */
  def lookupName(name: String, directory: Boolean): AbstractFile = {
    val child = nioPath.resolve(name)
    if ((Files.isDirectory(child) && directory) || (Files.isRegularFile(child) && !directory)) new PlainNioFile(child)
    else null
  }

  /** Does this abstract file denote an existing file? */
  def create(): Unit = if (!exists)  Files.createFile(nioPath)

  /** Delete the underlying file or directory (recursively). */
  def delete(): Unit =
    if (Files.isRegularFile(nioPath)) Files.deleteIfExists(nioPath)
    else if (Files.isDirectory(nioPath)) new Directory(nioPath.toFile).deleteRecursively()

  /** Returns a plain file with the given name. It does not
    *  check that it exists.
    */
  def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
    new PlainNioFile(nioPath.resolve(name))
}