diff options
Diffstat (limited to 'src')
5 files changed, 136 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala index 3a29f1ba11..80c5ec8828 100644 --- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala +++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala @@ -4,6 +4,7 @@ package scala.tools.nsc.classpath import scala.reflect.io.{AbstractFile, VirtualDirectory} +import scala.reflect.io.Path.string2path import scala.tools.nsc.Settings import FileUtils.AbstractFileOps import scala.tools.nsc.util.ClassPath @@ -52,7 +53,10 @@ class ClassPathFactory(settings: Settings) { protected def classesInPathImpl(path: String, expand: Boolean) = for { file <- expandPath(path, expand) - dir <- Option(AbstractFile.getDirectory(file)) + dir <- { + def asImage = if (file.endsWith(".jimage")) Some(AbstractFile.getFile(file)) else None + Option(AbstractFile.getDirectory(file)).orElse(asImage) + } } yield newClassPath(dir) private def createSourcePath(file: AbstractFile): ClassPath = diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index c4be59d7eb..133a656206 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -4,7 +4,9 @@ package scala.tools.nsc.classpath import java.io.File -import java.net.URL +import java.net.{URI, URL} +import java.nio.file.{FileSystems, Files, SimpleFileVisitor} +import java.util.function.IntFunction import java.util import java.util.Comparator @@ -119,6 +121,53 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo def asClassPathStrings: Seq[String] = Seq(dir.getPath) } +object JImageDirectoryLookup { + import java.nio.file._, java.net.URI, scala.collection.JavaConverters._ + def apply(): List[ClassPath] = { + try { + val fs = FileSystems.getFileSystem(URI.create("jrt:/")) + val dir: Path = fs.getPath("/modules") + val modules = Files.list(dir).iterator().asScala.toList + modules.map(m => new JImageDirectoryLookup(fs, m.getFileName.toString)) + } catch { + case _: ProviderNotFoundException | _: FileSystemNotFoundException => + Nil + } + } +} +class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { + import java.nio.file.Path, java.nio.file._ + type F = Path + val dir: Path = fs.getPath("/modules/" + module) + + protected def emptyFiles: Array[Path] = Array.empty + protected def getSubDir(packageDirName: String): Option[Path] = { + val packageDir = dir.resolve(packageDirName) + if (Files.exists(packageDir) && Files.isDirectory(packageDir)) Some(packageDir) + else None + } + protected def listChildren(dir: Path, filter: Option[Path => Boolean]): Array[Path] = { + import scala.collection.JavaConverters._ + val f = filter.getOrElse((p: Path) => true) + Files.list(dir).iterator().asScala.filter(f).toArray[Path] + } + protected def getName(f: Path): String = f.getFileName.toString + protected def toAbstractFile(f: Path): AbstractFile = new scala.reflect.io.PlainNioFile(f) + protected def isPackage(f: Path): Boolean = Files.isDirectory(f) && mayBeValidPackage(f.getFileName.toString) + + def asURLs: Seq[URL] = Seq(dir.toUri.toURL) + def asClassPathStrings: Seq[String] = asURLs.map(_.toString) + + def findClassFile(className: String): Option[AbstractFile] = { + val relativePath = FileUtils.dirPath(className) + ".class" + val classFile = dir.resolve(relativePath) + if (Files.exists(classFile)) Some(new scala.reflect.io.PlainNioFile(classFile)) else None + } + override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file) + override protected def isMatchingFile(f: Path): Boolean = Files.isRegularFile(f) && f.getFileName.toString.endsWith(".class") + override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage) +} + case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths { override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl diff --git a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala index bbcfcb24ca..2ade83c6f9 100644 --- a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala +++ b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala @@ -63,7 +63,7 @@ object FileUtils { // probably it should match a pattern like [a-z_]{1}[a-z0-9_]* but it cannot be changed // because then some tests in partest don't pass - private def mayBeValidPackage(dirName: String): Boolean = + def mayBeValidPackage(dirName: String): Boolean = (dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.') def mkFileFilter(f: JFile => Boolean) = new FileFilter { diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index c351b6ace1..188cabbc8d 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -234,6 +234,7 @@ final class PathResolver(settings: Settings) { // Assemble the elements! def basis = List[Traversable[ClassPath]]( + JImageDirectoryLookup.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system) classesInPath(javaBootClassPath), // 1. The Java bootstrap class path. contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path. classesInExpandedPath(javaUserClassPath), // 3. The Java application class path. diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala index eb0940e703..989081ebe0 100644 --- a/src/reflect/scala/reflect/io/PlainFile.scala +++ b/src/reflect/scala/reflect/io/PlainFile.scala @@ -40,7 +40,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile { override def output = givenPath.toFile.outputStream() override def sizeOption = Some(givenPath.length.toInt) - override def toString = path override def hashCode(): Int = fpath.hashCode() override def equals(that: Any): Boolean = that match { case x: PlainFile => fpath == x.fpath @@ -91,3 +90,82 @@ class PlainFile(val givenPath: Path) extends AbstractFile { def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = new PlainFile(givenPath / name) } + +private[scala] 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)) +} |