blob: 784d9ad410ff094d44b43f618b0d849c18e8fec4 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
package mill.eval
import java.io.IOException
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{FileVisitResult, FileVisitor}
import java.nio.{file => jnio}
import java.security.MessageDigest
import upickle.default.{ReadWriter => RW}
import ammonite.ops.Path
import mill.util.JsonFormatters
/**
* A wrapper around `ammonite.ops.Path` that calculates it's hashcode based
* on the contents of the filesystem underneath it. Used to ensure filesystem
* changes can bust caches which are keyed off hashcodes.
*/
case class PathRef(path: ammonite.ops.Path, quick: Boolean = false){
val sig = {
val digest = MessageDigest.getInstance("MD5")
val buffer = new Array[Byte](16 * 1024)
jnio.Files.walkFileTree(
path.toNIO,
new FileVisitor[jnio.Path] {
def preVisitDirectory(dir: jnio.Path, attrs: BasicFileAttributes) = {
digest.update(dir.toAbsolutePath.toString.getBytes)
FileVisitResult.CONTINUE
}
def visitFile(file: jnio.Path, attrs: BasicFileAttributes) = {
digest.update(file.toAbsolutePath.toString.getBytes)
if (quick){
val value = (path.mtime.toMillis, path.size).hashCode()
digest.update((value >>> 24).toByte)
digest.update((value >>> 16).toByte)
digest.update((value >>> 8).toByte)
digest.update(value.toByte)
}else {
val is = jnio.Files.newInputStream(file)
def rec(): Unit = {
val length = is.read(buffer)
if (length != -1) {
digest.update(buffer, 0, length)
rec()
}
}
rec()
}
FileVisitResult.CONTINUE
}
def visitFileFailed(file: jnio.Path, exc: IOException) = FileVisitResult.CONTINUE
def postVisitDirectory(dir: jnio.Path, exc: IOException) = FileVisitResult.CONTINUE
}
)
java.util.Arrays.hashCode(digest.digest())
}
override def hashCode() = sig
}
object PathRef{
private implicit val pathFormat: RW[Path] = JsonFormatters.pathReadWrite
implicit def jsonFormatter: RW[PathRef] = upickle.default.macroRW
}
|