@@ -10,9 +10,10 @@ import java.util.function.IntFunction
10
10
import java .util
11
11
import java .util .Comparator
12
12
13
- import scala .reflect .io .{AbstractFile , PlainFile }
13
+ import scala .reflect .io .{AbstractFile , PlainFile , PlainNioFile }
14
14
import scala .tools .nsc .util .{ClassPath , ClassRepresentation }
15
15
import FileUtils ._
16
+ import scala .collection .JavaConverters ._
16
17
17
18
/**
18
19
* A trait allowing to look for classpath entries in directories. It provides common logic for
@@ -121,51 +122,78 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo
121
122
def asClassPathStrings : Seq [String ] = Seq (dir.getPath)
122
123
}
123
124
124
- object JImageDirectoryLookup {
125
- import java .nio .file ._ , java .net .URI , scala . collection . JavaConverters . _
126
- def apply (): List [ClassPath ] = {
125
+ object JrtClassPath {
126
+ import java .nio .file ._ , java .net .URI
127
+ def apply (): Option [ClassPath ] = {
127
128
try {
128
129
val fs = FileSystems .getFileSystem(URI .create(" jrt:/" ))
129
- val dir : Path = fs.getPath(" /modules" )
130
- val modules = Files .list(dir).iterator().asScala.toList
131
- modules.map(m => new JImageDirectoryLookup (fs, m.getFileName.toString))
130
+ Some (new JrtClassPath (fs))
132
131
} catch {
133
132
case _ : ProviderNotFoundException | _ : FileSystemNotFoundException =>
134
- Nil
133
+ None
135
134
}
136
135
}
137
136
}
138
- class JImageDirectoryLookup (fs : java.nio.file.FileSystem , module : String ) extends DirectoryLookup [ClassFileEntryImpl ] with NoSourcePaths {
137
+
138
+ /**
139
+ * Implementation `ClassPath` based on the JDK 9 encapsulated runtime modules (JEP-220)
140
+ *
141
+ * https://bugs.openjdk.java.net/browse/JDK-8066492 is the most up to date reference
142
+ * for the structure of the jrt:// filesystem.
143
+ *
144
+ * The implementation assumes that no classes exist in the empty package.
145
+ */
146
+ final class JrtClassPath (fs : java.nio.file.FileSystem ) extends ClassPath with NoSourcePaths {
139
147
import java .nio .file .Path , java .nio .file ._
140
148
type F = Path
141
- val dir : Path = fs.getPath(" /modules/ " + module )
149
+ private val dir : Path = fs.getPath(" /packages " )
142
150
143
- protected def emptyFiles : Array [Path ] = Array .empty
144
- protected def getSubDir (packageDirName : String ): Option [Path ] = {
145
- val packageDir = dir.resolve(packageDirName)
146
- if (Files .exists(packageDir) && Files .isDirectory(packageDir)) Some (packageDir)
147
- else None
151
+ // e.g. "java.lang" -> Seq("/modules/java.base")
152
+ private val packageToModuleBases : Map [String , Seq [Path ]] = {
153
+ val ps = Files .newDirectoryStream(dir).iterator().asScala
154
+ def lookup (pack : Path ): Seq [Path ] = {
155
+ Files .list(pack).iterator().asScala.map(l => if (Files .isSymbolicLink(l)) Files .readSymbolicLink(l) else l).toList
156
+ }
157
+ ps.map(p => (p.toString.stripPrefix(" /packages/" ), lookup(p))).toMap
148
158
}
149
- protected def listChildren (dir : Path , filter : Option [Path => Boolean ]): Array [Path ] = {
150
- import scala .collection .JavaConverters ._
151
- val f = filter.getOrElse((p : Path ) => true )
152
- Files .list(dir).iterator().asScala.filter(f).toArray[Path ]
159
+
160
+ override private [nsc] def packages (inPackage : String ): Seq [PackageEntry ] = {
161
+ def matches (packageDottedName : String ) =
162
+ if (packageDottedName.contains(" ." ))
163
+ packageOf(packageDottedName) == inPackage
164
+ else inPackage == " "
165
+ packageToModuleBases.keysIterator.filter(matches).map(PackageEntryImpl (_)).toVector
166
+ }
167
+ private [nsc] def classes (inPackage : String ): Seq [ClassFileEntry ] = {
168
+ if (inPackage == " " ) Nil
169
+ else {
170
+ packageToModuleBases.getOrElse(inPackage, Nil ).flatMap(x =>
171
+ Files .list(x.resolve(inPackage.replace('.' , '/' ))).iterator().asScala.filter(_.getFileName.toString.endsWith(" .class" ))).map(x =>
172
+ ClassFileEntryImpl (new PlainNioFile (x))).toVector
173
+ }
153
174
}
154
- protected def getName (f : Path ): String = f.getFileName.toString
155
- protected def toAbstractFile (f : Path ): AbstractFile = new scala.reflect.io.PlainNioFile (f)
156
- protected def isPackage (f : Path ): Boolean = Files .isDirectory(f) && mayBeValidPackage(f.getFileName.toString)
175
+
176
+ override private [nsc] def list (inPackage : String ): ClassPathEntries =
177
+ if (inPackage == " " ) ClassPathEntries (packages(inPackage), Nil )
178
+ else ClassPathEntries (packages(inPackage), classes(inPackage))
157
179
158
180
def asURLs : Seq [URL ] = Seq (dir.toUri.toURL)
159
- def asClassPathStrings : Seq [String ] = asURLs.map(_.toString)
181
+ // We don't yet have a scheme to represent the JDK modules in our `-classpath`.
182
+ // java models them as entries in the new "module path", we'll probably need to follow this.
183
+ def asClassPathStrings : Seq [String ] = Nil
160
184
161
185
def findClassFile (className : String ): Option [AbstractFile ] = {
162
- val relativePath = FileUtils .dirPath(className) + " .class"
163
- val classFile = dir.resolve(relativePath)
164
- if (Files .exists(classFile)) Some (new scala.reflect.io.PlainNioFile (classFile)) else None
186
+ if (! className.contains(" ." )) None
187
+ else {
188
+ val inPackage = packageOf(className)
189
+ packageToModuleBases.getOrElse(inPackage, Nil ).iterator.flatMap{x =>
190
+ val file = x.resolve(className.replace('.' , '/' ) + " .class" )
191
+ if (Files .exists(file)) new scala.reflect.io.PlainNioFile (file) :: Nil else Nil
192
+ }.take(1 ).toList.headOption
193
+ }
165
194
}
166
- override protected def createFileEntry (file : AbstractFile ): ClassFileEntryImpl = ClassFileEntryImpl (file)
167
- override protected def isMatchingFile (f : Path ): Boolean = Files .isRegularFile(f) && f.getFileName.toString.endsWith(" .class" )
168
- override private [nsc] def classes (inPackage : String ): Seq [ClassFileEntry ] = files(inPackage)
195
+ private def packageOf (dottedClassName : String ): String =
196
+ dottedClassName.substring(0 , dottedClassName.lastIndexOf(" ." ))
169
197
}
170
198
171
199
case class DirectoryClassPath (dir : File ) extends JFileDirectoryLookup [ClassFileEntryImpl ] with NoSourcePaths {
0 commit comments