From 3ce3d6214b1c52c692926ab373412b71fe097c21 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Fri, 29 Dec 2017 22:47:15 -0800 Subject: Assign different overrides of a Target different cache directories and paths, to fix https://github.com/lihaoyi/mill/issues/86 --- core/src/main/scala/mill/define/Task.scala | 60 ++++++++++++++-------- core/src/main/scala/mill/discover/Discovered.scala | 9 +++- core/src/main/scala/mill/eval/Evaluator.scala | 31 ++++++----- .../test/scala/mill/discover/DiscoveredTests.scala | 5 +- .../src/test/scala/mill/eval/EvaluationTests.scala | 7 +++ core/src/test/scala/mill/util/TestGraphs.scala | 8 +++ core/src/test/scala/mill/util/TestUtil.scala | 5 +- 7 files changed, 88 insertions(+), 37 deletions(-) (limited to 'core') diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index bb877d08..4ccb93b6 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -1,9 +1,11 @@ package mill.define +import ammonite.main.Router.Overrides import mill.define.Applicative.Applyable import mill.eval.{PathRef, Result} import mill.util.Ctx -import upickle.default.{Reader => R, Writer => W, ReadWriter => RW} +import upickle.default.{ReadWriter => RW, Reader => R, Writer => W} + import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context @@ -35,6 +37,7 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[Task, T]{ trait NamedTask[+T] extends Task[T]{ def owner: Task.Module def name: String + def overrides: Int } trait Target[+T] extends NamedTask[T]{ override def asTarget = Some(this) @@ -49,7 +52,8 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: W[T], e: sourcecode.Enclosing, n: sourcecode.Name, - cl: Caller[mill.define.Task.Module]): Target[T] = macro targetImpl[T] + cl: Caller[mill.define.Task.Module], + o: Overrides): Target[T] = macro targetImpl[T] def targetImpl[T: c.WeakTypeTag](c: Context) (t: c.Expr[T]) @@ -57,11 +61,12 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: c.Expr[W[T]], e: c.Expr[sourcecode.Enclosing], n: c.Expr[sourcecode.Name], - cl: c.Expr[Caller[mill.define.Task.Module]]): c.Expr[Target[T]] = { + cl: c.Expr[Caller[mill.define.Task.Module]], + o: c.Expr[Overrides]): c.Expr[Target[T]] = { import c.universe._ c.Expr[Target[T]]( mill.plugin.Cacher.wrapCached(c)( - q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Ctx](c)(q"mill.eval.Result.Success($t)").tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read))" + q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Ctx](c)(q"mill.eval.Result.Success($t)").tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read), $o.value)" ) ) } @@ -71,7 +76,8 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: W[T], e: sourcecode.Enclosing, n: sourcecode.Name, - cl: Caller[mill.define.Task.Module]): Target[T] = macro targetResultImpl[T] + cl: Caller[mill.define.Task.Module], + o: Overrides): Target[T] = macro targetResultImpl[T] def targetResultImpl[T: c.WeakTypeTag](c: Context) (t: c.Expr[Result[T]]) @@ -79,11 +85,12 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: c.Expr[W[T]], e: c.Expr[sourcecode.Enclosing], n: c.Expr[sourcecode.Name], - cl: c.Expr[Caller[mill.define.Task.Module]]): c.Expr[Target[T]] = { + cl: c.Expr[Caller[mill.define.Task.Module]], + o: c.Expr[Overrides]): c.Expr[Target[T]] = { import c.universe._ c.Expr[Target[T]]( mill.plugin.Cacher.wrapCached(c)( - q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Ctx](c)(t.tree).tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read))" + q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Ctx](c)(t.tree).tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read), $o.value)" ) ) } @@ -93,7 +100,8 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: W[T], e: sourcecode.Enclosing, n: sourcecode.Name, - cl: Caller[mill.define.Task.Module]): Target[T] = macro targetTaskImpl[T] + cl: Caller[mill.define.Task.Module], + o: Overrides): Target[T] = macro targetTaskImpl[T] def targetTaskImpl[T: c.WeakTypeTag](c: Context) (t: c.Expr[Task[T]]) @@ -101,11 +109,12 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: c.Expr[W[T]], e: c.Expr[sourcecode.Enclosing], n: c.Expr[sourcecode.Name], - cl: c.Expr[Caller[mill.define.Task.Module]]): c.Expr[Target[T]] = { + cl: c.Expr[Caller[mill.define.Task.Module]], + o: c.Expr[Overrides]): c.Expr[Target[T]] = { import c.universe._ c.Expr[Target[T]]( mill.plugin.Cacher.wrapCached(c)( - q"new ${weakTypeOf[TargetImpl[T]]}($t, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read))" + q"new ${weakTypeOf[TargetImpl[T]]}($t, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read), $o.value)" ) ) } @@ -113,24 +122,27 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul def command[T](t: Result[T]) (implicit w: W[T], n: sourcecode.Name, - cl: Caller[mill.define.Task.Module]): Command[T] = macro commandImpl[T] + cl: Caller[mill.define.Task.Module], + o: Overrides): Command[T] = macro commandImpl[T] def source(path: ammonite.ops.Path) = new Source(path) def command[T](t: Task[T]) (implicit c: Caller[Task.Module], n: sourcecode.Name, - w: W[T]): Command[T] = new Command(t, c.value, n.value, w) + w: W[T], + o: Overrides): Command[T] = new Command(t, c.value, n.value, w, o.value) def commandImpl[T: c.WeakTypeTag](c: Context) (t: c.Expr[T]) (w: c.Expr[W[T]], n: c.Expr[sourcecode.Name], - cl: c.Expr[Caller[mill.define.Task.Module]]): c.Expr[Command[T]] = { + cl: c.Expr[Caller[mill.define.Task.Module]], + o: c.Expr[Overrides]): c.Expr[Command[T]] = { import c.universe._ c.Expr[Command[T]]( - q"new ${weakTypeOf[Command[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree}, $cl.value, $n.value, $w)" + q"new ${weakTypeOf[Command[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree}, $cl.value, $n.value, $w, $o.value)" ) } @@ -140,7 +152,8 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: W[T], e: sourcecode.Enclosing, n: sourcecode.Name, - cl: Caller[mill.define.Task.Module]): Target[T] = macro persistentImpl[T] + cl: Caller[mill.define.Task.Module], + o: Overrides): Target[T] = macro persistentImpl[T] def persistentImpl[T: c.WeakTypeTag](c: Context) (t: c.Expr[T]) @@ -148,12 +161,13 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul w: c.Expr[W[T]], e: c.Expr[sourcecode.Enclosing], n: c.Expr[sourcecode.Name], - cl: c.Expr[Caller[mill.define.Task.Module]]): c.Expr[Persistent[T]] = { + cl: c.Expr[Caller[mill.define.Task.Module]], + o: c.Expr[Overrides]): c.Expr[Persistent[T]] = { import c.universe._ c.Expr[Persistent[T]]( mill.plugin.Cacher.wrapCached(c)( - q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read))" + q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree}, $e.value, $cl.value, $n.value, upickle.default.ReadWriter($w.write, $r.read), $o.value)" ) ) } @@ -170,6 +184,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul def zip[A](a: Task[A]) = a.map(Tuple1(_)) def zip[A, B](a: Task[A], b: Task[B]) = a.zip(b) } + case class Caller[A](value: A) object Caller { def apply[T]()(implicit c: Caller[T]) = c.value @@ -184,7 +199,8 @@ class TargetImpl[+T](t: Task[T], val enclosing: String, val owner: Task.Module, val name: String, - val readWrite: RW[_]) extends Target[T] { + val readWrite: RW[_], + val overrides: Int) extends Target[T] { val inputs = Seq(t) def evaluate(args: Ctx) = args[T](0) override def toString = enclosing + "@" + Integer.toHexString(System.identityHashCode(this)) @@ -192,7 +208,8 @@ class TargetImpl[+T](t: Task[T], class Command[+T](t: Task[T], val owner: Task.Module, val name: String, - val writer: W[_]) extends NamedTask[T] { + val writer: W[_], + val overrides: Int) extends NamedTask[T] { val inputs = Seq(t) def evaluate(args: Ctx) = args[T](0) override def asCommand = Some(this) @@ -201,8 +218,9 @@ class Persistent[+T](t: Task[T], enclosing: String, owner: Task.Module, name: String, - readWrite: RW[_]) - extends TargetImpl[T](t, enclosing, owner, name, readWrite) { + readWrite: RW[_], + overrides: Int) + extends TargetImpl[T](t, enclosing, owner, name, readWrite, overrides) { override def flushDest = false override def asPersistent = Some(this) } diff --git a/core/src/main/scala/mill/discover/Discovered.scala b/core/src/main/scala/mill/discover/Discovered.scala index 6e819d75..cef0d193 100644 --- a/core/src/main/scala/mill/discover/Discovered.scala +++ b/core/src/main/scala/mill/discover/Discovered.scala @@ -3,6 +3,7 @@ package mill.discover import mill.define.Task.Module import mill.define.{Cross, Target, Task} import ammonite.main.Router +import ammonite.main.Router.EntryPoint import mill.discover.Mirror.{Segment, TargetPoint} import mill.util.Ctx.Loader @@ -30,18 +31,24 @@ object Discovered { ) Seq(resolvedNode -> segmentsRev.reverse) }.toMap + val targets = Mirror.traverse(base, mirror){ (mirror, segmentsRev) => val resolvedNode = mirror.node( base, segmentsRev.reverse.map{case Mirror.Segment.Cross(vs) => vs.toList case _ => Nil}.toList ) for(target <- mirror.targets) yield { - target.asInstanceOf[TargetPoint[Any, Any]].run(resolvedNode) -> (segmentsRev.reverse :+ Segment.Label(target.label)) } }.toMap + val segmentsToCommands = Mirror.traverse[T, T, (Seq[Segment], EntryPoint[_])](base, mirror){ (mirror, segmentsRev) => + for(command <- mirror.commands) + yield (segmentsRev.reverse :+ Segment.Label(command.name)) -> command + }.toMap + + val segmentsToTargets = targets.map(_.swap) } def consistencyCheck[T](mapping: Discovered.Mapping[T]) = { diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index 110747a1..ed8145b2 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -11,9 +11,13 @@ import mill.util import mill.util._ import scala.collection.mutable -case class Labelled[T](target: Task[T], - format: Option[upickle.default.ReadWriter[T]], - segments: Seq[Segment]) +case class Labelled[T](target: NamedTask[T], + segments: Seq[Segment]){ + def format = target match{ + case t: Target[Any] => Some(t.readWrite.asInstanceOf[upickle.default.ReadWriter[Any]]) + case _ => None + } +} class Evaluator[T](val workspacePath: Path, val mapping: Discovered.Mapping[T], log: Logger, @@ -29,15 +33,18 @@ class Evaluator[T](val workspacePath: Path, val transitive = Graph.transitiveTargets(goals) val topoSorted = Graph.topoSorted(transitive) val sortedGroups = Graph.groupAroundImportantTargets(topoSorted){ - case t: NamedTask[Any] if mapping.modules.contains(t.owner) => - Right(Labelled( - t, - t match{ - case t: Target[Any] => Some(t.readWrite.asInstanceOf[upickle.default.ReadWriter[Any]]) - case _ => None - }, - mapping.modules(t.owner) :+ Segment.Label(t.name) - )) + case t: NamedTask[Any] if mapping.modules.contains(t.owner) => + val segments = mapping.modules(t.owner) :+ Segment.Label(t.name) + val finalTaskOverrides = t match{ + case t: Target[_] => mapping.segmentsToTargets(segments).overrides + case c: mill.define.Command[_] => mapping.segmentsToCommands(segments).overrides + } + val delta = finalTaskOverrides - t.overrides + val additional = + if (delta == 0) Seq(segments.last) + else Seq(Segment.Label(segments.last.asInstanceOf[Segment.Label].value + "-override-" + delta)) + + Right(Labelled(t, segments.init ++ additional)) case t if goals.contains(t) => Left(t) } diff --git a/core/src/test/scala/mill/discover/DiscoveredTests.scala b/core/src/test/scala/mill/discover/DiscoveredTests.scala index b2d14080..8501f4cc 100644 --- a/core/src/test/scala/mill/discover/DiscoveredTests.scala +++ b/core/src/test/scala/mill/discover/DiscoveredTests.scala @@ -68,11 +68,12 @@ object DiscoveredTests extends TestSuite{ val outerCommands = discovered.mirror.commands assertMatch(outerCommands){case Seq( - EntryPoint("hello", Nil, None, false, _), + EntryPoint("hello", Nil, None, false, _, _), EntryPoint("echoPair", List(ArgSig("prefix", "String", None, None), ArgSig("suffix", "String", None, None)), None, false, + _, _ ) ) =>} @@ -82,7 +83,7 @@ object DiscoveredTests extends TestSuite{ .flatMap(_._2.commands.asInstanceOf[Seq[EntryPoint[_]]]) assertMatch(innerCommands){case Seq( - EntryPoint("inner", _, None, false, _), + EntryPoint("inner", _, None, false, _, _), ) =>} } diff --git a/core/src/test/scala/mill/eval/EvaluationTests.scala b/core/src/test/scala/mill/eval/EvaluationTests.scala index 2b40724a..75a6cc52 100644 --- a/core/src/test/scala/mill/eval/EvaluationTests.scala +++ b/core/src/test/scala/mill/eval/EvaluationTests.scala @@ -196,6 +196,13 @@ object EvaluationTests extends TestSuite{ checker(task2, 4, OSet(), extraEvaled = -1, secondRunNoOp = false) } + 'overrideSuperTask - { + import canOverrideSuper._ + + val checker = new Checker(mapping(canOverrideSuper)) + checker(foo, Seq("base", "object"), OSet(foo), extraEvaled = -1) + } + 'tasksAreUncached - { // Make sure the tasks `left` and `middle` re-compute every time, while // the target `right` does not diff --git a/core/src/test/scala/mill/util/TestGraphs.scala b/core/src/test/scala/mill/util/TestGraphs.scala index 46ca9ff9..0f2c769f 100644 --- a/core/src/test/scala/mill/util/TestGraphs.scala +++ b/core/src/test/scala/mill/util/TestGraphs.scala @@ -167,6 +167,14 @@ object TestGraphs{ } + trait BaseModule extends Module { + def foo = T{ Seq("base") } + } + + object canOverrideSuper extends BaseModule { + override def foo = T{ super.foo() ++ Seq("object") } + } + trait TraitWithModule extends Module{ outer => object TraitModule extends Module{ def testFramework = T{ "mill.UTestFramework" } diff --git a/core/src/test/scala/mill/util/TestUtil.scala b/core/src/test/scala/mill/util/TestUtil.scala index 8adbc87a..0457431b 100644 --- a/core/src/test/scala/mill/util/TestUtil.scala +++ b/core/src/test/scala/mill/util/TestUtil.scala @@ -1,5 +1,6 @@ package mill.util +import ammonite.main.Router.Overrides import mill.define.{Caller, Target, Task} import mill.eval.Result import utest.assert @@ -38,8 +39,10 @@ object TestUtil { val pure: Boolean) (implicit enclosing0: sourcecode.Enclosing, owner0: Caller[mill.Module], - name0: sourcecode.Name) + name0: sourcecode.Name, + o: Overrides) extends Test(inputs) with Target[Int]{ + val overrides = o.value val enclosing = enclosing0.value val owner = owner0.value val name = name0.value -- cgit v1.2.3