@@ -5,6 +5,9 @@ package dotty.tools.dotc.classpath
55
66import java .io .File
77import java .net .URL
8+ import java .nio .file .Files
9+ import java .nio .file .attribute .{BasicFileAttributes , FileTime }
10+
811import scala .annotation .tailrec
912import dotty .tools .io .{AbstractFile , ClassPath , ClassRepresentation , FileZipArchive , ManifestResources }
1013import dotty .tools .dotc .core .Contexts .Context
@@ -19,23 +22,17 @@ import FileUtils._
1922 * when there are a lot of projects having a lot of common dependencies.
2023 */
2124sealed trait ZipAndJarFileLookupFactory {
22- private val cache = collection.mutable. Map .empty[ AbstractFile , ClassPath ]
25+ private val cache = new FileBasedCache [ ClassPath ]
2326
2427 def create (zipFile : AbstractFile )(implicit ctx : Context ): ClassPath = {
25- if (ctx.settings.YdisableFlatCpCaching .value) createForZipFile(zipFile)
28+ if (ctx.settings.YdisableFlatCpCaching .value || zipFile.file == null ) createForZipFile(zipFile)
2629 else createUsingCache(zipFile)
2730 }
2831
2932 protected def createForZipFile (zipFile : AbstractFile ): ClassPath
3033
31- private def createUsingCache (zipFile : AbstractFile )(implicit ctx : Context ): ClassPath = cache.synchronized {
32- def newClassPathInstance = {
33- if (ctx.settings.verbose.value || ctx.settings.Ylogcp .value)
34- println(s " $zipFile is not yet in the classpath cache " )
35- createForZipFile(zipFile)
36- }
37- cache.getOrElseUpdate(zipFile, newClassPathInstance)
38- }
34+ private def createUsingCache (zipFile : AbstractFile ): ClassPath =
35+ cache.getOrCreate(zipFile.file.toPath, () => createForZipFile(zipFile))
3936}
4037
4138/**
@@ -179,3 +176,29 @@ object ZipAndJarSourcePathFactory extends ZipAndJarFileLookupFactory {
179176
180177 override protected def createForZipFile (zipFile : AbstractFile ): ClassPath = ZipArchiveSourcePath (zipFile.file)
181178}
179+
180+ final class FileBasedCache [T ] {
181+ private case class Stamp (lastModified : FileTime , fileKey : Object )
182+ private val cache = collection.mutable.Map .empty[java.nio.file.Path , (Stamp , T )]
183+
184+ def getOrCreate (path : java.nio.file.Path , create : () => T ): T = cache.synchronized {
185+ val attrs = Files .readAttributes(path, classOf [BasicFileAttributes ])
186+ val lastModified = attrs.lastModifiedTime()
187+ // only null on some platforms, but that's okay, we just use the last modified timestamp as our stamp
188+ val fileKey = attrs.fileKey()
189+ val stamp = Stamp (lastModified, fileKey)
190+ cache.get(path) match {
191+ case Some ((cachedStamp, cached)) if cachedStamp == stamp => cached
192+ case _ =>
193+ val value = create()
194+ cache.put(path, (stamp, value))
195+ value
196+ }
197+ }
198+
199+ def clear (): Unit = cache.synchronized {
200+ // TODO support closing
201+ // cache.valuesIterator.foreach(_.close())
202+ cache.clear()
203+ }
204+ }
0 commit comments