diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index 549ded4d6..bdebf8deb 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -57,20 +57,12 @@ abstract class JLine extends LineReader { else readLineDirectRaw(prompt, mask) - private[this] val console = ConsoleOut.systemOut private[this] def readLineDirectRaw(prompt: String, mask: Option[Char]): Option[String] = { val newprompt = handleMultilinePrompt(prompt) - val result = mask match { + mask match { case Some(m) => Option(reader.readLine(newprompt, m)) case None => Option(reader.readLine(newprompt)) } - - // since the task progress scrolls the logs upward, and expects the cursors to be on - // the last text line, this moves the cursor up to complensate for user hitting return. - val CursorUp1 = s"\u001B[A" - if (ConsoleAppender.showProgress) console.print(CursorUp1) - else () - result } private[this] def handleMultilinePrompt(prompt: String): String = { @@ -87,7 +79,7 @@ abstract class JLine extends LineReader { private[this] def handleProgress(prompt: String): String = { import ConsoleAppender._ - if (showProgress) s"$ScrollUp$DeleteLine" + prompt + if (showProgress) s"$DeleteLine" + prompt else prompt } diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index a6fab3b55..d0db3a307 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -170,7 +170,11 @@ object EvaluateTask { Some(sharedTraceEvent) } else None - def taskProgress: ExecuteProgress[Task] = new TaskProgress() + def taskProgress: ExecuteProgress[Task] = { + val appender = MainAppender.defaultScreen(StandardMain.console) + val log = LogManager.progressLogger(appender) + new TaskProgress(log) + } // sbt-pgp calls this @deprecated("No longer used", "1.3.0") diff --git a/main/src/main/scala/sbt/internal/AbstractTaskProgress.scala b/main/src/main/scala/sbt/internal/AbstractTaskProgress.scala index 0565a57c0..082c18419 100644 --- a/main/src/main/scala/sbt/internal/AbstractTaskProgress.scala +++ b/main/src/main/scala/sbt/internal/AbstractTaskProgress.scala @@ -75,7 +75,7 @@ object AbstractTaskExecuteProgress { def durationNanos: Long = endNanos - startNanos def startMicros: Long = (startNanos.toDouble / 1000).toLong def durationMicros: Long = (durationNanos.toDouble / 1000).toLong - def currentElapsedSeconds: Long = - ((System.nanoTime() - startNanos).toDouble / 1000000000L).toLong + def currentElapsedMicros: Long = + ((System.nanoTime() - startNanos).toDouble / 1000).toLong } } diff --git a/main/src/main/scala/sbt/internal/LogManager.scala b/main/src/main/scala/sbt/internal/LogManager.scala index 09a1d407e..12678337f 100644 --- a/main/src/main/scala/sbt/internal/LogManager.scala +++ b/main/src/main/scala/sbt/internal/LogManager.scala @@ -246,6 +246,16 @@ object LogManager { s1 } + def progressLogger(appender: Appender): ManagedLogger = { + val log = LogExchange.logger("progress", None, None) + LogExchange.unbindLoggerAppenders("progress") + LogExchange.bindLoggerAppenders( + "progress", + List(appender -> Level.Info) + ) + log + } + // This is the default implementation for the relay appender val defaultRelay: Unit => Appender = _ => defaultRelayImpl diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index 438e1f287..0a3f7bee2 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -8,15 +8,23 @@ package sbt package internal -import sbt.internal.util.{ RMap, ConsoleOut, ConsoleAppender, LogOption, JLine } +import sbt.internal.util.{ + RMap, + ConsoleAppender, + LogOption, + JLine, + ManagedLogger, + ProgressEvent, + ProgressItem +} +import sbt.util.Level import scala.concurrent.{ blocking, Future, ExecutionContext } import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger } -import TaskProgress._ /** * implements task progress display on the shell. */ -private[sbt] final class TaskProgress +private[sbt] final class TaskProgress(log: ManagedLogger) extends AbstractTaskExecuteProgress with ExecuteProgress[Task] { private[this] val isReady = new AtomicBoolean(false) @@ -53,74 +61,39 @@ private[sbt] final class TaskProgress } } - private[this] val console = ConsoleOut.systemOut override def afterAllCompleted(results: RMap[Task, Result]): Unit = { + // send an empty progress report to clear out the previous report + val event = ProgressEvent("Info", Vector(), Some(lastTaskCount.get), None, None) + import sbt.internal.util.codec.JsonProtocol._ + log.logEvent(Level.Info, event) isAllCompleted.set(true) - // completionReport() } private[this] val skipReportTasks = Set("run", "bgRun", "fgRun", "scala", "console", "consoleProject") - private[this] def report(): Unit = console.lockObject.synchronized { - val currentTasks = activeTasks.toList + private[this] def report(): Unit = { + val currentTasks = activeTasks.toVector val ltc = lastTaskCount.get val currentTasksCount = currentTasks.size def report0(): Unit = { - console.print(s"$CursorDown1") - currentTasks foreach { task => - val elapsed = timings.get(task).currentElapsedSeconds - console.println(s"$DeleteLine | => ${taskName(task)} ${elapsed}s") - } - if (ltc > currentTasksCount) deleteConsoleLines(ltc - currentTasksCount) - else () - console.print(cursorUp(math.max(currentTasksCount, ltc) + 1)) + val event = ProgressEvent("Info", currentTasks map { task => + val elapsed = timings.get(task).currentElapsedMicros + ProgressItem(taskName(task), elapsed) + }, Some(ltc), None, None) + import sbt.internal.util.codec.JsonProtocol._ + log.logEvent(Level.Info, event) } if (containsSkipTasks(currentTasks)) () else report0() lastTaskCount.set(currentTasksCount) } - // todo: use logger instead of console - // private[this] def completionReport(): Unit = console.lockObject.synchronized { - // val completedTasks = timings.asScala.toList - // val notableTasks = completedTasks - // .filter({ - // case (_, time: Long) => time >= 1000000000L * 10L - // }) - // .sortBy({ - // case (_, time: Long) => -time - // }) - // .take(5) - // def report0(): Unit = { - // console.print(s"$CursorDown1") - // console.println(s"$DeleteLine notable completed tasks:") - // notableTasks foreach { - // case (task, time) => - // val elapsed = time / 1000000000L - // console.println(s"$DeleteLine | => ${taskName(task)} ${elapsed}s") - // } - // } - // if (containsSkipTasks(notableTasks) || notableTasks.isEmpty) () - // else report0() - // } - - private[this] def containsSkipTasks(tasks: List[Task[_]]): Boolean = + private[this] def containsSkipTasks(tasks: Vector[Task[_]]): Boolean = tasks .map(t => taskName(t)) .exists(n => skipReportTasks.exists(m => n.endsWith("/ " + m))) - - private[this] def deleteConsoleLines(n: Int): Unit = { - (1 to n) foreach { _ => - console.println(DeleteLine) - } - } } private[sbt] object TaskProgress { - final val DeleteLine = "\u001B[2K" - def cursorUp(n: Int): String = s"\u001B[${n}A" - def cursorDown(n: Int): String = s"\u001B[${n}B" - final val CursorDown1 = cursorDown(1) - def isEnabled: Boolean = ConsoleAppender.formatEnabledInEnv && sys.props .get("sbt.supershell") diff --git a/project/Dependencies.scala b/project/Dependencies.scala index be9c738d9..5b0ef4a13 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -10,7 +10,7 @@ object Dependencies { // sbt modules private val ioVersion = "1.3.0-M7" - private val utilVersion = "1.3.0-M5" + private val utilVersion = "1.3.0-M6" private val lmVersion = sys.props.get("sbt.build.lm.version") match { case Some(version) => version diff --git a/sbt/src/main/resources/log4j2.component.properties b/sbt/src/main/resources/log4j2.component.properties deleted file mode 100644 index ee7c90784..000000000 --- a/sbt/src/main/resources/log4j2.component.properties +++ /dev/null @@ -1 +0,0 @@ -Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector