From 933a3df121e49cff240b5e29d9dab763562c44ef Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 18 Nov 2017 05:37:11 -0800 Subject: Implement `T.persistent{}` targets, which have their dest directory persist between runs so the task implementation can use it as a cache --- core/src/main/scala/mill/Main.scala | 2 ++ core/src/main/scala/mill/define/Cacher.scala | 11 +++++---- core/src/main/scala/mill/define/Task.scala | 34 +++++++++++++++++++++++---- core/src/main/scala/mill/eval/Evaluator.scala | 3 ++- 4 files changed, 40 insertions(+), 10 deletions(-) (limited to 'core/src/main') diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index f4042ae8..c4df0ee5 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -12,6 +12,7 @@ import ammonite.main.Scripts.pathScoptRead import ammonite.repl.Repl object Main { + def apply[T: Discovered](args: Seq[String], obj: T, watch: Path => Unit) = { val Seq(selectorString, rest @_*) = args @@ -131,6 +132,7 @@ class Main(config: Main.Config){ case Res.Failure(msg) => printError(msg) false + case Res.Exception(ex, s) => printError( Repl.showException(ex, fansi.Color.Red, fansi.Attr.Reset, fansi.Color.Green) diff --git a/core/src/main/scala/mill/define/Cacher.scala b/core/src/main/scala/mill/define/Cacher.scala index 224704ce..09200203 100644 --- a/core/src/main/scala/mill/define/Cacher.scala +++ b/core/src/main/scala/mill/define/Cacher.scala @@ -4,12 +4,12 @@ import scala.collection.mutable import scala.reflect.macros.blackbox.Context -trait Cacher[C[_], V[_]]{ - private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, V[_]] - def wrapCached[T](in: C[T], enclosing: String): V[T] +trait Cacher[C[_]]{ + private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, C[_]] + def wrapCached[T](in: C[T], enclosing: String): C[T] protected[this] def cachedTarget[T](t: => C[T]) - (implicit c: sourcecode.Enclosing): V[T] = synchronized{ - cacherLazyMap.getOrElseUpdate(c, wrapCached(t, c.value)).asInstanceOf[V[T]] + (implicit c: sourcecode.Enclosing): C[T] = synchronized{ + cacherLazyMap.getOrElseUpdate(c, wrapCached(t, c.value)).asInstanceOf[C[T]] } } object Cacher{ @@ -17,6 +17,7 @@ object Cacher{ c.Expr[M[T]](wrapCached(c)(t.tree)) } def wrapCached(c: Context)(t: c.Tree) = { + import c.universe._ val owner = c.internal.enclosingOwner val ownerIsCacherClass = diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index 0e2591c6..70f93d35 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -24,6 +24,8 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ * anyway? */ def sideHash: Int = 0 + + def flushDest: Boolean = true } trait Target[+T] extends Task[T] @@ -31,7 +33,7 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ implicit def apply[T](t: T): Target[T] = macro targetImpl[T] - def apply[T](t: Task[T]): Target[T] = macro Cacher.impl0[Task, T] + def apply[T](t: Task[T]): Target[T] = macro targetTaskImpl[T] def command[T](t: T): Command[T] = macro commandImpl[T] @@ -42,6 +44,16 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ def task[T](t: T): Task[T] = macro Applicative.impl[Task, T, Args] def task[T](t: Task[T]): Task[T] = t + def persistent[T](t: T): Target[T] = macro persistentImpl[T] + def persistentImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Persistent[T]] = { + import c.universe._ + + c.Expr[Persistent[T]]( + mill.define.Cacher.wrapCached(c)( + q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree})" + ) + ) + } def commandImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Command[T]] = { import c.universe._ @@ -50,10 +62,19 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ ) } + def targetTaskImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]]): c.Expr[Target[T]] = { + import c.universe._ + c.Expr[Target[T]]( + mill.define.Cacher.wrapCached(c)( + q"new ${weakTypeOf[TargetImpl[T]]}($t, _root_.sourcecode.Enclosing())" + ) + ) + } def targetImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = { + import c.universe._ c.Expr[Target[T]]( mill.define.Cacher.wrapCached(c)( - Applicative.impl[Task, T, Args](c)(t).tree + q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree}, _root_.sourcecode.Enclosing())" ) ) } @@ -93,6 +114,11 @@ class Command[+T](t: Task[T]) extends Task[T] { val inputs = Seq(t) def evaluate(args: Args) = args[T](0) } +class Persistent[+T](t: Task[T]) extends Target[T] { + val inputs = Seq(t) + def evaluate(args: Args) = args[T](0) + override def flushDest = false +} object Source{ implicit def apply(p: ammonite.ops.Path) = new Source(p) } @@ -107,8 +133,8 @@ object Task { - trait Module extends mill.define.Cacher[Task, Target]{ - def wrapCached[T](t: Task[T], enclosing: String): Target[T] = new TargetImpl(t, enclosing) + trait Module extends mill.define.Cacher[Target]{ + def wrapCached[T](t: Target[T], enclosing: String): Target[T] = t } class Task0[T](t: T) extends Task[T]{ lazy val t0 = t diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index 22861847..ef81515c 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -77,6 +77,7 @@ class Evaluator(workspacePath: Path, if (labeled.nonEmpty){ println(fansi.Color.Blue("Running " + labeled.map(_.segments.mkString(".")).mkString(", "))) } + if (terminal.flushDest) targetDestPath.foreach(rm) val (newResults, newEvaluated, terminalResult) = evaluateGroup(group, results, targetDestPath) metadataPath.foreach( @@ -95,7 +96,7 @@ class Evaluator(workspacePath: Path, results: collection.Map[Task[_], Any], targetDestPath: Option[Path]) = { - targetDestPath.foreach(rm) + var terminalResult: upickle.Js.Value = null val newEvaluated = mutable.Buffer.empty[Task[_]] val newResults = mutable.LinkedHashMap.empty[Task[_], Any] -- cgit v1.2.3