From d38196041663959ed71881d6d83a27d4639f3134 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 14 Dec 2017 07:29:33 -0800 Subject: Move `Evaluator`s to be long lived, and make tests pass --- core/src/main/scala/mill/Main.scala | 13 +++++++- core/src/main/scala/mill/define/Applicative.scala | 3 ++ core/src/main/scala/mill/define/Task.scala | 4 +++ core/src/main/scala/mill/define/Worker.scala | 6 ++-- core/src/main/scala/mill/eval/Evaluator.scala | 7 ++-- .../main/scala/mill/main/ReplApplyHandler.scala | 16 ++------- core/src/main/scala/mill/util/Ctx.scala | 16 ++++----- .../test/scala/mill/define/ApplicativeTests.scala | 3 ++ core/src/test/scala/mill/eval/FailureTests.scala | 38 ++++++++++++---------- 9 files changed, 59 insertions(+), 47 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index afc59e33..90a70edb 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -124,7 +124,18 @@ object Main { | |@main def idea() = mill.scalaplugin.GenIdea(build)(discovered) | - |implicit val replApplyHandler = new mill.main.ReplApplyHandler(build)(discovered)""".stripMargin + |val mirror = mill.Main.discoverMirror(build) match{ + | case Left(err) => throw new Exception("Failed discovery consistency check: " + err) + | case Right(mirror) => mirror + |} + | + |val evaluator = new mill.eval.Evaluator( + | ammonite.ops.pwd / 'out, + | mill.discover.Discovered.mapping(build)(mirror), + | new mill.util.PrintLogger(true) + |) + | + |implicit val replApplyHandler = new mill.main.ReplApplyHandler(evaluator)""".stripMargin ) import ammonite.main.Cli diff --git a/core/src/main/scala/mill/define/Applicative.scala b/core/src/main/scala/mill/define/Applicative.scala index 686220f7..592708cb 100644 --- a/core/src/main/scala/mill/define/Applicative.scala +++ b/core/src/main/scala/mill/define/Applicative.scala @@ -48,6 +48,8 @@ object Applicative { (cb: (A, B, C, D, E, F, G, H, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f, g, h)){case ((a, b, c, d, e, f, g, h), x) => cb(a, b, c, d, e, f, g, h, x)} def zipMap[A, B, C, D, E, F, G, H, I, R](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H], i: T[I]) (cb: (A, B, C, D, E, F, G, H, I, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f, g, h, i)){case ((a, b, c, d, e, f, g, h, i), x) => cb(a, b, c, d, e, f, g, h, i, x)} + def zipMap[A, B, C, D, E, F, G, H, I, J, R](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H], i: T[I], j: T[J]) + (cb: (A, B, C, D, E, F, G, H, I, J, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f, g, h, i, j)){case ((a, b, c, d, e, f, g, h, i, j), x) => cb(a, b, c, d, e, f, g, h, i, j, x)} def zip(): T[Unit] def zip[A](a: T[A]): T[Tuple1[A]] @@ -58,6 +60,7 @@ object Applicative { def zip[A, B, C, D, E, F](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F]): T[(A, B, C, D, E, F)] def zip[A, B, C, D, E, F, G, H](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H]): T[(A, B, C, D, E, F, G, H)] def zip[A, B, C, D, E, F, G, H, I](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H], i: T[I]): T[(A, B, C, D, E, F, G, H, I)] + def zip[A, B, C, D, E, F, G, H, I, J](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H], i: T[I], j: T[J]): T[(A, B, C, D, E, F, G, H, I, J)] } diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index 8c91997b..e88ad8c6 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -122,6 +122,10 @@ object Target extends Applicative.Applyer[Task, Task, Result, Ctx]{ val inputs = Seq(a, b, c, d, e, f, g, h, i) def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5), args[G](6), args[H](7), args[I](8)) } + def zip[A, B, C, D, E, F, G, H, I, J](a: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F], g: Task[G], h: Task[H], i: Task[I], j: Task[J]) = new Task[(A, B, C, D, E, F, G, H, I, J)]{ + val inputs = Seq(a, b, c, d, e, f, g, h, i, j) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5), args[G](6), args[H](7), args[I](8), args[J](9)) + } } class TargetImpl[+T](t: Task[T], enclosing: String) extends Target[T] { val inputs = Seq(t) diff --git a/core/src/main/scala/mill/define/Worker.scala b/core/src/main/scala/mill/define/Worker.scala index 385d795f..0a6d31d2 100644 --- a/core/src/main/scala/mill/define/Worker.scala +++ b/core/src/main/scala/mill/define/Worker.scala @@ -2,8 +2,6 @@ package mill.define import mill.util.Ctx -import scala.annotation.compileTimeOnly - /** * Worker serves three purposes: * @@ -27,9 +25,9 @@ import scala.annotation.compileTimeOnly * evaluating the task graph. The Worker defines how it is evaluated, but it's * evaluation/caching/lifecycle are controlled by the `Evaluator` */ -trait Worker[V] extends Task[V]{ +trait Worker[V] extends Task[V] with Ctx.Loader[V]{ val inputs = Nil def make(): V - def evaluate(args: Ctx) = args.workerFor(this) + def evaluate(args: Ctx) = args.load(this) def path = this.getClass.getCanonicalName.filter(_ != '$').split('.') } \ No newline at end of file diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index dffd609e..fab5dbe9 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -9,7 +9,6 @@ import mill.discover.Mirror import mill.discover.Mirror.LabelledTarget import mill.discover.Mirror.Segment.{Cross, Label} import mill.util -import mill.util.Ctx.WorkerCtx import mill.util._ import scala.collection.mutable @@ -19,7 +18,7 @@ class Evaluator(workspacePath: Path, log: Logger, sel: List[Mirror.Segment] = List(), classLoaderSig: Seq[(Path, Long)] = Evaluator.classLoaderSig){ - val workerCache = mutable.Map.empty[Worker[_], _] + val workerCache = mutable.Map.empty[Ctx.Loader[_], Any] def evaluate(goals: OSet[Task[_]]): Evaluator.Results = { mkdir(workspacePath) @@ -165,8 +164,8 @@ class Evaluator(workspacePath: Path, targetInputValues.toArray[Any], targetDestPath.orNull, multiLogger, - new WorkerCtx{ - def workerFor[T](x: mill.define.Worker[T]): T = { + new Ctx.LoaderCtx{ + def load[T](x: Ctx.Loader[T]): T = { workerCache.getOrElseUpdate(x, x.make()).asInstanceOf[T] } } diff --git a/core/src/main/scala/mill/main/ReplApplyHandler.scala b/core/src/main/scala/mill/main/ReplApplyHandler.scala index 2e8d2da7..b2b688df 100644 --- a/core/src/main/scala/mill/main/ReplApplyHandler.scala +++ b/core/src/main/scala/mill/main/ReplApplyHandler.scala @@ -8,21 +8,11 @@ import mill.discover.Discovered import mill.eval.Evaluator import mill.util.{OSet, PrintLogger} -class ReplApplyHandler[T: Discovered](obj: T) extends ApplyHandler[Task] { +class ReplApplyHandler(evaluator: Evaluator) extends ApplyHandler[Task] { // Evaluate classLoaderSig only once in the REPL to avoid busting caches // as the user enters more REPL commands and changes the classpath val classLoaderSig = Evaluator.classLoaderSig - override def apply[V](t: Task[V]) = discoverMirror(obj) match{ - case Left(err) => - throw new Exception("Failed discovery consistency check: " + err) - case Right(mirror) => - val log = new PrintLogger(true) - val evaluator = new Evaluator( - pwd / 'out, - Discovered.mapping(obj)(mirror), - log, - classLoaderSig = classLoaderSig - ) - evaluator.evaluate(OSet(t)).values.head.asInstanceOf[V] + override def apply[V](t: Task[V]) = { + evaluator.evaluate(OSet(t)).values.head.asInstanceOf[V] } } diff --git a/core/src/main/scala/mill/util/Ctx.scala b/core/src/main/scala/mill/util/Ctx.scala index 3b8fb171..38a8aee3 100644 --- a/core/src/main/scala/mill/util/Ctx.scala +++ b/core/src/main/scala/mill/util/Ctx.scala @@ -1,11 +1,8 @@ package mill.util -import java.io.PrintStream - import ammonite.ops.Path import mill.define.Applicative.ImplicitStub -import mill.define.Worker -import mill.util.Ctx.{ArgCtx, DestCtx, LogCtx, WorkerCtx} +import mill.util.Ctx.{ArgCtx, DestCtx, LoaderCtx, LogCtx} import scala.annotation.compileTimeOnly @@ -23,16 +20,19 @@ object Ctx{ trait ArgCtx{ def args: IndexedSeq[_] } - trait WorkerCtx{ - def workerFor[T](x: mill.define.Worker[T]): T + trait LoaderCtx{ + def load[T](x: Loader[T]): T + } + trait Loader[T]{ + def make(): T } } class Ctx(val args: IndexedSeq[_], val dest: Path, val log: Logger, - workerCtx0: Ctx.WorkerCtx) extends DestCtx with LogCtx with ArgCtx with WorkerCtx{ + workerCtx0: Ctx.LoaderCtx) extends DestCtx with LogCtx with ArgCtx with LoaderCtx{ - def workerFor[T](x: mill.define.Worker[T]): T = workerCtx0.workerFor(x) + def load[T](x: Ctx.Loader[T]): T = workerCtx0.load(x) def length = args.length def apply[T](index: Int): T = { if (index >= 0 && index < args.length) args(index).asInstanceOf[T] diff --git a/core/src/test/scala/mill/define/ApplicativeTests.scala b/core/src/test/scala/mill/define/ApplicativeTests.scala index 9991b9f0..0dbc91a0 100644 --- a/core/src/test/scala/mill/define/ApplicativeTests.scala +++ b/core/src/test/scala/mill/define/ApplicativeTests.scala @@ -44,6 +44,9 @@ object ApplicativeTests extends TestSuite { def zip[A, B, C, D, E, F, G, H, I](a: O[A], b: O[B], c: O[C], d: O[D], e: O[E], f: O[F], g: O[G], h: O[H], i: O[I]) = { for(a <- a; b <- b; c <- c; d <- d; e <- e; f <- f; g <- g; h <- h; i <- i) yield (a, b, c, d, e, f, g, h, i) } + def zip[A, B, C, D, E, F, G, H, I, J](a: O[A], b: O[B], c: O[C], d: O[D], e: O[E], f: O[F], g: O[G], h: O[H], i: O[I], j: O[J]) = { + for(a <- a; b <- b; c <- c; d <- d; e <- e; f <- f; g <- g; h <- h; i <- i; j <- j) yield (a, b, c, d, e, f, g, h, i, j) + } } class Counter{ var value = 0 diff --git a/core/src/test/scala/mill/eval/FailureTests.scala b/core/src/test/scala/mill/eval/FailureTests.scala index 2279d931..4c3b6fca 100644 --- a/core/src/test/scala/mill/eval/FailureTests.scala +++ b/core/src/test/scala/mill/eval/FailureTests.scala @@ -11,13 +11,12 @@ object FailureTests extends TestSuite{ def workspace(implicit tp: TestPath) = { ammonite.ops.pwd / 'target / 'workspace / 'failure / implicitly[TestPath].value } - val tests = Tests{ - val graphs = new mill.util.TestGraphs() - import graphs._ - def check[T: Discovered](base: T) - (target: T => Target[_], expectedFailCount: Int, expectedRawValues: Seq[Result[_]]) - (implicit tp: TestPath) = { - val evaluator = new Evaluator(workspace, Discovered.mapping(base), DummyLogger) + class Checker[T: Discovered](base: T)(implicit tp: TestPath){ + + val evaluator = new Evaluator(workspace, Discovered.mapping(base), DummyLogger) + + def apply(target: T => Target[_], expectedFailCount: Int, expectedRawValues: Seq[Result[_]]) = { + val res = evaluator.evaluate(OSet(target(base))) assert( res.rawValues == expectedRawValues, @@ -25,10 +24,15 @@ object FailureTests extends TestSuite{ ) } + } + val tests = Tests{ + val graphs = new mill.util.TestGraphs() + import graphs._ + 'evaluateSingle - { ammonite.ops.rm(ammonite.ops.Path(workspace, ammonite.ops.pwd)) - - check(singleton)( + val check = new Checker(singleton) + check( target = _.single, expectedFailCount = 0, expectedRawValues = Seq(Result.Success(0)) @@ -36,7 +40,7 @@ object FailureTests extends TestSuite{ singleton.single.failure = Some("lols") - check(singleton)( + check( target = _.single, expectedFailCount = 1, expectedRawValues = Seq(Result.Failure("lols")) @@ -44,7 +48,7 @@ object FailureTests extends TestSuite{ singleton.single.failure = None - check(singleton)( + check( target = _.single, expectedFailCount = 0, expectedRawValues = Seq(Result.Success(0)) @@ -55,7 +59,7 @@ object FailureTests extends TestSuite{ singleton.single.exception = Some(ex) - check(singleton)( + check( target = _.single, expectedFailCount = 1, expectedRawValues = Seq(Result.Exception(ex)) @@ -63,8 +67,8 @@ object FailureTests extends TestSuite{ } 'evaluatePair - { ammonite.ops.rm(ammonite.ops.Path(workspace, ammonite.ops.pwd)) - - check(pair)( + val check = new Checker(pair) + check( _.down, expectedFailCount = 0, expectedRawValues = Seq(Result.Success(0)) @@ -72,7 +76,7 @@ object FailureTests extends TestSuite{ pair.up.failure = Some("lols") - check(pair)( + check( _.down, expectedFailCount = 1, expectedRawValues = Seq(Result.Skipped) @@ -80,7 +84,7 @@ object FailureTests extends TestSuite{ pair.up.failure = None - check(pair)( + check( _.down, expectedFailCount = 0, expectedRawValues = Seq(Result.Success(0)) @@ -88,7 +92,7 @@ object FailureTests extends TestSuite{ pair.up.exception = Some(new IndexOutOfBoundsException()) - check(pair)( + check( _.down, expectedFailCount = 1, expectedRawValues = Seq(Result.Skipped) -- cgit v1.2.3