From 8adb24219e3ccc73dea52cbb50df58d687ef2277 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 17 Dec 2024 16:57:38 +0800 Subject: [PATCH] Disable selection execution for run that occurs when enter is pressed during watch (#4149) No tests for now, since our integration test suite doesn't easily support feeding stdin to the mill subprocess --- runner/src/mill/runner/MillMain.scala | 5 ++++- runner/src/mill/runner/Watching.scala | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/runner/src/mill/runner/MillMain.scala b/runner/src/mill/runner/MillMain.scala index a501e68c7f6..fa553492d85 100644 --- a/runner/src/mill/runner/MillMain.scala +++ b/runner/src/mill/runner/MillMain.scala @@ -233,7 +233,7 @@ object MillMain { watch = config.watch.value, streams = streams, setIdle = setIdle, - evaluate = (prevState: Option[RunnerState]) => { + evaluate = (enterKeyPressed: Boolean, prevState: Option[RunnerState]) => { adjustJvmProperties(userSpecifiedProperties, initialSystemProperties) withOutLock( @@ -256,6 +256,9 @@ object MillMain { colored = colored, colors = colors )) { logger => + // Enter key pressed, removing mill-selective-execution.json to + // ensure all tasks re-run even though no inputs may have changed + if (enterKeyPressed) os.remove(out / OutFiles.millSelectiveExecution) SystemStreams.withStreams(logger.systemStreams) { tailManager.withOutErr(logger.outputStream, logger.errorStream) { new MillBuildBootstrap( diff --git a/runner/src/mill/runner/Watching.scala b/runner/src/mill/runner/Watching.scala index ce114bdb69f..a2f7e2b2ef1 100644 --- a/runner/src/mill/runner/Watching.scala +++ b/runner/src/mill/runner/Watching.scala @@ -20,12 +20,13 @@ object Watching { watch: Boolean, streams: SystemStreams, setIdle: Boolean => Unit, - evaluate: Option[T] => Result[T], + evaluate: (Boolean, Option[T]) => Result[T], colors: Colors ): (Boolean, T) = { var prevState: Option[T] = None + var enterKeyPressed = false while (true) { - val Result(watchables, errorOpt, result) = evaluate(prevState) + val Result(watchables, errorOpt, result) = evaluate(enterKeyPressed, prevState) prevState = Some(result) errorOpt.foreach(streams.err.println) if (ringBell) { @@ -42,8 +43,9 @@ object Watching { } val alreadyStale = watchables.exists(!_.validate()) + enterKeyPressed = false if (!alreadyStale) { - Watching.watchAndWait(streams, setIdle, streams.in, watchables, colors) + enterKeyPressed = Watching.watchAndWait(streams, setIdle, streams.in, watchables, colors) } } ??? @@ -55,7 +57,7 @@ object Watching { stdin: InputStream, watched: Seq[Watchable], colors: Colors - ): Unit = { + ): Boolean = { setIdle(true) val watchedPaths = watched.collect { case p: Watchable.Path => p.p.path } val watchedValues = watched.size - watchedPaths.size @@ -68,21 +70,25 @@ object Watching { ).toString ) - statWatchWait(watched, stdin) + val enterKeyPressed = statWatchWait(watched, stdin) setIdle(false) + enterKeyPressed } - def statWatchWait(watched: Seq[Watchable], stdin: InputStream): Unit = { + // Returns `true` if enter key is pressed to re-run tasks explicitly + def statWatchWait(watched: Seq[Watchable], stdin: InputStream): Boolean = { val buffer = new Array[Byte](4 * 1024) - @tailrec def statWatchWait0(): Unit = { + @tailrec def statWatchWait0(): Boolean = { if (watched.forall(_.validate())) { - if (lookForEnterKey()) () - else { + if (lookForEnterKey()) { + mill.main.client.DebugLog.println("ENTER KEY DETECTED") + true + } else { Thread.sleep(100) statWatchWait0() } - } + } else false } @tailrec def lookForEnterKey(): Boolean = {