Add watchPersistFileStamps key

The persistentFileStampCache does seem to work pretty well but in case
users encounter issues, I add a boolean flag that allows the user to
turn this behavior off and always re-stamp every source file in every
task evaluation run.
This commit is contained in:
Ethan Atkins 2019-05-09 13:26:21 -07:00
parent ec09e73437
commit 4007810adb
3 changed files with 17 additions and 11 deletions

View File

@ -153,6 +153,7 @@ object Defaults extends BuildCommon {
inputFileStamper :== sbt.nio.FileStamper.Hash,
outputFileStamper :== sbt.nio.FileStamper.LastModified,
watchForceTriggerOnAnyChange :== true,
watchPersistFileStamps :== true,
watchTriggers :== Nil,
clean := { () },
sbt.nio.Keys.fileStampCache := {

View File

@ -291,20 +291,22 @@ private[sbt] object Continuous extends DeprecatedContinuous {
} else {
FileTreeRepository.default
}
val attributeMap = new FileStamp.Cache
repo.addObserver(t => attributeMap.invalidate(t.path))
val fileStampCache = new FileStamp.Cache
repo.addObserver(t => fileStampCache.invalidate(t.path))
try {
val stateWithRepo = state
.put(globalFileTreeRepository, repo)
.put(persistentFileStampCache, attributeMap)
setup(stateWithRepo, command) { (commands, s, valid, invalid) =>
val stateWithRepo = state.put(globalFileTreeRepository, repo)
val fullState =
if (extracted.get(watchPersistFileStamps))
stateWithRepo.put(persistentFileStampCache, fileStampCache)
else stateWithRepo
setup(fullState, command) { (commands, s, valid, invalid) =>
EvaluateTask.withStreams(extracted.structure, s)(_.use(streams in Global) { streams =>
implicit val logger: Logger = streams.log
if (invalid.isEmpty) {
val currentCount = new AtomicInteger(count)
val configs = getAllConfigs(valid.map(v => v._1 -> v._2))
val callbacks =
aggregate(configs, logger, in, s, currentCount, isCommand, commands, attributeMap)
aggregate(configs, logger, in, s, currentCount, isCommand, commands, fileStampCache)
val task = () => {
currentCount.getAndIncrement()
// abort as soon as one of the tasks fails
@ -401,7 +403,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
count: AtomicInteger,
isCommand: Boolean,
commands: Seq[String],
attributeMap: FileStamp.Cache
fileStampCache: FileStamp.Cache
)(
implicit extracted: Extracted
): Callbacks = {
@ -411,7 +413,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
val onStart: () => Watch.Action = getOnStart(project, commands, configs, rawLogger, count)
val nextInputEvent: () => Watch.Action = parseInputEvents(configs, state, inputStream, logger)
val (nextFileEvent, cleanupFileMonitor): (() => Option[(Watch.Event, Watch.Action)], () => Unit) =
getFileEvents(configs, rawLogger, state, count, commands, attributeMap)
getFileEvents(configs, rawLogger, state, count, commands, fileStampCache)
val nextEvent: () => Watch.Action =
combineInputAndFileEvents(nextInputEvent, nextFileEvent, logger)
val onExit = () => {
@ -476,7 +478,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
state: State,
count: AtomicInteger,
commands: Seq[String],
attributeMap: FileStamp.Cache
fileStampCache: FileStamp.Cache
)(implicit extracted: Extracted): (() => Option[(Watch.Event, Watch.Action)], () => Unit) = {
val trackMetaBuild = configs.forall(_.watchSettings.trackMetaBuild)
val buildGlobs =
@ -491,7 +493,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
def watchEvent(stamper: FileStamper, forceTrigger: Boolean): Option[Watch.Event] = {
if (!event.exists) {
Some(Deletion(event))
attributeMap.remove(event.path) match {
fileStampCache.remove(event.path) match {
case null => None
case _ => Some(Deletion(event))
}

View File

@ -85,6 +85,9 @@ object Keys {
val watchOnTermination = settingKey[(Watch.Action, String, Int, State) => State](
"Transforms the state upon completion of a watch. The String argument is the command that was run during the watch. The Int parameter specifies how many times the command was run during the watch."
).withRank(DSetting)
val watchPersistFileStamps = settingKey[Boolean](
"Toggles whether or not the continuous build will reuse the file stamps computed in previous runs. Setting this to true decrease watch startup latency but could cause inconsistent results if many source files are concurrently modified."
).withRank(DSetting)
val watchStartMessage = settingKey[(Int, String, Seq[String]) => Option[String]](
"The message to show when triggered execution waits for sources to change. The parameters are the current watch iteration count, the current project name and the tasks that are being run with each build."
).withRank(DSetting)