From 32b0a5bacbf8e7db5901fa9239fad1e72340b4b4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 27 Oct 2017 16:13:56 +0200 Subject: [PATCH 01/11] Use nio.Path instead of io.File to properly support PlainNioFile --- .../dotc/classpath/DirectoryClassPath.scala | 6 +- .../src/dotty/tools/io/AbstractFile.scala | 30 +++++-- compiler/src/dotty/tools/io/Directory.scala | 4 +- compiler/src/dotty/tools/io/File.scala | 6 +- .../src/dotty/tools/io/NoAbstractFile.scala | 2 +- compiler/src/dotty/tools/io/Path.scala | 89 ++++++++++--------- compiler/src/dotty/tools/io/PlainFile.scala | 13 +-- .../src/dotty/tools/io/VirtualDirectory.scala | 2 +- compiler/src/dotty/tools/io/VirtualFile.scala | 2 +- compiler/src/dotty/tools/io/ZipArchive.scala | 4 +- compiler/src/dotty/tools/io/package.scala | 1 + 11 files changed, 89 insertions(+), 70 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala index 91620151bbb6..20b798dea105 100644 --- a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala @@ -119,7 +119,7 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo } else Array() } protected def getName(f: File): String = f.getName - protected def toAbstractFile(f: File): AbstractFile = new PlainFile(new dotty.tools.io.File(f)) + protected def toAbstractFile(f: File): AbstractFile = new PlainFile(new dotty.tools.io.File(f.toPath)) protected def isPackage(f: File): Boolean = f.isPackage assert(dir != null, "Directory file in DirectoryFileLookup cannot be null") @@ -212,7 +212,7 @@ case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileE val relativePath = FileUtils.dirPath(className) val classFile = new File(s"$dir/$relativePath.class") if (classFile.exists) { - val wrappedClassFile = new dotty.tools.io.File(classFile) + val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) val abstractClassFile = new PlainFile(wrappedClassFile) Some(abstractClassFile) } else None @@ -239,7 +239,7 @@ case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFil .collectFirst { case file if file.exists() => file } sourceFile.map { file => - val wrappedSourceFile = new dotty.tools.io.File(file) + val wrappedSourceFile = new dotty.tools.io.File(file.toPath) val abstractSourceFile = new PlainFile(wrappedSourceFile) abstractSourceFile } diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index c151739cdc31..19b2a64048ee 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -10,6 +10,7 @@ import java.io.{ ByteArrayOutputStream } import java.net.URL +import java.nio.file.{FileAlreadyExistsException, Files} /** * An abstraction over files for use in the reflection/compiler libraries. @@ -94,7 +95,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { def path: String /** Returns the path of this abstract file in a canonical form. */ - def canonicalPath: String = if (file == null) path else file.getCanonicalPath + def canonicalPath: String = if (jpath == null) path else jpath.toFile.getCanonicalPath /** Checks extension case insensitively. */ def hasExtension(other: String) = extension == other.toLowerCase @@ -107,18 +108,26 @@ abstract class AbstractFile extends Iterable[AbstractFile] { def container : AbstractFile /** Returns the underlying File if any and null otherwise. */ - def file: JFile + def file: JFile = try { + if (jpath == null) null + else jpath.toFile + } catch { + case _: UnsupportedOperationException => null + } + + /** Returns the underlying Path if any and null otherwise. */ + def jpath: JPath /** An underlying source, if known. Mostly, a zip/jar file. */ def underlyingSource: Option[AbstractFile] = None /** Does this abstract file denote an existing file? */ def exists: Boolean = { - (file eq null) || file.exists + (jpath eq null) || Files.exists(jpath) } /** Does this abstract file represent something which can contain classfiles? */ - def isClassContainer = isDirectory || (file != null && (extension == "jar" || extension == "zip")) + def isClassContainer = isDirectory || (jpath != null && (extension == "jar" || extension == "zip")) /** Create a file on disk, if one does not exist already. */ def create(): Unit @@ -147,7 +156,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { /** size of this file if it is a concrete file. */ def sizeOption: Option[Int] = None - def toURL: URL = if (file == null) null else file.toURI.toURL + def toURL: URL = if (jpath == null) null else jpath.toUri.toURL /** Returns contents of file (if applicable) in a Char array. * warning: use `Global.getSourceFile()` to use the proper @@ -232,9 +241,14 @@ abstract class AbstractFile extends Iterable[AbstractFile] { val lookup = lookupName(name, isDir) if (lookup != null) lookup else { - val jfile = new JFile(file, name) - if (isDir) jfile.mkdirs() else jfile.createNewFile() - new PlainFile(jfile) + val path = jpath.resolve(name) + try { + if (isDir) Files.createDirectories(path) + else Files.createFile(path) + } catch { + case _: FileAlreadyExistsException => + } + new PlainNioFile(path) } } diff --git a/compiler/src/dotty/tools/io/Directory.scala b/compiler/src/dotty/tools/io/Directory.scala index 6c23fd413194..ba3f32454741 100644 --- a/compiler/src/dotty/tools/io/Directory.scala +++ b/compiler/src/dotty/tools/io/Directory.scala @@ -34,10 +34,10 @@ object Directory { * * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ -class Directory(jfile: JFile) extends Path(jfile) { +class Directory(jpath: JPath) extends Path(jpath) { override def toAbsolute: Directory = if (isAbsolute) this else super.toAbsolute.toDirectory override def toDirectory: Directory = this - override def toFile: File = new File(jfile) + override def toFile: File = new File(jpath) override def normalize: Directory = super.normalize.toDirectory /** An iterator over the contents of this directory. diff --git a/compiler/src/dotty/tools/io/File.scala b/compiler/src/dotty/tools/io/File.scala index 61dcb1a1b6e0..f95ed414134d 100644 --- a/compiler/src/dotty/tools/io/File.scala +++ b/compiler/src/dotty/tools/io/File.scala @@ -20,7 +20,7 @@ import scala.io.Codec object File { def pathSeparator = java.io.File.pathSeparator def separator = java.io.File.separator - def apply(path: Path)(implicit codec: Codec) = new File(path.jfile)(codec) + def apply(path: Path)(implicit codec: Codec) = new File(path.jpath)(codec) // Create a temporary file, which will be deleted upon jvm exit. def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) = { @@ -41,12 +41,12 @@ object File { * * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ -class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars { +class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) with Streamable.Chars { override val creationCodec = constructorCodec override def addExtension(ext: String): File = super.addExtension(ext).toFile override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile - override def toDirectory: Directory = new Directory(jfile) + override def toDirectory: Directory = new Directory(jfile.toPath) override def toFile: File = this override def normalize: File = super.normalize.toFile override def length = super[Path].length diff --git a/compiler/src/dotty/tools/io/NoAbstractFile.scala b/compiler/src/dotty/tools/io/NoAbstractFile.scala index 3b2bbeb58022..3ba5eaff7d3f 100644 --- a/compiler/src/dotty/tools/io/NoAbstractFile.scala +++ b/compiler/src/dotty/tools/io/NoAbstractFile.scala @@ -17,7 +17,7 @@ object NoAbstractFile extends AbstractFile { def container: AbstractFile = this def create(): Unit = ??? def delete(): Unit = ??? - def file: java.io.File = null + def jpath: JPath = null def input: InputStream = null def isDirectory: Boolean = false override def isVirtual: Boolean = true diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index 034360a67515..a7b806e2c740 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -6,9 +6,10 @@ package dotty.tools.io import scala.language.implicitConversions - import java.io.RandomAccessFile -import java.net.{ URI, URL } +import java.nio.file.{FileAlreadyExistsException, Files} +import java.net.{URI, URL} + import scala.util.Random.alphanumeric /** An abstraction for filesystem paths. The differences between @@ -54,10 +55,10 @@ object Path { def apply(path: String): Path = apply(new JFile(path)) def apply(jfile: JFile): Path = try { - if (jfile.isFile) new File(jfile) - else if (jfile.isDirectory) new Directory(jfile) - else new Path(jfile) - } catch { case ex: SecurityException => new Path(jfile) } + if (jfile.isFile) new File(jfile.toPath) + else if (jfile.isDirectory) new Directory(jfile.toPath) + else new Path(jfile.toPath) + } catch { case ex: SecurityException => new Path(jfile.toPath) } /** Avoiding any shell/path issues by only using alphanumerics. */ private[io] def randomPrefix = alphanumeric take 6 mkString "" @@ -70,16 +71,16 @@ import Path._ * * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ -class Path private[io] (val jfile: JFile) { +class Path private[io] (val jpath: JPath) { val separator = java.io.File.separatorChar val separatorStr = java.io.File.separator // conversions - def toFile: File = new File(jfile) - def toDirectory: Directory = new Directory(jfile) - def toAbsolute: Path = if (isAbsolute) this else Path(jfile.getAbsolutePath()) + def toFile: File = new File(jpath) + def toDirectory: Directory = new Directory(jpath) + def toAbsolute: Path = if (isAbsolute) this else new Path(jpath.toAbsolutePath) def toCanonical: Path = Path(jfile.getCanonicalPath()) - def toURI: URI = jfile.toURI() + def toURI: URI = jpath.toUri() def toURL: URL = toURI.toURL() /** If this path is absolute, returns it: otherwise, returns an absolute @@ -90,7 +91,7 @@ class Path private[io] (val jfile: JFile) { /** 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 = if (isEmpty) child else new Path(new JFile(jfile, child.path)) + def /(child: Path): Path = if (isEmpty) child else new Path(jpath.resolve(child.path)) def /(child: Directory): Directory = /(child: Path).toDirectory def /(child: File): File = /(child: Path).toFile @@ -111,9 +112,11 @@ class Path private[io] (val jfile: JFile) { */ def walk: Iterator[Path] = walkFilter(_ => true) + def jfile: JFile = jpath.toFile + // identity - def name: String = jfile.getName() - def path: String = jfile.getPath() + def name: String = jpath.getFileName().toString + def path: String = jpath.toString def normalize: Path = Path(jfile.getAbsolutePath()) def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other) @@ -141,12 +144,12 @@ class Path private[io] (val jfile: JFile) { // the only solution <-- a comment which could have used elaboration if (segments.nonEmpty && segments.last == "..") (path / "..").toDirectory - else jfile.getParent match { + else jpath.getParent match { case null => if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root else Directory(".") // a dir under pwd case x => - Directory(x) + Directory(x.toFile) } } def parents: List[Directory] = { @@ -173,62 +176,68 @@ class Path private[io] (val jfile: JFile) { def addExtension(ext: String): Path = Path(path + "." + ext) // changes the existing extension out for a new one, or adds it // if the current path has none. - def changeExtension(ext: String): Path = ( + def changeExtension(ext: String): Path = if (extension == "") addExtension(ext) else Path(path.stripSuffix(extension) + ext) - ) // conditionally execute def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None def ifDirectory[T](f: Directory => T): Option[T] = if (isDirectory) Some(f(toDirectory)) else None // Boolean tests - def canRead = jfile.canRead() - def canWrite = jfile.canWrite() - def exists = try jfile.exists() catch { case ex: SecurityException => false } - def isFile = try jfile.isFile() catch { case ex: SecurityException => false } + def canRead = Files.isReadable(jpath) + def canWrite = Files.isWritable(jpath) + def exists = try Files.exists(jpath) catch { case ex: SecurityException => false } + def isFile = try Files.isRegularFile(jpath) catch { case ex: SecurityException => false } def isDirectory = - try jfile.isDirectory() - catch { case ex: SecurityException => jfile.getPath == "." } - def isAbsolute = jfile.isAbsolute() + try Files.isDirectory(jpath) + catch { case ex: SecurityException => jpath.toString == "." } + def isAbsolute = jpath.isAbsolute() def isEmpty = path.length == 0 // Information - def lastModified = jfile.lastModified() - def length = jfile.length() + def lastModified = Files.getLastModifiedTime(jpath) + def length = Files.size(jpath) // Boolean path comparisons def endsWith(other: Path) = segments endsWith other.segments def isSame(other: Path) = toCanonical == other.toCanonical - def isFresher(other: Path) = lastModified > other.lastModified + def isFresher(other: Path) = lastModified.compareTo(other.lastModified) > 0 // creations def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = { - val res = if (force) jfile.mkdirs() else jfile.mkdir() + val res = try { + if (force) Files.createDirectories(jpath) else Files.createDirectory(jpath) + true + } catch { + case _: FileAlreadyExistsException => false + } if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name) else if (isDirectory) toDirectory - else new Directory(jfile) + else new Directory(jpath) } def createFile(failIfExists: Boolean = false): File = { - val res = jfile.createNewFile() + val res = try { Files.createFile(jpath); true } catch { case e: FileAlreadyExistsException => false} if (!res && failIfExists && exists) fail("File '%s' already exists." format name) else if (isFile) toFile - else new File(jfile) + else new File(jpath) } // deletions - def delete() = jfile.delete() + def delete(): Unit = Files.delete(jpath) /** Deletes the path recursively. Returns false on failure. * Use with caution! */ - def deleteRecursively(): Boolean = deleteRecursively(jfile) - private def deleteRecursively(f: JFile): Boolean = { - if (f.isDirectory) f.listFiles match { - case null => - case xs => xs foreach deleteRecursively - } - f.delete() + def deleteRecursively(): Boolean = deleteRecursively(jpath) + private def deleteRecursively(p: JPath): Boolean = { + import scala.collection.JavaConverters._ + if (Files.isDirectory(p)) + Files.list(p).iterator().asScala.foreach(deleteRecursively) + try { + Files.delete(p) + true + } catch { case _: Throwable => false } } def truncate() = diff --git a/compiler/src/dotty/tools/io/PlainFile.scala b/compiler/src/dotty/tools/io/PlainFile.scala index 76de56c11f01..a5164bec8818 100644 --- a/compiler/src/dotty/tools/io/PlainFile.scala +++ b/compiler/src/dotty/tools/io/PlainFile.scala @@ -20,7 +20,7 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { class PlainFile(val givenPath: Path) extends AbstractFile { assert(path ne null) - val file = givenPath.jfile + val jpath = givenPath.jpath override def underlyingSource = Some(this) private val fpath = givenPath.toAbsolute @@ -49,7 +49,7 @@ class PlainFile(val givenPath: Path) extends AbstractFile { def isDirectory: Boolean = givenPath.isDirectory /** Returns the time that this abstract file was last modified. */ - def lastModified: Long = givenPath.lastModified + def lastModified: Long = givenPath.lastModified.toMillis /** Returns all abstract subfiles of this abstract directory. */ def iterator: Iterator[AbstractFile] = { @@ -95,12 +95,7 @@ private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractF 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 - } + def jpath = nioPath override def underlyingSource = Some(this) @@ -160,7 +155,7 @@ private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractF /** 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() + else if (Files.isDirectory(nioPath)) new Directory(nioPath).deleteRecursively() /** Returns a plain file with the given name. It does not * check that it exists. diff --git a/compiler/src/dotty/tools/io/VirtualDirectory.scala b/compiler/src/dotty/tools/io/VirtualDirectory.scala index d3e4ebb4dee3..b32eb78541ad 100644 --- a/compiler/src/dotty/tools/io/VirtualDirectory.scala +++ b/compiler/src/dotty/tools/io/VirtualDirectory.scala @@ -28,7 +28,7 @@ extends AbstractFile { override def isVirtual = true val lastModified: Long = System.currentTimeMillis - override def file = null + override def jpath = null override def input = sys.error("directories cannot be read") override def output = sys.error("directories cannot be written") diff --git a/compiler/src/dotty/tools/io/VirtualFile.scala b/compiler/src/dotty/tools/io/VirtualFile.scala index be2c6902cd39..5708b67607c7 100644 --- a/compiler/src/dotty/tools/io/VirtualFile.scala +++ b/compiler/src/dotty/tools/io/VirtualFile.scala @@ -35,7 +35,7 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF def absolute = this /** Returns null. */ - def file: JFile = null + def jpath: JPath = null override def sizeOption: Option[Int] = Some(content.length) diff --git a/compiler/src/dotty/tools/io/ZipArchive.scala b/compiler/src/dotty/tools/io/ZipArchive.scala index 786163242b55..5a6be642ab2b 100644 --- a/compiler/src/dotty/tools/io/ZipArchive.scala +++ b/compiler/src/dotty/tools/io/ZipArchive.scala @@ -54,7 +54,7 @@ object ZipArchive { } import ZipArchive._ /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ -abstract class ZipArchive(override val file: JFile) extends AbstractFile with Equals { +abstract class ZipArchive(override val jpath: JPath) extends AbstractFile with Equals { self => override def underlyingSource = Some(this) @@ -112,7 +112,7 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq } } /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ -final class FileZipArchive(file: JFile) extends ZipArchive(file) { +final class FileZipArchive(file: JFile) extends ZipArchive(file.toPath) { private[this] def openZipFile(): ZipFile = try { new ZipFile(file) } catch { diff --git a/compiler/src/dotty/tools/io/package.scala b/compiler/src/dotty/tools/io/package.scala index 7201bf0eb216..19bb6e4ad19b 100644 --- a/compiler/src/dotty/tools/io/package.scala +++ b/compiler/src/dotty/tools/io/package.scala @@ -8,4 +8,5 @@ package dotty.tools package object io { type JManifest = java.util.jar.Manifest type JFile = java.io.File + type JPath = java.nio.file.Path } From aeec4292761b8fdf2a5976ccd8615f6c0db132bf Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 27 Oct 2017 16:57:41 +0200 Subject: [PATCH 02/11] Fix creation and deletion methods --- compiler/src/dotty/tools/io/Path.scala | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index a7b806e2c740..47daa07d71f2 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -7,7 +7,7 @@ package dotty.tools.io import scala.language.implicitConversions import java.io.RandomAccessFile -import java.nio.file.{FileAlreadyExistsException, Files} +import java.nio.file.{DirectoryNotEmptyException, FileAlreadyExistsException, Files, NoSuchFileException} import java.net.{URI, URL} import scala.util.Random.alphanumeric @@ -206,25 +206,23 @@ class Path private[io] (val jpath: JPath) { // creations def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = { - val res = try { - if (force) Files.createDirectories(jpath) else Files.createDirectory(jpath) - true - } catch { - case _: FileAlreadyExistsException => false - } + val res = tryCreate(if (force) Files.createDirectories(jpath) else Files.createDirectory(jpath)) if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name) else if (isDirectory) toDirectory else new Directory(jpath) } def createFile(failIfExists: Boolean = false): File = { - val res = try { Files.createFile(jpath); true } catch { case e: FileAlreadyExistsException => false} + val res = tryCreate(Files.createFile(jpath)) if (!res && failIfExists && exists) fail("File '%s' already exists." format name) else if (isFile) toFile else new File(jpath) } + private def tryCreate(create: => JPath): Boolean = + try { create; true } catch { case _: FileAlreadyExistsException => false } + // deletions - def delete(): Unit = Files.delete(jpath) + def delete(): Unit = delete(jpath) /** Deletes the path recursively. Returns false on failure. * Use with caution! @@ -234,12 +232,12 @@ class Path private[io] (val jpath: JPath) { import scala.collection.JavaConverters._ if (Files.isDirectory(p)) Files.list(p).iterator().asScala.foreach(deleteRecursively) - try { - Files.delete(p) - true - } catch { case _: Throwable => false } + delete(p) } + private def delete(path: JPath): Boolean = + try { Files.delete(path); true } catch { case _: DirectoryNotEmptyException | _: NoSuchFileException => false } + def truncate() = isFile && { val raf = new RandomAccessFile(jfile, "rw") From aced7e004b2eb8b2e649432e943c101a549b94a7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 27 Oct 2017 17:18:37 +0200 Subject: [PATCH 03/11] Fix nio.Path in dotty doc and ensure that its compilation is tested --- doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index 0f273f5c9f09..bc304cbc204f 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -409,7 +409,7 @@ case class Site( } private def toSourceFile(f: JFile): SourceFile = - SourceFile(AbstractFile.getFile(new File(f)), Source.fromFile(f).toArray) + SourceFile(AbstractFile.getFile(new File(f.toPath)), Source.fromFile(f).toArray) private def collectFiles(dir: JFile, includes: String => Boolean): Array[JFile] = dir From 7ff1cb6fbc6261a364481be597b20a17423f4d72 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 1 Nov 2017 17:16:15 +0100 Subject: [PATCH 04/11] Fixes and more translations --- .../dotc/classpath/ZipArchiveFileLookup.scala | 2 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 6 ++--- .../tools/dotc/sbt/ExtractDependencies.scala | 10 ++++---- .../src/dotty/tools/io/AbstractFile.scala | 11 ++++----- compiler/src/dotty/tools/io/Directory.scala | 16 +++++++++---- compiler/src/dotty/tools/io/File.scala | 2 +- compiler/src/dotty/tools/io/Path.scala | 23 ++++++++++--------- compiler/src/dotty/tools/io/PlainFile.scala | 20 ++++++++-------- compiler/src/dotty/tools/io/ZipArchive.scala | 19 +++++++-------- 9 files changed, 58 insertions(+), 51 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala b/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala index 2b7d039a6bb9..77f628c673d4 100644 --- a/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala +++ b/compiler/src/dotty/tools/dotc/classpath/ZipArchiveFileLookup.scala @@ -23,7 +23,7 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepresentation] extends ClassPa override def asURLs: Seq[URL] = Seq(zipFile.toURI.toURL) override def asClassPathStrings: Seq[String] = Seq(zipFile.getPath) - private val archive = new FileZipArchive(zipFile) + private val archive = new FileZipArchive(zipFile.toPath) override private[dotty] def packages(inPackage: String): Seq[PackageEntry] = { val prefix = PackageNameUtils.packagePrefix(inPackage) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index a8c3667d8992..532aef36b723 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -45,13 +45,13 @@ class ExtractAPI extends Phase { val dumpInc = ctx.settings.YdumpSbtInc.value val forceRun = dumpInc || ctx.settings.YforceSbtPhases.value if ((ctx.sbtCallback != null || forceRun) && !unit.isJava) { - val sourceFile = unit.source.file.file + val sourceFile = unit.source.file val apiTraverser = new ExtractAPICollector val source = apiTraverser.apiSource(unit.tpdTree) if (dumpInc) { // Append to existing file that should have been created by ExtractDependencies - val pw = new PrintWriter(Path(sourceFile).changeExtension("inc").toFile + val pw = new PrintWriter(Path(sourceFile.jpath).changeExtension("inc").toFile .bufferedWriter(append = true), true) try { pw.println(DefaultShowAPI(source)) @@ -59,7 +59,7 @@ class ExtractAPI extends Phase { } if (ctx.sbtCallback != null) - ctx.sbtCallback.api(sourceFile, source) + ctx.sbtCallback.api(sourceFile.file, source) } } } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 5992fe350c7d..32b9827e8535 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -47,7 +47,7 @@ class ExtractDependencies extends Phase { val dumpInc = ctx.settings.YdumpSbtInc.value val forceRun = dumpInc || ctx.settings.YforceSbtPhases.value if ((ctx.sbtCallback != null || forceRun) && !unit.isJava) { - val sourceFile = unit.source.file.file + val sourceFile = unit.source.file val extractDeps = new ExtractDependenciesCollector extractDeps.traverse(unit.tpdTree) @@ -59,7 +59,7 @@ class ExtractDependencies extends Phase { Arrays.sort(deps) Arrays.sort(inhDeps) - val pw = Path(sourceFile).changeExtension("inc").toFile.printWriter() + val pw = Path(sourceFile.jpath).changeExtension("inc").toFile.printWriter() try { pw.println(s"// usedNames: ${names.mkString(",")}") pw.println(s"// topLevelDependencies: ${deps.mkString(",")}") @@ -69,11 +69,11 @@ class ExtractDependencies extends Phase { if (ctx.sbtCallback != null) { extractDeps.usedNames.foreach(name => - ctx.sbtCallback.usedName(sourceFile, name.toString)) + ctx.sbtCallback.usedName(sourceFile.file, name.toString)) extractDeps.topLevelDependencies.foreach(dep => - recordDependency(sourceFile, dep, DependencyContext.DependencyByMemberRef)) + recordDependency(sourceFile.file, dep, DependencyContext.DependencyByMemberRef)) extractDeps.topLevelInheritanceDependencies.foreach(dep => - recordDependency(sourceFile, dep, DependencyContext.DependencyByInheritance)) + recordDependency(sourceFile.file, dep, DependencyContext.DependencyByInheritance)) } } } diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index 19b2a64048ee..b58412e144ab 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -95,7 +95,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { def path: String /** Returns the path of this abstract file in a canonical form. */ - def canonicalPath: String = if (jpath == null) path else jpath.toFile.getCanonicalPath + def canonicalPath: String = if (jpath == null) path else jpath.normalize.toString /** Checks extension case insensitively. */ def hasExtension(other: String) = extension == other.toLowerCase @@ -241,13 +241,10 @@ abstract class AbstractFile extends Iterable[AbstractFile] { val lookup = lookupName(name, isDir) if (lookup != null) lookup else { + Files.createDirectories(jpath) val path = jpath.resolve(name) - try { - if (isDir) Files.createDirectories(path) - else Files.createFile(path) - } catch { - case _: FileAlreadyExistsException => - } + if (isDir) Files.createDirectory(path) + else Files.createFile(path) new PlainNioFile(path) } } diff --git a/compiler/src/dotty/tools/io/Directory.scala b/compiler/src/dotty/tools/io/Directory.scala index ba3f32454741..0eaa52c071de 100644 --- a/compiler/src/dotty/tools/io/Directory.scala +++ b/compiler/src/dotty/tools/io/Directory.scala @@ -8,6 +8,11 @@ package dotty.tools.io +import java.nio.file.Files +import java.util.stream.Collectors + +import scala.collection.JavaConverters._ + /** * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ @@ -18,6 +23,7 @@ object Directory { def Current: Option[Directory] = if (userDir == "") None else normalizePath(userDir) def apply(path: Path): Directory = path.toDirectory + def apply(jpath: JPath): Directory = new Directory(jpath) // Like File.makeTemp but creates a directory instead def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null): Directory = { @@ -42,11 +48,13 @@ class Directory(jpath: JPath) extends Path(jpath) { /** An iterator over the contents of this directory. */ - def list: Iterator[Path] = - jfile.listFiles match { - case null => Iterator.empty - case xs => xs.iterator map Path.apply + def list: Iterator[Path] = { + try { + Files.list(jpath).toArray[JPath](n => new Array(n)).iterator.map(Path.apply) + } catch { + case _: java.nio.file.NoSuchFileException => Iterator.empty } + } def dirs: Iterator[Directory] = list collect { case x: Directory => x } def files: Iterator[File] = list collect { case x: File => x } diff --git a/compiler/src/dotty/tools/io/File.scala b/compiler/src/dotty/tools/io/File.scala index f95ed414134d..10348e2a6aaa 100644 --- a/compiler/src/dotty/tools/io/File.scala +++ b/compiler/src/dotty/tools/io/File.scala @@ -46,7 +46,7 @@ class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) w override def addExtension(ext: String): File = super.addExtension(ext).toFile override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile - override def toDirectory: Directory = new Directory(jfile.toPath) + override def toDirectory: Directory = new Directory(jpath) override def toFile: File = this override def normalize: File = super.normalize.toFile override def length = super[Path].length diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index 47daa07d71f2..4e44b035293b 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -7,7 +7,7 @@ package dotty.tools.io import scala.language.implicitConversions import java.io.RandomAccessFile -import java.nio.file.{DirectoryNotEmptyException, FileAlreadyExistsException, Files, NoSuchFileException} +import java.nio.file.{DirectoryNotEmptyException, FileAlreadyExistsException, Files, NoSuchFileException, Paths} import java.net.{URI, URL} import scala.util.Random.alphanumeric @@ -45,20 +45,20 @@ 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) + implicit def jfile2path(jfile: JFile): Path = apply(jfile.toPath) def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory) def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory) def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile) - def roots: List[Path] = java.io.File.listRoots().toList map Path.apply + def roots: List[Path] = java.io.File.listRoots().toList.map(r => Path.apply(r.toPath)) - def apply(path: String): Path = apply(new JFile(path)) - def apply(jfile: JFile): Path = try { - if (jfile.isFile) new File(jfile.toPath) - else if (jfile.isDirectory) new Directory(jfile.toPath) - else new Path(jfile.toPath) - } catch { case ex: SecurityException => new Path(jfile.toPath) } + def apply(path: String): Path = apply(Paths.get(path)) + def apply(jpath: JPath): Path = try { + if (Files.isRegularFile(jpath)) new File(jpath) + else if (Files.isDirectory(jpath)) new Directory(jpath) + else new Path(jpath) + } catch { case ex: SecurityException => new Path(jpath) } /** Avoiding any shell/path issues by only using alphanumerics. */ private[io] def randomPrefix = alphanumeric take 6 mkString "" @@ -149,7 +149,7 @@ class Path private[io] (val jpath: JPath) { if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root else Directory(".") // a dir under pwd case x => - Directory(x.toFile) + Directory(x) } } def parents: List[Directory] = { @@ -213,6 +213,7 @@ class Path private[io] (val jpath: JPath) { } def createFile(failIfExists: Boolean = false): File = { val res = tryCreate(Files.createFile(jpath)) + jfile.createNewFile() if (!res && failIfExists && exists) fail("File '%s' already exists." format name) else if (isFile) toFile else new File(jpath) @@ -236,7 +237,7 @@ class Path private[io] (val jpath: JPath) { } private def delete(path: JPath): Boolean = - try { Files.delete(path); true } catch { case _: DirectoryNotEmptyException | _: NoSuchFileException => false } + try { Files.deleteIfExists(path); true } catch { case _: DirectoryNotEmptyException => false } def truncate() = isFile && { diff --git a/compiler/src/dotty/tools/io/PlainFile.scala b/compiler/src/dotty/tools/io/PlainFile.scala index a5164bec8818..8c30b31e8d83 100644 --- a/compiler/src/dotty/tools/io/PlainFile.scala +++ b/compiler/src/dotty/tools/io/PlainFile.scala @@ -6,6 +6,8 @@ package dotty.tools package io +import java.nio.file.{Files, NotDirectoryException} + /** ''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 @@ -35,8 +37,8 @@ class PlainFile(val givenPath: Path) extends AbstractFile { 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 input = Files.newInputStream(jpath) + override def output = Files.newOutputStream(jpath) override def sizeOption = Some(givenPath.length.toInt) override def hashCode(): Int = fpath.hashCode() @@ -53,14 +55,13 @@ class PlainFile(val givenPath: Path) extends AbstractFile { /** 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 + try { + import scala.collection.JavaConverters._ + val it = Files.newDirectoryStream(jpath).iterator() + it.asScala.map(new PlainNioFile(_)) + } catch { + case _: NotDirectoryException => Iterator.empty } - if (!isDirectory) Iterator.empty - else givenPath.toDirectory.list filter existsFast map (new PlainFile(_)) } /** @@ -91,7 +92,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile { } private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile { - import java.nio.file._ assert(nioPath ne null) diff --git a/compiler/src/dotty/tools/io/ZipArchive.scala b/compiler/src/dotty/tools/io/ZipArchive.scala index 5a6be642ab2b..6ce3f310992b 100644 --- a/compiler/src/dotty/tools/io/ZipArchive.scala +++ b/compiler/src/dotty/tools/io/ZipArchive.scala @@ -7,6 +7,7 @@ package dotty.tools.io import java.net.URL import java.io.{ IOException, InputStream, ByteArrayInputStream, FilterInputStream } +import java.nio.file.Files import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream } import java.util.jar.Manifest import scala.collection.mutable @@ -32,7 +33,7 @@ object ZipArchive { */ def fromFile(file: File): FileZipArchive = fromFile(file.jfile) def fromFile(file: JFile): FileZipArchive = - try { new FileZipArchive(file) } + try { new FileZipArchive(file.toPath) } catch { case _: IOException => null } def fromManifestURL(url: URL): AbstractFile = new ManifestResources(url) @@ -112,7 +113,7 @@ abstract class ZipArchive(override val jpath: JPath) extends AbstractFile with E } } /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ -final class FileZipArchive(file: JFile) extends ZipArchive(file.toPath) { +final class FileZipArchive(jpath: JPath) extends ZipArchive(jpath) { private[this] def openZipFile(): ZipFile = try { new ZipFile(file) } catch { @@ -182,16 +183,16 @@ final class FileZipArchive(file: JFile) extends ZipArchive(file.toPath) { def iterator: Iterator[Entry] = root.iterator - def name = file.getName - def path = file.getPath - def input = File(file).inputStream() - def lastModified = file.lastModified + def name = jpath.getFileName.toString + def path = jpath.toString + def input = Files.newInputStream(jpath) + def lastModified = Files.getLastModifiedTime(jpath).toMillis - override def sizeOption = Some(file.length.toInt) + override def sizeOption = Some(Files.size(jpath).toInt) override def canEqual(other: Any) = other.isInstanceOf[FileZipArchive] - override def hashCode() = file.hashCode + override def hashCode() = jpath.hashCode override def equals(that: Any) = that match { - case x: FileZipArchive => file.getAbsoluteFile == x.file.getAbsoluteFile + case x: FileZipArchive => jpath.toAbsolutePath == x.jpath.toAbsolutePath case _ => false } } From 92a25cbb389f03e677d11cc94c106e9ecd6a6c56 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 2 Nov 2017 11:55:49 +0100 Subject: [PATCH 05/11] Remove PlainNioFile as it PlainFile is on nio now --- .../dotc/classpath/DirectoryClassPath.scala | 8 +- .../src/dotty/tools/io/AbstractFile.scala | 2 +- compiler/src/dotty/tools/io/PlainFile.scala | 75 +------------------ 3 files changed, 6 insertions(+), 79 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala index 20b798dea105..d8a920482cf7 100644 --- a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala @@ -3,14 +3,14 @@ */ package dotty.tools.dotc.classpath -import java.io.File +import java.io.File // TODO rename to JFile for consistency import java.net.{URI, URL} import java.nio.file.{FileSystems, Files, SimpleFileVisitor} import java.util.function.IntFunction import java.util import java.util.Comparator -import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, PlainNioFile} +import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation} import FileUtils._ import scala.collection.JavaConverters._ @@ -178,7 +178,7 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No else { packageToModuleBases.getOrElse(inPackage, Nil).flatMap(x => Files.list(x.resolve(inPackage.replace('.', '/'))).iterator().asScala.filter(_.getFileName.toString.endsWith(".class"))).map(x => - ClassFileEntryImpl(new PlainNioFile(x))).toVector + ClassFileEntryImpl(new PlainFile(new dotty.tools.io.File(x)))).toVector } } @@ -197,7 +197,7 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No val inPackage = packageOf(className) packageToModuleBases.getOrElse(inPackage, Nil).iterator.flatMap{x => val file = x.resolve(className.replace('.', '/') + ".class") - if (Files.exists(file)) new PlainNioFile(file) :: Nil else Nil + if (Files.exists(file)) new PlainFile(new dotty.tools.io.File(file)) :: Nil else Nil }.take(1).toList.headOption } } diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index b58412e144ab..a8f48d78e87e 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -245,7 +245,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { val path = jpath.resolve(name) if (isDir) Files.createDirectory(path) else Files.createFile(path) - new PlainNioFile(path) + new PlainFile(new File(path)) } } diff --git a/compiler/src/dotty/tools/io/PlainFile.scala b/compiler/src/dotty/tools/io/PlainFile.scala index 8c30b31e8d83..b7e3e171f557 100644 --- a/compiler/src/dotty/tools/io/PlainFile.scala +++ b/compiler/src/dotty/tools/io/PlainFile.scala @@ -58,7 +58,7 @@ class PlainFile(val givenPath: Path) extends AbstractFile { try { import scala.collection.JavaConverters._ val it = Files.newDirectoryStream(jpath).iterator() - it.asScala.map(new PlainNioFile(_)) + it.asScala.map(p => new PlainFile(Path(p))) } catch { case _: NotDirectoryException => Iterator.empty } @@ -90,76 +90,3 @@ class PlainFile(val givenPath: Path) extends AbstractFile { def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = new PlainFile(givenPath / name) } - -private[dotty] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile { - - assert(nioPath ne null) - - def jpath = nioPath - - 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).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)) -} From 3c1c655eee00538d26602093b59f25f33cd482e2 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 2 Nov 2017 11:58:25 +0100 Subject: [PATCH 06/11] Rename java.io.File to JFile for consistency --- .../dotc/classpath/DirectoryClassPath.scala | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala index d8a920482cf7..5e18859bae8d 100644 --- a/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/DirectoryClassPath.scala @@ -3,7 +3,7 @@ */ package dotty.tools.dotc.classpath -import java.io.File // TODO rename to JFile for consistency +import java.io.{File => JFile} import java.net.{URI, URL} import java.nio.file.{FileSystems, Files, SimpleFileVisitor} import java.util.function.IntFunction @@ -86,15 +86,15 @@ trait DirectoryLookup[FileEntryType <: ClassRepresentation] extends ClassPath { } trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends DirectoryLookup[FileEntryType] { - type F = File + type F = JFile - protected def emptyFiles: Array[File] = Array.empty - protected def getSubDir(packageDirName: String): Option[File] = { - val packageDir = new File(dir, packageDirName) + protected def emptyFiles: Array[JFile] = Array.empty + protected def getSubDir(packageDirName: String): Option[JFile] = { + val packageDir = new JFile(dir, packageDirName) if (packageDir.exists && packageDir.isDirectory) Some(packageDir) else None } - protected def listChildren(dir: File, filter: Option[File => Boolean]): Array[File] = { + protected def listChildren(dir: JFile, filter: Option[JFile => Boolean]): Array[JFile] = { val listing = filter match { case Some(f) => dir.listFiles(mkFileFilter(f)) case None => dir.listFiles() @@ -112,15 +112,15 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo // Note this behaviour can be enabled in javac with `javac -XDsortfiles`, but that's only // intended to improve determinism of the compiler for compiler hackers. java.util.Arrays.sort(listing, - new java.util.Comparator[File] { - def compare(o1: File, o2: File) = o1.getName.compareTo(o2.getName) + new java.util.Comparator[JFile] { + def compare(o1: JFile, o2: JFile) = o1.getName.compareTo(o2.getName) }) listing } else Array() } - protected def getName(f: File): String = f.getName - protected def toAbstractFile(f: File): AbstractFile = new PlainFile(new dotty.tools.io.File(f.toPath)) - protected def isPackage(f: File): Boolean = f.isPackage + protected def getName(f: JFile): String = f.getName + protected def toAbstractFile(f: JFile): AbstractFile = new PlainFile(new dotty.tools.io.File(f.toPath)) + protected def isPackage(f: JFile): Boolean = f.isPackage assert(dir != null, "Directory file in DirectoryFileLookup cannot be null") @@ -205,12 +205,12 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No dottedClassName.substring(0, dottedClassName.lastIndexOf(".")) } -case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { +case class DirectoryClassPath(dir: JFile) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl def findClassFile(className: String): Option[AbstractFile] = { val relativePath = FileUtils.dirPath(className) - val classFile = new File(s"$dir/$relativePath.class") + val classFile = new JFile(s"$dir/$relativePath.class") if (classFile.exists) { val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) val abstractClassFile = new PlainFile(wrappedClassFile) @@ -219,23 +219,23 @@ case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileE } protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) - protected def isMatchingFile(f: File): Boolean = f.isClass + protected def isMatchingFile(f: JFile): Boolean = f.isClass private[dotty] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) } -case class DirectorySourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths { +case class DirectorySourcePath(dir: JFile) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths { def asSourcePathString: String = asClassPathString protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file) - protected def isMatchingFile(f: File): Boolean = endsScalaOrJava(f.getName) + protected def isMatchingFile(f: JFile): Boolean = endsScalaOrJava(f.getName) override def findClass(className: String): Option[ClassRepresentation] = findSourceFile(className) map SourceFileEntryImpl private def findSourceFile(className: String): Option[AbstractFile] = { val relativePath = FileUtils.dirPath(className) val sourceFile = Stream("scala", "java") - .map(ext => new File(s"$dir/$relativePath.$ext")) + .map(ext => new JFile(s"$dir/$relativePath.$ext")) .collectFirst { case file if file.exists() => file } sourceFile.map { file => From 1eb1270e2161cb61940947e063a2626186b31563 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 3 Nov 2017 13:22:30 +0100 Subject: [PATCH 07/11] Remove dotty.tools.io.Path.jfile --- .../src/dotty/tools/io/AbstractFile.scala | 2 +- compiler/src/dotty/tools/io/File.scala | 8 +++--- compiler/src/dotty/tools/io/Jar.scala | 2 +- compiler/src/dotty/tools/io/Path.scala | 12 ++++----- compiler/src/dotty/tools/io/ZipArchive.scala | 6 ++--- .../test/dotty/tools/dotc/CompilerTest.scala | 8 +++--- .../tools/dotc/parsing/ScannerTest.scala | 8 +++--- .../transform/PatmatExhaustivityTest.scala | 27 ++++++++++--------- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index a8f48d78e87e..5c30f4eecf69 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -42,7 +42,7 @@ object AbstractFile { */ def getDirectory(file: File): AbstractFile = if (file.isDirectory) new PlainFile(file) - else if (file.isFile && Path.isExtensionJarOrZip(file.jfile)) ZipArchive fromFile file + else if (file.isFile && Path.isExtensionJarOrZip(file.jpath)) ZipArchive fromFile file else null /** diff --git a/compiler/src/dotty/tools/io/File.scala b/compiler/src/dotty/tools/io/File.scala index 10348e2a6aaa..5004003039ad 100644 --- a/compiler/src/dotty/tools/io/File.scala +++ b/compiler/src/dotty/tools/io/File.scala @@ -12,6 +12,8 @@ import java.io.{ FileInputStream, FileOutputStream, BufferedWriter, OutputStreamWriter, BufferedOutputStream, IOException, PrintWriter } +import java.nio.file.Files +import java.nio.file.StandardOpenOption._ import scala.io.Codec /** @@ -54,10 +56,10 @@ class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) w if (cond(this)) Iterator.single(this) else Iterator.empty /** Obtains an InputStream. */ - def inputStream() = new FileInputStream(jfile) + def inputStream() = Files.newInputStream(jpath) /** Obtains a OutputStream. */ - def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append) + def outputStream(append: Boolean = false) = Files.newOutputStream(jpath, APPEND) def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append)) /** Obtains an OutputStreamWriter wrapped around a FileOutputStream. @@ -108,7 +110,7 @@ class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) w try classOf[JFile].getMethod("setExecutable", classOf[Boolean], classOf[Boolean]) catch { case _: NoSuchMethodException => return false } - try method.invoke(jfile, executable: JBoolean, ownerOnly: JBoolean).asInstanceOf[JBoolean].booleanValue + try method.invoke(jpath.toFile, executable: JBoolean, ownerOnly: JBoolean).asInstanceOf[JBoolean].booleanValue catch { case _: Exception => false } } } diff --git a/compiler/src/dotty/tools/io/Jar.scala b/compiler/src/dotty/tools/io/Jar.scala index b77a2c7df24f..7c84916b55b9 100644 --- a/compiler/src/dotty/tools/io/Jar.scala +++ b/compiler/src/dotty/tools/io/Jar.scala @@ -42,7 +42,7 @@ class Jar(file: File) extends Iterable[JarEntry] { private implicit def enrichManifest(m: JManifest): Jar.WManifest = Jar.WManifest(m) - lazy val jarFile = new JarFile(file.jfile) + lazy val jarFile = new JarFile(file.jpath.toFile) lazy val manifest = withJarInput(s => Option(s.getManifest)) def mainClass = manifest map (f => f(Name.MAIN_CLASS)) diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index 4e44b035293b..0ab5d0328b2c 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -29,7 +29,7 @@ import scala.util.Random.alphanumeric * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object Path { - def isExtensionJarOrZip(jfile: JFile): Boolean = isExtensionJarOrZip(jfile.getName) + def isExtensionJarOrZip(jpath: JPath): Boolean = isExtensionJarOrZip(jpath.getFileName.toString) def isExtensionJarOrZip(name: String): Boolean = { val ext = extension(name) ext == "jar" || ext == "zip" @@ -79,7 +79,7 @@ class Path private[io] (val jpath: JPath) { def toFile: File = new File(jpath) def toDirectory: Directory = new Directory(jpath) def toAbsolute: Path = if (isAbsolute) this else new Path(jpath.toAbsolutePath) - def toCanonical: Path = Path(jfile.getCanonicalPath()) + def toCanonical: Path = normalize.toAbsolute def toURI: URI = jpath.toUri() def toURL: URL = toURI.toURL() @@ -112,12 +112,10 @@ class Path private[io] (val jpath: JPath) { */ def walk: Iterator[Path] = walkFilter(_ => true) - def jfile: JFile = jpath.toFile - // identity def name: String = jpath.getFileName().toString def path: String = jpath.toString - def normalize: Path = Path(jfile.getAbsolutePath()) + def normalize: Path = Path(jpath.normalize) def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other) def relativize(other: Path) = { @@ -213,7 +211,7 @@ class Path private[io] (val jpath: JPath) { } def createFile(failIfExists: Boolean = false): File = { val res = tryCreate(Files.createFile(jpath)) - jfile.createNewFile() + Files.createFile(jpath) if (!res && failIfExists && exists) fail("File '%s' already exists." format name) else if (isFile) toFile else new File(jpath) @@ -241,7 +239,7 @@ class Path private[io] (val jpath: JPath) { def truncate() = isFile && { - val raf = new RandomAccessFile(jfile, "rw") + val raf = new RandomAccessFile(jpath.toFile, "rw") raf setLength 0 raf.close() length == 0 diff --git a/compiler/src/dotty/tools/io/ZipArchive.scala b/compiler/src/dotty/tools/io/ZipArchive.scala index 6ce3f310992b..c38c27d8e38e 100644 --- a/compiler/src/dotty/tools/io/ZipArchive.scala +++ b/compiler/src/dotty/tools/io/ZipArchive.scala @@ -31,9 +31,9 @@ object ZipArchive { * @param file a File * @return A ZipArchive if `file` is a readable zip file, otherwise null. */ - def fromFile(file: File): FileZipArchive = fromFile(file.jfile) - def fromFile(file: JFile): FileZipArchive = - try { new FileZipArchive(file.toPath) } + def fromFile(file: File): FileZipArchive = fromPath(file.jpath) + def fromPath(jpath: JPath): FileZipArchive = + try { new FileZipArchive(jpath) } catch { case _: IOException => null } def fromManifestURL(url: URL): AbstractFile = new ManifestResources(url) diff --git a/compiler/test/dotty/tools/dotc/CompilerTest.scala b/compiler/test/dotty/tools/dotc/CompilerTest.scala index b32428362cb4..dd12bf2d148f 100644 --- a/compiler/test/dotty/tools/dotc/CompilerTest.scala +++ b/compiler/test/dotty/tools/dotc/CompilerTest.scala @@ -121,7 +121,7 @@ abstract class CompilerTest { def compileFiles(path: String, args: List[String] = Nil, verbose: Boolean = true, runTest: Boolean = false, compileSubDirs: Boolean = true)(implicit defaultOptions: List[String]): Unit = { val dir = Directory(path) - val fileNames = dir.files.toArray.map(_.jfile.getName).filter(name => (name endsWith ".scala") || (name endsWith ".java")) + val fileNames = dir.files.toArray.map(_.name).filter(name => (name endsWith ".scala") || (name endsWith ".java")) for (name <- fileNames) { if (verbose) log(s"testing $path$name") compileFile(path, name, args, "", runTest) @@ -129,7 +129,7 @@ abstract class CompilerTest { if (compileSubDirs) for (subdir <- dir.dirs) { if (verbose) log(s"testing $subdir") - compileDir(path, subdir.jfile.getName, args, runTest) + compileDir(path, subdir.name, args, runTest) } } def runFiles(path: String, args: List[String] = Nil, verbose: Boolean = true) @@ -363,13 +363,13 @@ abstract class CompilerTest { processFileDir(sourceFile, { sf => if (extensionsToCopy.contains(sf.extension)) { - dest.parent.jfile.mkdirs + dest.parent.createDirectory(force = true) copyfile(sf, false) } else { log(s"WARNING: ignoring $sf") } }, { sdir => - dest.jfile.mkdirs + dest.createDirectory(force = true) sdir.list.foreach(path => recCopyFiles(path, dest / path.name)) }, Some("DPCompilerTest.recCopyFiles: sourceFile not found: " + sourceFile)) } diff --git a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala index 001da38ee3fb..20958e30126d 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala @@ -33,13 +33,13 @@ class ScannerTest extends DottyTest { def scanDir(path: String): Unit = scanDir(Directory(path)) def scanDir(dir: Directory): Unit = { - if (blackList exists (dir.jfile.toString endsWith _)) - println(s"blacklisted package: ${dir.jfile.getAbsolutePath}") + if (blackList exists (dir.jpath.toString endsWith _)) + println(s"blacklisted package: ${dir.toAbsolute.jpath}") else for (f <- dir.files) if (f.name.endsWith(".scala")) - if (blackList exists (f.jfile.toString endsWith _)) - println(s"blacklisted file: ${f.jfile.getAbsolutePath}") + if (blackList exists (f.jpath.toString endsWith _)) + println(s"blacklisted file: ${f.toAbsolute.jpath}") else scan(new PlainFile(f)) for (d <- dir.dirs) diff --git a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala index 3ae26e4d421e..5d770557e056 100644 --- a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala +++ b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala @@ -4,6 +4,7 @@ package dotc package transform import java.io._ +import java.nio.file.{Path => JPath} import scala.io.Source._ import dotty.tools.io.Directory @@ -16,53 +17,53 @@ class PatmatExhaustivityTest { // stop-after: patmatexhaust-huge.scala crash compiler val options = List("-color:never", "-Ystop-after:splitter", "-Ycheck-all-patmat", "-classpath", TestConfiguration.classPath) - private def compileFile(file: File) = { + private def compileFile(path: JPath) = { val stringBuffer = new StringWriter() val reporter = TestReporter.simplifiedReporter(new PrintWriter(stringBuffer)) try { - Main.process((file.getPath::options).toArray, reporter, null) + Main.process((path.toString::options).toArray, reporter, null) } catch { case e: Throwable => - println(s"Compile $file exception:") + println(s"Compile $path exception:") e.printStackTrace() } val actual = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n") - val checkFilePath = file.getAbsolutePath.stripSuffix(".scala") + ".check" + val checkFilePath = path.toAbsolutePath.toString.stripSuffix(".scala") + ".check" val checkContent = if (new File(checkFilePath).exists) fromFile(checkFilePath).getLines().map(_.replaceAll("\\s+$", "")).mkString("\n").trim else "" - (file, checkContent, actual) + (path, checkContent, actual) } /** A single test with multiple files grouped in a folder */ - private def compileDir(file: File) = { + private def compileDir(path: JPath) = { val stringBuffer = new StringWriter() val reporter = TestReporter.simplifiedReporter(new PrintWriter(stringBuffer)) - val files = Directory(file.getPath).list.toList + val files = Directory(path).list.toList .filter(f => f.extension == "scala" || f.extension == "java" ) - .map(_.jfile.getPath) + .map(_.jpath.toString) try { Main.process((options ++ files).toArray, reporter, null) } catch { case e: Throwable => - println(s"Compile $file exception:") + println(s"Compile $path exception:") e.printStackTrace() } val actual = stringBuffer.toString.trim.replaceAll("\\s+\n", "\n") - val checkFilePath = file.getPath + File.separator + "expected.check" + val checkFilePath = path + File.separator + "expected.check" val checkContent = if (new File(checkFilePath).exists) fromFile(checkFilePath).getLines().map(_.replaceAll("\\s+$", "")).mkString("\n").trim else "" - (file, checkContent, actual) + (path, checkContent, actual) } @Test @@ -71,9 +72,9 @@ class PatmatExhaustivityTest { .filter(f => f.extension == "scala" || f.isDirectory) .map { f => if (f.isDirectory) - compileDir(f.jfile) + compileDir(f.jpath) else - compileFile(f.jfile) + compileFile(f.jpath) } val failed = res.filter { case (_, expected, actual) => expected != actual } From 757fb6a38fb4a1b8806be0013cd592233cdab9f7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 3 Nov 2017 14:40:02 +0100 Subject: [PATCH 08/11] Improve some implementations based on java Paths --- compiler/src/dotty/tools/io/Directory.scala | 10 ++---- compiler/src/dotty/tools/io/Path.scala | 36 ++++++++++++++------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/io/Directory.scala b/compiler/src/dotty/tools/io/Directory.scala index 0eaa52c071de..4e670d50c39b 100644 --- a/compiler/src/dotty/tools/io/Directory.scala +++ b/compiler/src/dotty/tools/io/Directory.scala @@ -48,13 +48,9 @@ class Directory(jpath: JPath) extends Path(jpath) { /** An iterator over the contents of this directory. */ - def list: Iterator[Path] = { - try { - Files.list(jpath).toArray[JPath](n => new Array(n)).iterator.map(Path.apply) - } catch { - case _: java.nio.file.NoSuchFileException => Iterator.empty - } - } + def list: Iterator[Path] = + if (isDirectory) Files.list(jpath).iterator.asScala.map(Path.apply) + else Iterator.empty def dirs: Iterator[Directory] = list collect { case x: Directory => x } def files: Iterator[File] = list collect { case x: File => x } diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index 0ab5d0328b2c..be6777200d74 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -7,8 +7,12 @@ package dotty.tools.io import scala.language.implicitConversions import java.io.RandomAccessFile -import java.nio.file.{DirectoryNotEmptyException, FileAlreadyExistsException, Files, NoSuchFileException, Paths} +import java.nio.file._ import java.net.{URI, URL} +import java.nio.file.attribute.BasicFileAttributes +import java.io.IOException + +import scala.collection.JavaConverters._ import scala.util.Random.alphanumeric @@ -51,7 +55,7 @@ object Path { def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory) def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile) - def roots: List[Path] = java.io.File.listRoots().toList.map(r => Path.apply(r.toPath)) + def roots: List[Path] = FileSystems.getDefault.getRootDirectories.iterator().asScala.map(Path.apply).toList def apply(path: String): Path = apply(Paths.get(path)) def apply(jpath: JPath): Path = try { @@ -221,22 +225,30 @@ class Path private[io] (val jpath: JPath) { try { create; true } catch { case _: FileAlreadyExistsException => false } // deletions - def delete(): Unit = delete(jpath) + def delete(): Unit = + try { Files.deleteIfExists(jpath) } catch { case _: DirectoryNotEmptyException => } /** Deletes the path recursively. Returns false on failure. * Use with caution! */ - def deleteRecursively(): Boolean = deleteRecursively(jpath) - private def deleteRecursively(p: JPath): Boolean = { - import scala.collection.JavaConverters._ - if (Files.isDirectory(p)) - Files.list(p).iterator().asScala.foreach(deleteRecursively) - delete(p) + def deleteRecursively(): Boolean = { + if (!exists) false + else { + Files.walkFileTree(jpath, new SimpleFileVisitor[JPath]() { + override def visitFile(file: JPath, attrs: BasicFileAttributes) = { + Files.delete(file) + FileVisitResult.CONTINUE + } + + override def postVisitDirectory(dir: JPath, exc: IOException) = { + Files.delete(dir) + FileVisitResult.CONTINUE + } + }) + true + } } - private def delete(path: JPath): Boolean = - try { Files.deleteIfExists(path); true } catch { case _: DirectoryNotEmptyException => false } - def truncate() = isFile && { val raf = new RandomAccessFile(jpath.toFile, "rw") From 88aa338664237d0a909a0e6e9e7b70ec28d185e4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 3 Nov 2017 18:04:27 +0100 Subject: [PATCH 09/11] Fix outputStream append flag --- compiler/src/dotty/tools/io/File.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/io/File.scala b/compiler/src/dotty/tools/io/File.scala index 5004003039ad..e41c954a9ea3 100644 --- a/compiler/src/dotty/tools/io/File.scala +++ b/compiler/src/dotty/tools/io/File.scala @@ -59,7 +59,9 @@ class File(jpath: JPath)(implicit constructorCodec: Codec) extends Path(jpath) w def inputStream() = Files.newInputStream(jpath) /** Obtains a OutputStream. */ - def outputStream(append: Boolean = false) = Files.newOutputStream(jpath, APPEND) + def outputStream(append: Boolean = false) = + if (append) Files.newOutputStream(jpath, APPEND) + else Files.newOutputStream(jpath) def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append)) /** Obtains an OutputStreamWriter wrapped around a FileOutputStream. From 672f557321bb884519bd8fa02660a11469a722b7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 3 Nov 2017 18:05:42 +0100 Subject: [PATCH 10/11] Remove unneeded exception handling --- compiler/src/dotty/tools/io/ZipArchive.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/io/ZipArchive.scala b/compiler/src/dotty/tools/io/ZipArchive.scala index c38c27d8e38e..d83fd230f0a6 100644 --- a/compiler/src/dotty/tools/io/ZipArchive.scala +++ b/compiler/src/dotty/tools/io/ZipArchive.scala @@ -32,9 +32,7 @@ object ZipArchive { * @return A ZipArchive if `file` is a readable zip file, otherwise null. */ def fromFile(file: File): FileZipArchive = fromPath(file.jpath) - def fromPath(jpath: JPath): FileZipArchive = - try { new FileZipArchive(jpath) } - catch { case _: IOException => null } + def fromPath(jpath: JPath): FileZipArchive = new FileZipArchive(jpath) def fromManifestURL(url: URL): AbstractFile = new ManifestResources(url) From 5065cf27448ead2cf47da6a54e2ae858aedd3cfb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sun, 5 Nov 2017 10:59:26 +0100 Subject: [PATCH 11/11] Implement resolve and relativize with nio --- compiler/src/dotty/tools/io/Path.scala | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/io/Path.scala b/compiler/src/dotty/tools/io/Path.scala index be6777200d74..a55d033f748d 100644 --- a/compiler/src/dotty/tools/io/Path.scala +++ b/compiler/src/dotty/tools/io/Path.scala @@ -95,7 +95,7 @@ class Path private[io] (val jpath: JPath) { /** 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 = if (isEmpty) child else new Path(jpath.resolve(child.path)) + def /(child: Path): Path = resolve(child) def /(child: Directory): Directory = /(child: Path).toDirectory def /(child: File): File = /(child: Path).toFile @@ -121,19 +121,8 @@ class Path private[io] (val jpath: JPath) { def path: String = jpath.toString def normalize: Path = Path(jpath.normalize) - def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other) - def relativize(other: Path) = { - assert(isAbsolute == other.isAbsolute, "Paths not of same type: "+this+", "+other) - - def createRelativePath(baseSegs: List[String], otherSegs: List[String]) : String = { - (baseSegs, otherSegs) match { - case (b :: bs, o :: os) if b == o => createRelativePath(bs, os) - case (bs, os) => ((".."+separator)*bs.length)+os.mkString(separatorStr) - } - } - - Path(createRelativePath(segments, other.segments)) - } + def resolve(other: Path) = Path(jpath.resolve(other.jpath)) + def relativize(other: Path) = Path(jpath.relativize(other.jpath)) def segments: List[String] = (path split separator).toList filterNot (_.length == 0)