From a97697a3c7294eb6dda30740fc6cdd92a9966ccd Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 13 Dec 2017 23:28:15 -0800 Subject: First pass at implementing long-lived `Worker` objects. These currently are managed by the `Evaluator`, which is now a stateful object that shouldn't be thrown away every time. We still need to update the code/test-suite to make the `Evaluator` hang around in between `evaluate` calls --- core/src/main/scala/mill/define/Worker.scala | 35 +++++++++++++++++++++++++++ core/src/main/scala/mill/eval/Evaluator.scala | 12 ++++++--- core/src/main/scala/mill/util/Ctx.scala | 11 +++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 core/src/main/scala/mill/define/Worker.scala (limited to 'core') diff --git a/core/src/main/scala/mill/define/Worker.scala b/core/src/main/scala/mill/define/Worker.scala new file mode 100644 index 00000000..385d795f --- /dev/null +++ b/core/src/main/scala/mill/define/Worker.scala @@ -0,0 +1,35 @@ +package mill.define + +import mill.util.Ctx + +import scala.annotation.compileTimeOnly + +/** + * Worker serves three purposes: + * + * - Cache in-memory state between tasks (e.g. object initialization) + * - Including warm classloaders with isolated bytecode + * - Mutex to limit concurrency + * - Manage out-of-process subprocesses <-- skip this for now + * + * Key usage: + * + * - T{ + * ZincWorker().compile(a() + b()) + * } + * + * Desugars into: + * + * - T.zipMap(ZincWorker, a, b){ (z, a1, b1) => z.compile(a1, b1) } + * + * Workers are shoehorned into the `Task` type. This lets them fit nicely in + * the `T{...}` syntax, as well as being statically-inspectable before + * 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]{ + val inputs = Nil + def make(): V + def evaluate(args: Ctx) = args.workerFor(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 9995215a..dffd609e 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -4,11 +4,12 @@ import java.net.URLClassLoader import ammonite.ops._ import ammonite.runtime.SpecialClassLoader -import mill.define.{Graph, Target, Task} +import mill.define.{Graph, Target, Task, Worker} 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 @@ -18,7 +19,7 @@ class Evaluator(workspacePath: Path, log: Logger, sel: List[Mirror.Segment] = List(), classLoaderSig: Seq[(Path, Long)] = Evaluator.classLoaderSig){ - + val workerCache = mutable.Map.empty[Worker[_], _] def evaluate(goals: OSet[Task[_]]): Evaluator.Results = { mkdir(workspacePath) @@ -163,7 +164,12 @@ class Evaluator(workspacePath: Path, val args = new Ctx( targetInputValues.toArray[Any], targetDestPath.orNull, - multiLogger + multiLogger, + new WorkerCtx{ + def workerFor[T](x: mill.define.Worker[T]): T = { + workerCache.getOrElseUpdate(x, x.make()).asInstanceOf[T] + } + } ) val out = System.out diff --git a/core/src/main/scala/mill/util/Ctx.scala b/core/src/main/scala/mill/util/Ctx.scala index 7a0a5694..3b8fb171 100644 --- a/core/src/main/scala/mill/util/Ctx.scala +++ b/core/src/main/scala/mill/util/Ctx.scala @@ -4,7 +4,8 @@ import java.io.PrintStream import ammonite.ops.Path import mill.define.Applicative.ImplicitStub -import mill.util.Ctx.{ArgCtx, DestCtx, LogCtx} +import mill.define.Worker +import mill.util.Ctx.{ArgCtx, DestCtx, LogCtx, WorkerCtx} import scala.annotation.compileTimeOnly @@ -22,10 +23,16 @@ object Ctx{ trait ArgCtx{ def args: IndexedSeq[_] } + trait WorkerCtx{ + def workerFor[T](x: mill.define.Worker[T]): T + } } class Ctx(val args: IndexedSeq[_], val dest: Path, - val log: Logger) extends DestCtx with LogCtx with ArgCtx{ + val log: Logger, + workerCtx0: Ctx.WorkerCtx) extends DestCtx with LogCtx with ArgCtx with WorkerCtx{ + + def workerFor[T](x: mill.define.Worker[T]): T = workerCtx0.workerFor(x) def length = args.length def apply[T](index: Int): T = { if (index >= 0 && index < args.length) args(index).asInstanceOf[T] -- cgit v1.2.3