@@ -13,9 +13,11 @@ package sbt
1313package internal
1414package inc
1515
16- import java .io .InputStream
16+ import java .io .{ ByteArrayInputStream , InputStream }
17+ import java .nio .ByteBuffer
1718import java .nio .file .{ Files , Path , Paths }
1819import xsbti .{ BasicVirtualFileRef , FileConverter , PathBasedFile , VirtualFile , VirtualFileRef }
20+ import sbt .nio .file .{ FileTreeView , Glob , IsNotHidden , IsRegularFile , RecursiveGlob }
1921
2022class MappedVirtualFile (encodedPath : String , rootPathsMap : Map [String , Path ])
2123 extends BasicVirtualFileRef (encodedPath)
@@ -40,8 +42,47 @@ object MappedVirtualFile {
4042 }
4143}
4244
45+ class MappedDirectory (
46+ encodedPath : String ,
47+ rootPathsMap : Map [String , Path ],
48+ items : List [VirtualFile ]
49+ ) extends BasicVirtualFileRef (encodedPath)
50+ with PathBasedFile {
51+ private def path : Path = MappedVirtualFile .toPath(encodedPath, rootPathsMap)
52+ override lazy val contentHash : Long = {
53+ val buffer = ByteBuffer .allocate(java.lang.Long .BYTES * items.size)
54+ val hashes = items.foreach { item =>
55+ buffer.putLong(item.contentHash)
56+ }
57+ HashUtil .farmHash(buffer.array())
58+ }
59+ override lazy val sizeBytes : Long = items.map(_.sizeBytes).sum
60+ override lazy val contentHashStr : String = {
61+ val sb = new StringBuilder
62+ val hashes = items.foreach { item =>
63+ sb.append(item.contentHashStr)
64+ }
65+ val stream = new ByteArrayInputStream (hashes.toString.getBytes(" UTF-8" ))
66+ HashUtil .sha256HashStr(stream)
67+ }
68+ override def input (): InputStream = ???
69+ override def toPath : Path = path
70+ }
71+
72+ object MappedDirectory {
73+ def apply (
74+ encodedPath : String ,
75+ rootPaths : Map [String , Path ],
76+ items : List [VirtualFile ]
77+ ): MappedDirectory =
78+ new MappedDirectory (encodedPath, rootPaths, items)
79+ }
80+
4381class MappedFileConverter (rootPaths : Map [String , Path ], allowMachinePath : Boolean )
4482 extends FileConverter {
83+
84+ import MappedFileConverter .view
85+
4586 val rootPaths2 : Seq [(String , Path )] = rootPaths.toSeq.flatMap {
4687 case (key, rootPath) =>
4788 if (rootPath.startsWith(" /var/" ) || rootPath.startsWith(" /tmp/" )) {
@@ -56,9 +97,15 @@ class MappedFileConverter(rootPaths: Map[String, Path], allowMachinePath: Boolea
5697 }
5798
5899 def toVirtualFile (path : Path ): VirtualFile = {
100+ def isDirectory : Boolean =
101+ Files .isDirectory(path) || (! Files .exists(path) && path.getFileName.toString().endsWith(
102+ " classes"
103+ ))
59104 rootPaths2.find { case (_, rootPath) => path.startsWith(rootPath) } match {
60105 case Some ((key, rootPath)) =>
61- MappedVirtualFile (s " $$ { $key}/ ${rootPath.relativize(path)}" .replace('\\ ' , '/' ), rootPaths)
106+ val encodedPath = s " $$ { $key}/ ${rootPath.relativize(path)}" .replace('\\ ' , '/' )
107+ if (isDirectory) toDirectory(path, encodedPath)
108+ else MappedVirtualFile (encodedPath, rootPaths)
62109 case _ =>
63110 def isCtSym =
64111 path.getFileSystem
@@ -67,13 +114,26 @@ class MappedFileConverter(rootPaths: Map[String, Path], allowMachinePath: Boolea
67114 def isJrt = path.getFileSystem.provider().getScheme == " jrt"
68115 if (isJrt || path.getFileName.toString == " rt.jar" || isCtSym)
69116 DummyVirtualFile (" rt.jar" , path)
70- else if (allowMachinePath) MappedVirtualFile (s " $path" .replace('\\ ' , '/' ), rootPaths)
71- else sys.error(s " $path cannot be mapped using the root paths $rootPaths" )
117+ else if (allowMachinePath) {
118+ val encodedPath = s " $path" .replace('\\ ' , '/' )
119+ if (isDirectory) toDirectory(path, encodedPath)
120+ else MappedVirtualFile (encodedPath, rootPaths)
121+ } else sys.error(s " $path cannot be mapped using the root paths $rootPaths" )
72122 }
73123 }
124+
125+ def toDirectory (path : Path , encodedPath : String ) = {
126+ val list = view.list(Glob (path, RecursiveGlob ), IsRegularFile && IsNotHidden )
127+ .map(_._1)
128+ .sortBy(x => x.toUri().toString())
129+ val items = list.map(toVirtualFile)
130+ MappedDirectory (encodedPath, rootPaths, items.toList)
131+ }
74132}
75133
76134object MappedFileConverter {
135+ private [sbt] lazy val view = FileTreeView .Ops (FileTreeView .default)
136+
77137 def empty : MappedFileConverter = new MappedFileConverter (Map (), true )
78138 def apply (rootPaths : Map [String , Path ], allowMachinePath : Boolean ): MappedFileConverter =
79139 new MappedFileConverter (rootPaths, allowMachinePath)
0 commit comments