Skip to content

Commit 93b1214

Browse files
committed
Further improve dotty.io
1 parent 8c5bc9e commit 93b1214

20 files changed

+71
-115
lines changed

compiler/src/dotty/tools/backend/jvm/GenBCode.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class GenBCode extends Phase {
5353

5454
def outputDir(implicit ctx: Context): AbstractFile = {
5555
val path = ctx.settings.outputDir.value
56-
if (path.isDirectory) new PlainDirectory(Directory(path))
56+
if (path.isDirectory) new PlainDirectory(path.toDirectory)
5757
else {
5858
if (jarFS == null) {
5959
path.delete()

compiler/src/dotty/tools/dotc/Run.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Run(comp: Compiler, ictx: Context) {
6060
assert(ctx.runId <= Periods.MaxPossibleRunId)
6161

6262
def getSource(fileName: String): SourceFile = {
63-
val f = new PlainFile(fileName)
63+
val f = new PlainFile(io.Path(fileName))
6464
if (f.isDirectory) {
6565
ctx.error(s"expected file, received directory '$fileName'")
6666
NoSource

compiler/src/dotty/tools/dotc/classpath/ClassPathFactory.scala

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package dotty.tools.dotc.classpath
55

66
import dotty.tools.io.{AbstractFile, VirtualDirectory}
7-
import dotty.tools.io.Path.string2path
87
import dotty.tools.dotc.config.Settings
98
import FileUtils.AbstractFileOps
109
import dotty.tools.io.ClassPath

compiler/src/dotty/tools/dotc/config/OutputDirs.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class OutputDirs {
3131
if (dir != null && dir.isDirectory)
3232
dir
3333
// was: else if (allowJar && dir == null && Path.isJarOrZip(name, false))
34-
else if (allowJar && dir == null && Jar.isJarOrZip(name, false))
34+
else if (allowJar && dir == null && Jar.isJarOrZip(File(name), false))
3535
new PlainFile(Path(name))
3636
else
3737
throw new FatalError(name + " does not exist or is not a directory"))

compiler/src/dotty/tools/dotc/config/PathResolver.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ object PathResolver {
8080
def scalaHome = Environment.scalaHome
8181
def scalaHomeDir = Directory(scalaHome)
8282
def scalaHomeExists = scalaHomeDir.isDirectory
83-
def scalaLibDir = Directory(scalaHomeDir / "lib")
84-
def scalaClassesDir = Directory(scalaHomeDir / "classes")
83+
def scalaLibDir = (scalaHomeDir / "lib").toDirectory
84+
def scalaClassesDir = (scalaHomeDir / "classes").toDirectory
8585

86-
def scalaLibAsJar = File(scalaLibDir / "scala-library.jar")
87-
def scalaLibAsDir = Directory(scalaClassesDir / "library")
86+
def scalaLibAsJar = (scalaLibDir / "scala-library.jar").toFile
87+
def scalaLibAsDir = (scalaClassesDir / "library").toDirectory
8888

8989
def scalaLibDirFound: Option[Directory] =
9090
if (scalaLibAsJar.isFile) Some(scalaLibDir)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ScalaSettings extends Settings.SettingGroup {
1818
val javaextdirs = PathSetting("-javaextdirs", "Override java extdirs classpath.", Defaults.javaExtDirs)
1919
val sourcepath = PathSetting("-sourcepath", "Specify location(s) of source files.", "") // Defaults.scalaSourcePath
2020
val classpath = PathSetting("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp"
21-
val outputDir = DirectoryJarSetting("-d", "directory|jar", "destination for generated classfiles.", Directory(Path(".")))
21+
val outputDir = DirectoryJarSetting("-d", "directory|jar", "destination for generated classfiles.", Directory("."))
2222
val priorityclasspath = PathSetting("-priorityclasspath", "class path that takes precedence over all other paths (or testing only)", "")
2323

2424
/** Other settings */

compiler/src/dotty/tools/dotc/config/Settings.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ object Settings {
163163
}
164164
case (DirectoryJarTag, arg :: args) =>
165165
val path = Path(arg)
166-
if (path.isDirectory) update(Directory(path), args)
166+
if (path.isDirectory) update(path, args)
167167
else if (path.extension == "jar") update(path, args)
168168
else fail(s"'$arg' does not exist or is not a directory", args)
169169
case (_, Nil) =>

compiler/src/dotty/tools/io/AbstractFile.scala

+11-16
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import java.io.{
1010
ByteArrayOutputStream
1111
}
1212
import java.net.URL
13-
import java.nio.file.{FileAlreadyExistsException, Files}
13+
import java.nio.file.{FileAlreadyExistsException, Files, Paths}
1414

1515
/**
1616
* An abstraction over files for use in the reflection/compiler libraries.
@@ -21,28 +21,26 @@ import java.nio.file.{FileAlreadyExistsException, Files}
2121
* @version 1.0, 23/03/2004
2222
*/
2323
object AbstractFile {
24-
/** Returns "getFile(new File(path))". */
2524
def getFile(path: String): AbstractFile = getFile(File(path))
26-
def getFile(path: Path): AbstractFile = getFile(path.toFile)
25+
def getDirectory(path: String): AbstractFile = getDirectory(Directory(path))
26+
def getFile(path: JPath): AbstractFile = getFile(File(path))
27+
def getDirectory(path: JPath): AbstractFile = getDirectory(Directory(path))
2728

2829
/**
2930
* If the specified File exists and is a regular file, returns an
3031
* abstract regular file backed by it. Otherwise, returns `null`.
3132
*/
32-
def getFile(file: File): AbstractFile =
33-
if (file.isFile) new PlainFile(file) else null
34-
35-
/** Returns "getDirectory(new File(path))". */
36-
def getDirectory(path: Path): AbstractFile = getDirectory(path.toFile)
33+
def getFile(path: Path): AbstractFile =
34+
if (path.isFile) new PlainFile(path) else null
3735

3836
/**
3937
* If the specified File exists and is either a directory or a
4038
* readable zip or jar archive, returns an abstract directory
4139
* backed by it. Otherwise, returns `null`.
4240
*/
43-
def getDirectory(file: File): AbstractFile =
44-
if (file.isDirectory) new PlainFile(file)
45-
else if (file.isFile && Path.isExtensionJarOrZip(file.jpath)) ZipArchive fromFile file
41+
def getDirectory(path: Path): AbstractFile =
42+
if (path.isDirectory) new PlainFile(path)
43+
else if (path.isFile && Path.isExtensionJarOrZip(path.jpath)) ZipArchive fromFile path.toFile
4644
else null
4745

4846
/**
@@ -51,11 +49,8 @@ object AbstractFile {
5149
* Otherwise, returns `null`.
5250
*/
5351
def getURL(url: URL): AbstractFile =
54-
if (url.getProtocol == "file") {
55-
val f = new java.io.File(url.getPath)
56-
if (f.isDirectory) getDirectory(f)
57-
else getFile(f)
58-
} else null
52+
if (url.getProtocol != "file") null
53+
else new PlainFile(new Path(Paths.get(url.toURI)))
5954

6055
def getResources(url: URL): AbstractFile = ZipArchive fromManifestURL url
6156
}

compiler/src/dotty/tools/io/Directory.scala

+12-15
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
package dotty.tools.io
1010

11-
import java.nio.file.Files
11+
import java.nio.file.{Files, Paths}
1212
import java.util.stream.Collectors
1313

1414
import scala.collection.JavaConverters._
@@ -19,18 +19,12 @@ import scala.collection.JavaConverters._
1919
object Directory {
2020
import scala.util.Properties.userDir
2121

22-
private def normalizePath(s: String) = Some(apply(Path(s).normalize))
23-
def Current: Option[Directory] = if (userDir == "") None else normalizePath(userDir)
22+
def Current: Option[Directory] =
23+
if (userDir == "") None
24+
else Some(apply(userDir).normalize)
2425

25-
def apply(path: Path): Directory = path.toDirectory
26-
def apply(jpath: JPath): Directory = new Directory(jpath)
27-
28-
// Like File.makeTemp but creates a directory instead
29-
def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null): Directory = {
30-
val path = File.makeTemp(prefix, suffix, dir)
31-
path.delete()
32-
path.createDirectory()
33-
}
26+
def apply(path: String): Directory = apply(Paths.get(path))
27+
def apply(path: JPath): Directory = new Directory(path)
3428
}
3529

3630
/** An abstraction for directories.
@@ -49,10 +43,13 @@ class Directory(jpath: JPath) extends Path(jpath) {
4943
/** An iterator over the contents of this directory.
5044
*/
5145
def list: Iterator[Path] =
52-
jpath.toFile.listFiles match {
53-
case null => Iterator.empty
54-
case xs => xs.iterator.map(x => Path(x.toPath))
46+
if (isDirectory) {
47+
val fileStream = Files.list(jpath)
48+
val files = fileStream.toArray(size => new Array[JPath](size))
49+
fileStream.close()
50+
files.iterator.map(Path.apply)
5551
}
52+
else Iterator.empty
5653

5754
def dirs: Iterator[Directory] = list collect { case x: Directory => x }
5855
def files: Iterator[File] = list collect { case x: File => x }

compiler/src/dotty/tools/io/File.scala

+6-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import java.io.{
1212
FileInputStream, FileOutputStream, BufferedWriter, OutputStreamWriter,
1313
BufferedOutputStream, IOException, PrintWriter
1414
}
15-
import java.nio.file.Files
15+
import java.nio.file.{Files, Paths}
1616
import java.nio.file.StandardOpenOption._
1717

1818
import scala.io.Codec
@@ -22,14 +22,9 @@ import scala.io.Codec
2222
object File {
2323
def pathSeparator = java.io.File.pathSeparator
2424
def separator = java.io.File.separator
25-
def apply(path: Path)(implicit codec: Codec) = new File(path.jpath)(codec)
2625

27-
// Create a temporary file, which will be deleted upon jvm exit.
28-
def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) = {
29-
val jfile = java.io.File.createTempFile(prefix, suffix, dir)
30-
jfile.deleteOnExit()
31-
apply(jfile)
32-
}
26+
def apply(path: String)(implicit codec: Codec): File = apply(Paths.get(path))
27+
def apply(path: JPath)(implicit codec: Codec): File = new File(path)
3328
}
3429

3530
/** An abstraction for files. For character data, a Codec
@@ -59,9 +54,9 @@ class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) w
5954
def inputStream() = Files.newInputStream(jpath)
6055

6156
/** Obtains a OutputStream. */
62-
def outputStream(append: Boolean = false) =
63-
if (append) Files.newOutputStream(jpath, APPEND)
64-
else Files.newOutputStream(jpath)
57+
def outputStream(append: Boolean = false) =
58+
if (append) Files.newOutputStream(jpath, CREATE, APPEND)
59+
else Files.newOutputStream(jpath, CREATE, TRUNCATE_EXISTING)
6560
def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append))
6661

6762
/** Obtains an OutputStreamWriter wrapped around a FileOutputStream.

compiler/src/dotty/tools/io/Jar.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import scala.annotation.tailrec
3535
// static Attributes.Name SPECIFICATION_VERSION
3636

3737
class Jar(file: File) extends Iterable[JarEntry] {
38-
def this(jfile: JFile) = this(File(jfile))
38+
def this(jfile: JFile) = this(File(jfile.toPath))
3939
def this(path: String) = this(File(path))
4040

4141
protected def errorFn(msg: String): Unit = Console println msg

compiler/src/dotty/tools/io/JarFS.scala

+1-21
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class JarFS private (private[this] var jarFS: FileSystem) {
1212

1313
def getRoot(): AbstractFile = {
1414
val root = jarFS.getRootDirectories.iterator().next()
15-
new JarFS.JarDirectory(root)(jarFS)
15+
new PlainDirectory(Directory(root))
1616
}
1717

1818
def close() = {
@@ -22,30 +22,10 @@ class JarFS private (private[this] var jarFS: FileSystem) {
2222
}
2323

2424
object JarFS {
25-
2625
def create(path: Path): JarFS = {
2726
assert(path.extension == "jar")
2827
val env = Map("create" -> "true").asJava
2928
val jarUri = java.net.URI.create("jar:file:" + path.toAbsolute.path)
3029
new JarFS(FileSystems.newFileSystem(jarUri, env))
3130
}
32-
33-
private class JarDirectory(path: JPath)(jarFS: FileSystem) extends PlainDirectory(new Directory(path)) {
34-
override def name = "<jar-dir>"
35-
override def file = throw new UnsupportedOperationException
36-
override def fileNamed(name: String): AbstractFile = new JarFile(pathTo(name))
37-
override def subdirectoryNamed(name: String): AbstractFile = new JarDirectory(pathTo(name))(jarFS)
38-
private def pathTo(name: String): JPath =
39-
jarFS.getPath(if (path.toString == "/") name else path.resolve(name).toString)
40-
}
41-
42-
private class JarFile(path: JPath) extends PlainFile(new File(path)) {
43-
override def name = "<jar-file>"
44-
override def file = throw new UnsupportedOperationException
45-
override def output = {
46-
if (path.getParent ne null)
47-
Files.createDirectories(path.getParent)
48-
Files.newOutputStream(path)
49-
}
50-
}
5131
}

compiler/src/dotty/tools/io/Path.scala

+13-23
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ object Path {
4747
else name.substring(i + 1).toLowerCase
4848
}
4949

50-
// not certain these won't be problematic, but looks good so far
51-
implicit def string2path(s: String): Path = apply(s)
52-
implicit def jfile2path(jfile: JFile): Path = apply(jfile.toPath)
53-
5450
def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
5551
def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
5652
def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile)
@@ -95,6 +91,7 @@ class Path private[io] (val jpath: JPath) {
9591
/** Creates a new Path with the specified path appended. Assumes
9692
* the type of the new component implies the type of the result.
9793
*/
94+
def /(child: String): Path = new Path(jpath.resolve(child))
9895
def /(child: Path): Path = resolve(child)
9996
def /(child: Directory): Directory = /(child: Path).toDirectory
10097
def /(child: File): File = /(child: Path).toFile
@@ -117,31 +114,24 @@ class Path private[io] (val jpath: JPath) {
117114
def walk: Iterator[Path] = walkFilter(_ => true)
118115

119116
// identity
120-
def name: String = jpath.getFileName().toString
117+
def name: String = jpath.getFileName() match {
118+
case null => ""
119+
case name => name.toString
120+
}
121121
def path: String = jpath.toString
122-
def normalize: Path = Path(jpath.normalize)
122+
def normalize: Path = new Path(jpath.normalize)
123123

124-
def resolve(other: Path) = Path(jpath.resolve(other.jpath))
125-
def relativize(other: Path) = Path(jpath.relativize(other.jpath))
124+
def resolve(other: Path) = new Path(jpath.resolve(other.jpath))
125+
def relativize(other: Path) = new Path(jpath.relativize(other.jpath))
126126

127127
def segments: List[String] = (path split separator).toList filterNot (_.length == 0)
128128

129129
/**
130130
* @return The path of the parent directory, or root if path is already root
131131
*/
132-
def parent: Directory = path match {
133-
case "" | "." => Directory("..")
134-
case _ =>
135-
// the only solution <-- a comment which could have used elaboration
136-
if (segments.nonEmpty && segments.last == "..")
137-
(path / "..").toDirectory
138-
else jpath.getParent match {
139-
case null =>
140-
if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root
141-
else Directory(".") // a dir under pwd
142-
case x =>
143-
Directory(x)
144-
}
132+
def parent: Directory = jpath.normalize.getParent match {
133+
case null => Directory(jpath)
134+
case parent => Directory(parent)
145135
}
146136
def parents: List[Directory] = {
147137
val p = parent
@@ -164,12 +154,12 @@ class Path private[io] (val jpath: JPath) {
164154
// returns the filename without the extension.
165155
def stripExtension: String = name stripSuffix ("." + extension)
166156
// returns the Path with the extension.
167-
def addExtension(ext: String): Path = Path(path + "." + ext)
157+
def addExtension(ext: String): Path = new Path(jpath.resolveSibling(name + ext))
168158
// changes the existing extension out for a new one, or adds it
169159
// if the current path has none.
170160
def changeExtension(ext: String): Path =
171161
if (extension == "") addExtension(ext)
172-
else Path(path.stripSuffix(extension) + ext)
162+
else new Path(jpath.resolveSibling(stripExtension + "." + ext))
173163

174164
// conditionally execute
175165
def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None

compiler/src/dotty/tools/io/PlainFile.scala

+5-6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
2222
class PlainFile(val givenPath: Path) extends AbstractFile {
2323
assert(path ne null)
2424

25-
val jpath = givenPath.jpath
25+
def jpath = givenPath.jpath
2626
override def underlyingSource = Some(this)
2727

2828
private val fpath = givenPath.toAbsolute
@@ -37,8 +37,8 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
3737
def absolute = new PlainFile(givenPath.toAbsolute)
3838

3939
override def container: AbstractFile = new PlainFile(givenPath.parent)
40-
override def input = Files.newInputStream(jpath)
41-
override def output = Files.newOutputStream(jpath)
40+
override def input = givenPath.toFile.inputStream()
41+
override def output = givenPath.toFile.outputStream()
4242
override def sizeOption = Some(givenPath.length.toInt)
4343

4444
override def hashCode(): Int = fpath.hashCode()
@@ -58,11 +58,10 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
5858
// Optimization: Assume that the file was not deleted and did not have permissions changed
5959
// between the call to `list` and the iteration. This saves a call to `exists`.
6060
def existsFast(path: Path) = path match {
61-
case (_: Directory | _: io.File) => true
61+
case (_: Directory | _: File) => true
6262
case _ => path.exists
6363
}
64-
if (!isDirectory) Iterator.empty
65-
else givenPath.toDirectory.list filter existsFast map (new PlainFile(_))
64+
givenPath.toDirectory.list.filter(existsFast).map(new PlainFile(_))
6665
}
6766

6867
/**

compiler/src/dotty/tools/repl/ReplDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class ReplDriver(settings: Array[String],
111111
else {
112112
val path = rootCtx.settings.outputDir.value(rootCtx)
113113
assert(path.isDirectory)
114-
new PlainDirectory(Directory(path))
114+
new PlainDirectory(path.toDirectory)
115115
}
116116
}
117117
compiler = new ReplCompiler(outDir)

0 commit comments

Comments
 (0)