summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-01-04 21:00:00 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-01-04 21:00:00 -0800
commitfb68da0e6803f2f8eb948515672bd2297aaa1709 (patch)
tree0bb086b005fbe96f8e68e4c2f4baf20706d48d6e
parent53f55cbba68617ff1a96c77ebb061276e4c8248d (diff)
downloadmill-fb68da0e6803f2f8eb948515672bd2297aaa1709.tar.gz
mill-fb68da0e6803f2f8eb948515672bd2297aaa1709.tar.bz2
mill-fb68da0e6803f2f8eb948515672bd2297aaa1709.zip
First pass at a ticker-based progress logger to reduce the spamminess of the console
-rw-r--r--core/src/main/scala/mill/Main.scala6
-rw-r--r--core/src/main/scala/mill/eval/Evaluator.scala28
-rw-r--r--core/src/main/scala/mill/main/MainRunner.scala6
-rw-r--r--core/src/main/scala/mill/main/ReplApplyHandler.scala11
-rw-r--r--core/src/main/scala/mill/main/RunScript.scala5
-rw-r--r--core/src/main/scala/mill/util/Logger.scala68
-rw-r--r--scalalib/src/main/scala/mill/scalalib/Module.scala3
-rw-r--r--scalalib/src/main/scala/mill/scalalib/TestRunner.scala10
8 files changed, 110 insertions, 27 deletions
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala
index 66f7ee59..479366b2 100644
--- a/core/src/main/scala/mill/Main.scala
+++ b/core/src/main/scala/mill/Main.scala
@@ -46,7 +46,11 @@ object Main {
else cliConfig.copy(
predefCode =
"""import $file.build, build._
- |implicit val replApplyHandler = mill.main.ReplApplyHandler(repl.pprinter(), build.mapping)
+ |implicit val replApplyHandler = mill.main.ReplApplyHandler(
+ | interp.colors(),
+ | repl.pprinter(),
+ | build.mapping
+ |)
|repl.pprinter() = replApplyHandler.pprinter
|import replApplyHandler.generatedEval._
|
diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala
index ccb81da3..9149e532 100644
--- a/core/src/main/scala/mill/eval/Evaluator.scala
+++ b/core/src/main/scala/mill/eval/Evaluator.scala
@@ -58,8 +58,10 @@ class Evaluator[T](val workspacePath: Path,
val evaluated = new OSet.Mutable[Task[_]]
val results = mutable.LinkedHashMap.empty[Task[_], Result[Any]]
- for ((terminal, group)<- sortedGroups.items()){
- val (newResults, newEvaluated) = evaluateGroupCached(terminal, group, results)
+ for (((terminal, group), i) <- sortedGroups.items().zipWithIndex){
+ // Increment the counter message by 1 to go from 1/10 to 10/10 instead of 0/10 to 9/10
+ val counterMsg = (i+1) + "/" + sortedGroups.keyCount
+ val (newResults, newEvaluated) = evaluateGroupCached(terminal, group, results, counterMsg)
for(ev <- newEvaluated){
evaluated.append(ev)
}
@@ -83,7 +85,8 @@ class Evaluator[T](val workspacePath: Path,
def evaluateGroupCached(terminal: Either[Task[_], Labelled[_]],
group: OSet[Task[_]],
- results: collection.Map[Task[_], Result[Any]]): (collection.Map[Task[_], Result[Any]], Seq[Task[_]]) = {
+ results: collection.Map[Task[_], Result[Any]],
+ counterMsg: String): (collection.Map[Task[_], Result[Any]], Seq[Task[_]]) = {
val externalInputs = group.items.flatMap(_.inputs).filter(!group.contains(_))
@@ -95,7 +98,14 @@ class Evaluator[T](val workspacePath: Path,
terminal match{
case Left(task) =>
- evaluateGroup(group, results, groupBasePath = None, paths = None, maybeTargetLabel = None)
+ evaluateGroup(
+ group,
+ results,
+ groupBasePath = None,
+ paths = None,
+ maybeTargetLabel = None,
+ counterMsg = counterMsg
+ )
case Right(labelledTarget) =>
val paths = Evaluator.resolveDestPaths(workspacePath, labelledTarget.segments)
val groupBasePath = basePath / Evaluator.makeSegmentStrings(labelledTarget.segments)
@@ -128,7 +138,8 @@ class Evaluator[T](val workspacePath: Path,
results,
groupBasePath = Some(groupBasePath),
paths = Some(paths),
- maybeTargetLabel = Some(msgParts.mkString)
+ maybeTargetLabel = Some(msgParts.mkString),
+ counterMsg = counterMsg
)
newResults(labelledTarget.target) match{
@@ -161,7 +172,8 @@ class Evaluator[T](val workspacePath: Path,
results: collection.Map[Task[_], Result[Any]],
groupBasePath: Option[Path],
paths: Option[Evaluator.Paths],
- maybeTargetLabel: Option[String]) = {
+ maybeTargetLabel: Option[String],
+ counterMsg: String) = {
val newEvaluated = mutable.Buffer.empty[Task[_]]
@@ -177,7 +189,7 @@ class Evaluator[T](val workspacePath: Path,
val logRun = inputResults.forall(_.isInstanceOf[Result.Success[_]])
- if(logRun) { log.info("Running " + targetLabel) }
+ if(logRun) { log.ticker(s"[$counterMsg] $targetLabel ") }
}
val multiLogger = resolveLogger(paths.map(_.log))
@@ -235,7 +247,7 @@ class Evaluator[T](val workspacePath: Path,
case None => log
case Some(path) =>
rm(path)
- MultiLogger(log, FileLogger(path))
+ MultiLogger(log.colored, log, FileLogger(log.colored, path))
}
}
diff --git a/core/src/main/scala/mill/main/MainRunner.scala b/core/src/main/scala/mill/main/MainRunner.scala
index 1b2322b0..4a6be436 100644
--- a/core/src/main/scala/mill/main/MainRunner.scala
+++ b/core/src/main/scala/mill/main/MainRunner.scala
@@ -1,9 +1,10 @@
package mill.main
import java.io.{InputStream, OutputStream, PrintStream}
+import ammonite.Main
import ammonite.interp.{Interpreter, Preprocessor}
import ammonite.ops.Path
-import ammonite.util.{Imports, Name, Res, Util}
+import ammonite.util._
import mill.discover.Discovered
import mill.eval.{Evaluator, PathRef}
import upickle.Js
@@ -21,6 +22,7 @@ class MainRunner(config: ammonite.main.Cli.Config, show: Boolean,
stdErr: OutputStream)
extends ammonite.MainRunner(config, outprintStream, errPrintStream, stdIn, stdOut, stdErr){
var lastEvaluator: Option[(Seq[(Path, Long)], Evaluator[_])] = None
+
override def runScript(scriptPath: Path, scriptArgs: List[String]) =
watchLoop(
isRepl = false,
@@ -28,7 +30,7 @@ class MainRunner(config: ammonite.main.Cli.Config, show: Boolean,
mainCfg => {
val (result, interpWatched) = RunScript.runScript(
mainCfg.wd, scriptPath, mainCfg.instantiateInterpreter(), scriptArgs, lastEvaluator,
- errPrintStream, errPrintStream
+ errPrintStream, errPrintStream, colors
)
result match{
diff --git a/core/src/main/scala/mill/main/ReplApplyHandler.scala b/core/src/main/scala/mill/main/ReplApplyHandler.scala
index 6b065a58..e68dfd93 100644
--- a/core/src/main/scala/mill/main/ReplApplyHandler.scala
+++ b/core/src/main/scala/mill/main/ReplApplyHandler.scala
@@ -10,14 +10,21 @@ import mill.util.OSet
import scala.collection.mutable
object ReplApplyHandler{
- def apply[T](pprinter0: pprint.PPrinter, mapping: Discovered.Mapping[T]) = {
+ def apply[T](colors: ammonite.util.Colors,
+ pprinter0: pprint.PPrinter,
+ mapping: Discovered.Mapping[T]) = {
new ReplApplyHandler(
pprinter0,
new mill.eval.Evaluator(
ammonite.ops.pwd / 'out,
ammonite.ops.pwd,
mapping,
- new mill.util.PrintLogger(true, System.err, System.err)
+ new mill.util.PrintLogger(
+ colors != ammonite.util.Colors.BlackWhite,
+ colors,
+ System.err,
+ System.err
+ )
)
)
}
diff --git a/core/src/main/scala/mill/main/RunScript.scala b/core/src/main/scala/mill/main/RunScript.scala
index e2c8ce6c..bd27039c 100644
--- a/core/src/main/scala/mill/main/RunScript.scala
+++ b/core/src/main/scala/mill/main/RunScript.scala
@@ -27,10 +27,11 @@ object RunScript{
scriptArgs: Seq[String],
lastEvaluator: Option[(Seq[(Path, Long)], Evaluator[_])],
infoStream: PrintStream,
- errStream: PrintStream)
+ errStream: PrintStream,
+ colors: ammonite.util.Colors)
: (Res[(Evaluator[_], Seq[(Path, Long)], Either[String, Seq[Js.Value]])], Seq[(Path, Long)]) = {
- val log = new PrintLogger(true, infoStream, errStream)
+ val log = new PrintLogger(colors != ammonite.util.Colors.BlackWhite, colors, infoStream, errStream)
val (evalRes, interpWatched) = lastEvaluator match{
case Some((prevInterpWatchedSig, prevEvaluator))
if watchedSigUnchanged(prevInterpWatchedSig) =>
diff --git a/core/src/main/scala/mill/util/Logger.scala b/core/src/main/scala/mill/util/Logger.scala
index 36c825a6..5a843002 100644
--- a/core/src/main/scala/mill/util/Logger.scala
+++ b/core/src/main/scala/mill/util/Logger.scala
@@ -1,38 +1,84 @@
package mill.util
-import java.io.{FileOutputStream, PrintStream}
+import java.io._
import ammonite.ops.Path
import ammonite.util.Colors
trait Logger {
+ def colored: Boolean
val outputStream: PrintStream
def info(s: String): Unit
def error(s: String): Unit
+
+ /**
+ * Like [[info]], but if two calls to [[ticker]] are made consecutively
+ * without any calls to [[info]]/[[error]][[outputStream]] in between,
+ * the second call to [[ticker]] over-writes the first one in the console.
+ * This is useful for displaying loading bars, progress updates or all other
+ * sorts of fast-changing information to the user
+ */
+ def ticker(s: String): Unit
def close(): Unit = ()
}
object DummyLogger extends Logger {
+ def colored = false
object outputStream extends PrintStream(_ => ())
def info(s: String) = ()
def error(s: String) = ()
+ def ticker(s: String) = ()
}
-case class PrintLogger(coloredOutput: Boolean,
+case class PrintLogger(colored: Boolean,
+ colors: ammonite.util.Colors,
infoStream: PrintStream,
errorStream: PrintStream) extends Logger {
- override val outputStream = infoStream
- val colors =
- if(coloredOutput) Colors.Default
- else Colors.BlackWhite
+ var lastLineTicker = false
+ override val outputStream = new PrintStream(
+ new OutputStream {
+ override def write(b: Array[Byte]): Unit = {
+ lastLineTicker = false
+ infoStream.write(b)
+ }
+
+ override def write(b: Array[Byte], off: Int, len: Int): Unit = {
+ lastLineTicker = false
+ infoStream.write(b, off, len)
+ }
+
+ def write(b: Int) = {
+ lastLineTicker = false
+ infoStream.write(b)
+ }
+ }
+ )
- def info(s: String) = infoStream.println(colors.info()(s))
- def error(s: String) = errorStream.println(colors.error()(s))
+ def info(s: String) = {
+ lastLineTicker = false
+ infoStream.println(colors.info()(s))
+ }
+ def error(s: String) = {
+ lastLineTicker = false
+ errorStream.println(colors.error()(s))
+ }
+ def ticker(s: String) = {
+ if (lastLineTicker){
+ val p = new PrintWriter(infoStream)
+ val nav = new ammonite.terminal.AnsiNav(p)
+ nav.up(1)
+ nav.clearLine(2)
+ nav.left(9999)
+ p.flush()
+ }
+ lastLineTicker = true
+ infoStream.println(colors.info()(s))
+ }
}
-case class FileLogger(file: Path) extends Logger {
+case class FileLogger(colored: Boolean, file: Path) extends Logger {
private[this] var outputStreamUsed: Boolean = false
lazy val outputStream = {
@@ -42,13 +88,14 @@ case class FileLogger(file: Path) extends Logger {
def info(s: String) = outputStream.println(s)
def error(s: String) = outputStream.println(s)
+ def ticker(s: String) = outputStream.println(s)
override def close() = {
if (outputStreamUsed)
outputStream.close()
}
}
-case class MultiLogger(streams: Logger*) extends Logger {
+case class MultiLogger(colored: Boolean, streams: Logger*) extends Logger {
lazy val outputStream: PrintStream =
new PrintStream(b => streams.foreach(_.outputStream.write(b))) {
override def flush() = streams.foreach(_.outputStream.flush())
@@ -57,5 +104,6 @@ case class MultiLogger(streams: Logger*) extends Logger {
def info(s: String) = streams.foreach(_.info(s))
def error(s: String) = streams.foreach(_.error(s))
+ def ticker(s: String) = streams.foreach(_.ticker(s))
override def close() = streams.foreach(_.close())
} \ No newline at end of file
diff --git a/scalalib/src/main/scala/mill/scalalib/Module.scala b/scalalib/src/main/scala/mill/scalalib/Module.scala
index 3cd4cde0..c6fcfb4d 100644
--- a/scalalib/src/main/scala/mill/scalalib/Module.scala
+++ b/scalalib/src/main/scala/mill/scalalib/Module.scala
@@ -39,7 +39,8 @@ trait TestModule extends Module with TaskModule {
(runDepClasspath().map(_.path) :+ compile().classes.path).distinct.mkString(" "),
Seq(compile().classes.path).mkString(" "),
args.mkString(" "),
- outputPath.toString
+ outputPath.toString,
+ T.ctx().log.colored.toString
),
workingDir = forkWorkingDir
)
diff --git a/scalalib/src/main/scala/mill/scalalib/TestRunner.scala b/scalalib/src/main/scala/mill/scalalib/TestRunner.scala
index 734bc1e0..304ae989 100644
--- a/scalalib/src/main/scala/mill/scalalib/TestRunner.scala
+++ b/scalalib/src/main/scala/mill/scalalib/TestRunner.scala
@@ -6,11 +6,13 @@ import java.net.URLClassLoader
import java.util.zip.ZipInputStream
import ammonite.ops.{Path, ls, pwd}
+import ammonite.util.Colors
import mill.util.Ctx.LogCtx
import mill.util.PrintLogger
import sbt.testing._
import upickle.Js
import mill.util.JsonFormatters._
+
import scala.collection.mutable
object TestRunner {
@@ -49,7 +51,13 @@ object TestRunner {
entireClasspath = args(1).split(" ").map(Path(_)),
testClassfilePath = args(2).split(" ").map(Path(_)),
args = args(3) match{ case "" => Nil case x => x.split(" ").toList }
- )(new PrintLogger(true, System.err, System.err))
+ )(new PrintLogger(
+ args(5) == "true",
+ if(args(5) == "true") Colors.Default
+ else Colors.BlackWhite,
+ System.err,
+ System.err
+ ))
val outputPath = args(4)
ammonite.ops.write(Path(outputPath), upickle.default.write(result))