2010-09-05 17:19:19 +02:00
|
|
|
/* sbt -- Simple Build Tool
|
|
|
|
|
* Copyright 2009, 2010 Mikko Peltonen, Stuart Roebuck, Mark Harrah
|
|
|
|
|
*/
|
|
|
|
|
package sbt
|
|
|
|
|
|
2012-01-29 20:36:27 +01:00
|
|
|
import BasicCommandStrings.ClearOnFailure
|
|
|
|
|
import State.FailureWall
|
2010-09-22 04:02:26 +02:00
|
|
|
import annotation.tailrec
|
2011-03-01 14:51:14 +01:00
|
|
|
import java.io.File
|
2011-09-17 04:04:51 +02:00
|
|
|
import Types.const
|
2010-09-05 17:19:19 +02:00
|
|
|
|
|
|
|
|
trait Watched
|
|
|
|
|
{
|
2011-04-27 03:06:54 +02:00
|
|
|
/** The files watched when an action is run with a preceeding ~ */
|
2011-03-01 14:51:14 +01:00
|
|
|
def watchPaths(s: State): Seq[File] = Nil
|
2010-09-05 17:19:19 +02:00
|
|
|
def terminateWatch(key: Int): Boolean = Watched.isEnter(key)
|
2011-03-01 14:51:14 +01:00
|
|
|
/** The time in milliseconds between checking for changes. The actual time between the last change made to a file and the
|
|
|
|
|
* execution time is between `pollInterval` and `pollInterval*2`.*/
|
|
|
|
|
def pollInterval: Int = Watched.PollDelayMillis
|
2011-09-17 04:04:51 +02:00
|
|
|
/** The message to show when triggered execution waits for sources to change.*/
|
|
|
|
|
def watchingMessage(s: WatchState): String = Watched.defaultWatchingMessage(s)
|
|
|
|
|
/** The message to show before an action is run. */
|
|
|
|
|
def triggeredMessage(s: WatchState): String = Watched.defaultTriggeredMessage(s)
|
2010-09-05 17:19:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object Watched
|
|
|
|
|
{
|
2011-09-17 04:04:51 +02:00
|
|
|
val defaultWatchingMessage: WatchState => String = _.count + ". Waiting for source changes... (press enter to interrupt)"
|
|
|
|
|
val defaultTriggeredMessage: WatchState => String = const("")
|
|
|
|
|
val clearWhenTriggered: WatchState => String = const(clearScreen)
|
|
|
|
|
def clearScreen: String = "\033[2J\033[0;0H"
|
|
|
|
|
|
2011-01-19 00:24:11 +01:00
|
|
|
private[this] class AWatched extends Watched
|
|
|
|
|
|
|
|
|
|
def multi(base: Watched, paths: Seq[Watched]): Watched =
|
|
|
|
|
new AWatched
|
|
|
|
|
{
|
2011-03-01 14:51:14 +01:00
|
|
|
override def watchPaths(s: State) = (base.watchPaths(s) /: paths)(_ ++ _.watchPaths(s))
|
2011-01-19 00:24:11 +01:00
|
|
|
override def terminateWatch(key: Int): Boolean = base.terminateWatch(key)
|
2011-03-01 14:51:14 +01:00
|
|
|
override val pollInterval = (base +: paths).map(_.pollInterval).min
|
2011-09-17 04:04:51 +02:00
|
|
|
override def watchingMessage(s: WatchState) = base.watchingMessage(s)
|
|
|
|
|
override def triggeredMessage(s: WatchState) = base.triggeredMessage(s)
|
2011-01-19 00:24:11 +01:00
|
|
|
}
|
|
|
|
|
def empty: Watched = new AWatched
|
|
|
|
|
|
2011-03-01 14:51:14 +01:00
|
|
|
val PollDelayMillis = 500
|
2010-09-05 17:19:19 +02:00
|
|
|
def isEnter(key: Int): Boolean = key == 10 || key == 13
|
2011-09-17 04:04:51 +02:00
|
|
|
def printIfDefined(msg: String) = if(!msg.isEmpty) System.out.println(msg)
|
2011-01-19 00:24:11 +01:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def executeContinuously(watched: Watched, s: State, next: String, repeat: String): State =
|
2010-09-05 17:19:19 +02:00
|
|
|
{
|
2010-12-19 18:03:10 +01:00
|
|
|
@tailrec def shouldTerminate: Boolean = (System.in.available > 0) && (watched.terminateWatch(System.in.read()) || shouldTerminate)
|
2011-05-15 00:21:41 +02:00
|
|
|
val sourcesFinder = PathFinder { watched watchPaths s }
|
2010-09-05 17:19:19 +02:00
|
|
|
val watchState = s get ContinuousState getOrElse WatchState.empty
|
|
|
|
|
|
|
|
|
|
if(watchState.count > 0)
|
2011-09-17 04:04:51 +02:00
|
|
|
printIfDefined(watched watchingMessage watchState)
|
2010-09-05 17:19:19 +02:00
|
|
|
|
2011-04-27 03:06:54 +02:00
|
|
|
val (triggered, newWatchState, newState) =
|
|
|
|
|
try {
|
|
|
|
|
val (triggered, newWatchState) = SourceModificationWatch.watch(sourcesFinder, watched.pollInterval, watchState)(shouldTerminate)
|
|
|
|
|
(triggered, newWatchState, s)
|
|
|
|
|
}
|
|
|
|
|
catch { case e: Exception =>
|
2011-10-16 23:27:36 +02:00
|
|
|
val log = s.log
|
2011-04-27 03:06:54 +02:00
|
|
|
log.error("Error occurred obtaining files to watch. Terminating continuous execution...")
|
2012-01-29 20:36:27 +01:00
|
|
|
MainLoop.handleException(e, s, log)
|
2011-04-27 03:06:54 +02:00
|
|
|
(false, watchState, s.fail)
|
|
|
|
|
}
|
2010-09-05 17:19:19 +02:00
|
|
|
|
2011-09-17 04:04:51 +02:00
|
|
|
if(triggered) {
|
|
|
|
|
printIfDefined(watched triggeredMessage newWatchState)
|
2011-02-20 04:22:09 +01:00
|
|
|
(ClearOnFailure :: next :: FailureWall :: repeat :: s).put(ContinuousState, newWatchState)
|
2011-09-17 04:04:51 +02:00
|
|
|
}
|
2010-09-05 17:19:19 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (System.in.available() > 0) System.in.read()
|
|
|
|
|
s.put(ContinuousState, WatchState.empty)
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-21 02:18:58 +02:00
|
|
|
val ContinuousState = AttributeKey[WatchState]("watch state", "Internal: tracks state for continuous execution.")
|
|
|
|
|
val Configuration = AttributeKey[Watched]("watched-configuration", "Configures continuous execution.")
|
2010-09-05 17:19:19 +02:00
|
|
|
}
|