Merge pull request #97 from eed3si9n/wip/hash

Tracked fixes
This commit is contained in:
eugene yokota 2017-07-16 19:44:28 -04:00 committed by GitHub
commit a09cd424f1
2 changed files with 109 additions and 8 deletions

View File

@ -70,9 +70,66 @@ object Tracked {
def lastOutput[I, O: JsonFormat](cacheFile: File)(f: (I, Option[O]) => O): I => O =
lastOutput(CacheStore(cacheFile))(f)
/**
* Creates a tracker that indicates whether the output returned from `p` has changed or not.
*
* {{{
* val cachedTask = inputChanged(cache / "inputs") { (inChanged, in: Inputs) =>
* Tracked.outputChanged(cache / "output") { (outChanged, outputs: FilesInfo[PlainFileInfo]) =>
* if (inChanged || outChanged) {
* doSomething(label, sources, classpath, outputDirectory, options, log)
* }
* }
* }
* cachedDoc(inputs)(() => exists(outputDirectory.allPaths.get.toSet))
* }}}
*/
def outputChanged[A1: JsonFormat, A2](store: CacheStore)(f: (Boolean, A1) => A2): (() => A1) => A2 = p => {
val cache: SingletonCache[Long] = {
import CacheImplicits.LongJsonFormat
implicitly
}
val initial = p()
val help = new CacheHelp(cache)
val changed = help.changed(store, initial)
val result = f(changed, initial)
if (changed) {
help.save(store, initial)
}
result
}
/**
* Creates a tracker that indicates whether the output returned from `p` has changed or not.
*
* {{{
* val cachedTask = inputChanged(cache / "inputs") { (inChanged, in: Inputs) =>
* Tracked.outputChanged(cache / "output") { (outChanged, outputs: FilesInfo[PlainFileInfo]) =>
* if (inChanged || outChanged) {
* doSomething(label, sources, classpath, outputDirectory, options, log)
* }
* }
* }
* cachedDoc(inputs)(() => exists(outputDirectory.allPaths.get.toSet))
* }}}
*/
def outputChanged[A1: JsonFormat, A2](cacheFile: File)(f: (Boolean, A1) => A2): (() => A1) => A2 =
outputChanged[A1, A2](CacheStore(cacheFile))(f)
/**
* Creates a tracker that indicates whether the arguments given to f have changed since the most
* recent invocation.
*
* {{{
* val cachedTask = inputChanged(cache / "inputs") { (inChanged, in: Inputs) =>
* Tracked.outputChanged(cache / "output") { (outChanged, outputs: FilesInfo[PlainFileInfo]) =>
* if (inChanged || outChanged) {
* doSomething(label, sources, classpath, outputDirectory, options, log)
* }
* }
* }
* cachedDoc(inputs)(() => exists(outputDirectory.allPaths.get.toSet))
* }}}
*/
def inputChanged[I: JsonFormat: SingletonCache, O](store: CacheStore)(f: (Boolean, I) => O): I => O = { in =>
val cache: SingletonCache[Long] = {
@ -90,22 +147,37 @@ object Tracked {
/**
* Creates a tracker that indicates whether the arguments given to f have changed since the most
* recent invocation.
*
* {{{
* val cachedTask = inputChanged(cache / "inputs") { (inChanged, in: Inputs) =>
* Tracked.outputChanged(cache / "output") { (outChanged, outputs: FilesInfo[PlainFileInfo]) =>
* if (inChanged || outChanged) {
* doSomething(label, sources, classpath, outputDirectory, options, log)
* }
* }
* }
* cachedDoc(inputs)(() => exists(outputDirectory.allPaths.get.toSet))
* }}}
*/
def inputChanged[I: JsonFormat: SingletonCache, O](cacheFile: File)(f: (Boolean, I) => O): I => O =
inputChanged(CacheStore(cacheFile))(f)
private final class CacheHelp[I: JsonFormat](val sc: SingletonCache[Long]) {
import CacheImplicits.implicitHashWriter
import CacheImplicits.LongJsonFormat
def save(store: CacheStore, value: I): Unit = {
store.write(value)
Hasher.hash(value) match {
case Success(keyHash) => store.write[Long](keyHash.toLong)
case Failure(e) => ()
}
}
def changed(store: CacheStore, value: I): Boolean =
Try { store.read[I] } match {
case Success(prev) =>
Try { store.read[Long] } match {
case Success(prev: Long) =>
Hasher.hash(value) match {
case Success(keyHash) => keyHash.toLong != prev
case Failure(_) => true
case Success(keyHash: Int) => keyHash.toLong != prev
case Failure(_) => true
}
case Failure(_) => true
}

View File

@ -51,10 +51,10 @@ class TrackedSpec extends UnitSpec {
"inputChanged" should "detect that the input has not changed" in {
withStore { store =>
val input0 = 0
val input0 = "foo"
val res0 =
Tracked.inputChanged[Int, Int](store) {
Tracked.inputChanged[String, String](store) {
case (true, in) =>
assert(in === input0)
in
@ -64,7 +64,7 @@ class TrackedSpec extends UnitSpec {
assert(res0 === input0)
val res1 =
Tracked.inputChanged[Int, Int](store) {
Tracked.inputChanged[String, String](store) {
case (true, in) =>
fail()
case (false, in) =>
@ -104,6 +104,35 @@ class TrackedSpec extends UnitSpec {
}
}
"outputChanged" should "detect that the output has not changed" in {
withStore { store =>
val input0: String = "foo"
val p0: () => String = () => input0
val res0 =
Tracked.outputChanged[String, String](store) {
case (true, in) =>
assert(in === input0)
in
case (false, in) =>
fail()
}(implicitly)(p0)
assert(res0 === input0)
val res1 =
Tracked.outputChanged[String, String](store) {
case (true, in) =>
fail()
case (false, in) =>
assert(in === input0)
in
}(implicitly)(p0)
assert(res1 === input0)
}
}
"tstamp tracker" should "have a timestamp of 0 on first invocation" in {
withStore { store =>
Tracked.tstamp(store) { last =>