diff options
-rw-r--r-- | core/src/main/scala/mill/define/Worker.scala | 35 | ||||
-rw-r--r-- | core/src/main/scala/mill/eval/Evaluator.scala | 12 | ||||
-rw-r--r-- | core/src/main/scala/mill/util/Ctx.scala | 11 | ||||
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala | 28 |
4 files changed, 70 insertions, 16 deletions
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] diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala b/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala index 5c9aa4f7..637906a5 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala @@ -7,6 +7,7 @@ import java.util.Optional import ammonite.ops._ import coursier.{Cache, Fetch, MavenRepository, Repository, Resolution} +import mill.define.Worker import mill.eval.{PathRef, Result} import mill.util.Ctx import sbt.internal.inc._ @@ -21,6 +22,12 @@ object CompilationResult { // analysisFile is represented by Path, so we won't break caches after file changes case class CompilationResult(analysisFile: Path, classes: PathRef) +object ZincWorker extends Worker[ZincWorker]{ + def make() = new ZincWorker +} +class ZincWorker{ + var scalaInstanceCache = Option.empty[(Long, ScalaInstance)] +} object Lib{ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { override def analysis(classpathEntry: File): Optional[CompileAnalysis] = @@ -30,9 +37,15 @@ object Lib{ Locate.definesClass(classpathEntry) } - var scalaInstanceCache = Option.empty[(Long, ScalaInstance)] + def grepJar(classPath: Seq[Path], s: String) = { + classPath + .find(_.toString.endsWith(s)) + .getOrElse(throw new Exception("Cannot find " + s)) + .toIO + } - def compileScala(scalaVersion: String, + def compileScala(zincWorker: ZincWorker, + scalaVersion: String, sources: Seq[Path], compileClasspath: Seq[Path], compilerClasspath: Seq[Path], @@ -44,18 +57,11 @@ object Lib{ (implicit ctx: Ctx): CompilationResult = { val compileClasspathFiles = compileClasspath.map(_.toIO).toArray - def grepJar(classPath: Seq[Path], s: String) = { - classPath - .find(_.toString.endsWith(s)) - .getOrElse(throw new Exception("Cannot find " + s)) - .toIO - } - val compilerJars = compilerClasspath.toArray.map(_.toIO) val classloaderSig = compilerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum - val scalaInstance = scalaInstanceCache match{ + val scalaInstance = zincWorker.scalaInstanceCache match{ case Some((k, v)) if k == classloaderSig => v case _ => val scalaInstance = new ScalaInstance( @@ -66,7 +72,7 @@ object Lib{ allJars = compilerJars, explicitActual = None ) - scalaInstanceCache = Some((classloaderSig, scalaInstance)) + zincWorker.scalaInstanceCache = Some((classloaderSig, scalaInstance)) scalaInstance } |