From e0e537b937fc411188af2ae7ab417b6f4a9dabbe Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sun, 4 Mar 2018 17:34:13 -0800 Subject: Introduced the `mill plan foo.bar` command, which shows you what the execution plan of running the `foo.bar` task looks like without actually evaluating it. --- core/src/mill/eval/Evaluator.scala | 82 +++++++++++++++++++------------------ main/src/mill/main/MainModule.scala | 16 ++++++++ readme.md | 5 +++ 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/core/src/mill/eval/Evaluator.scala b/core/src/mill/eval/Evaluator.scala index 4bc11338..7ae68751 100644 --- a/core/src/mill/eval/Evaluator.scala +++ b/core/src/mill/eval/Evaluator.scala @@ -36,45 +36,7 @@ case class Evaluator[T](outPath: Path, def evaluate(goals: Agg[Task[_]]): Evaluator.Results = { mkdir(outPath) - val transitive = Graph.transitiveTargets(goals) - val topoSorted = Graph.topoSorted(transitive) - val sortedGroups = Graph.groupAroundImportantTargets(topoSorted){ - case t: NamedTask[Any] => - val segments = t.ctx.segments - val finalTaskOverrides = t match{ - case t: Target[_] => - rootModule.millInternal.segmentsToTargets.get(segments).fold(0)(_.ctx.overrides) - - case c: mill.define.Command[_] => - def findMatching(cls: Class[_]): Option[Seq[(Int, EntryPoint[_])]] = { - rootModule.millDiscover.value.get(cls) match{ - case Some(v) => Some(v) - case None => - cls.getSuperclass match{ - case null => None - case superCls => findMatching(superCls) - } - } - } - - findMatching(c.cls) match{ - case Some(v) => - v.find(_._2.name == c.ctx.segment.pathSegments.head).get._1 - // For now we don't properly support overrides for external modules - // that do not appear in the Evaluator's main Discovered listing - case None => 0 - } - - case c: mill.define.Worker[_] => 0 - } - - val additional = - if (finalTaskOverrides == t.ctx.overrides) Nil - else Seq(Segment.Label("overriden")) ++ t.ctx.enclosing.split("\\.|#| ").map(Segment.Label) - - Right(Labelled(t, segments ++ additional)) - case t if goals.contains(t) => Left(t) - } + val (sortedGroups, transitive) = Evaluator.plan(rootModule, goals) val evaluated = new Agg.Mutable[Task[_]] val results = mutable.LinkedHashMap.empty[Task[_], Result[(Any, Int)]] @@ -379,4 +341,46 @@ object Evaluator{ results: collection.Map[Task[_], Result[Any]]){ def values = rawValues.collect{case Result.Success(v) => v} } + def plan(rootModule: BaseModule, goals: Agg[Task[_]]) = { + val transitive = Graph.transitiveTargets(goals) + val topoSorted = Graph.topoSorted(transitive) + val sortedGroups = Graph.groupAroundImportantTargets(topoSorted){ + case t: NamedTask[Any] => + val segments = t.ctx.segments + val finalTaskOverrides = t match{ + case t: Target[_] => + rootModule.millInternal.segmentsToTargets.get(segments).fold(0)(_.ctx.overrides) + + case c: mill.define.Command[_] => + def findMatching(cls: Class[_]): Option[Seq[(Int, EntryPoint[_])]] = { + rootModule.millDiscover.value.get(cls) match{ + case Some(v) => Some(v) + case None => + cls.getSuperclass match{ + case null => None + case superCls => findMatching(superCls) + } + } + } + + findMatching(c.cls) match{ + case Some(v) => + v.find(_._2.name == c.ctx.segment.pathSegments.head).get._1 + // For now we don't properly support overrides for external modules + // that do not appear in the Evaluator's main Discovered listing + case None => 0 + } + + case c: mill.define.Worker[_] => 0 + } + + val additional = + if (finalTaskOverrides == t.ctx.overrides) Nil + else Seq(Segment.Label("overriden")) ++ t.ctx.enclosing.split("\\.|#| ").map(Segment.Label) + + Right(Labelled(t, segments ++ additional)) + case t if goals.contains(t) => Left(t) + } + (sortedGroups, transitive) + } } diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index feafd35d..33eddbe4 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -46,6 +46,22 @@ trait MainModule extends mill.Module{ } } + def plan(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ + val resolved = RunScript.resolveTasks( + mill.main.ResolveTasks, evaluator, targets, multiSelect = true + ) + + resolved match{ + case Left(err) => Result.Failure(err) + case Right(rs) => + val (sortedGroups, transitive) = Evaluator.plan(evaluator.rootModule, rs) + for(Right(r) <- sortedGroups.keys()){ + println(r.segments.render) + } + Result.Success(()) + } + } + def describe(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ MainModule.resolveTasks(evaluator, targets, multiSelect = true){ tasks => for{ diff --git a/readme.md b/readme.md index c67170dc..c535b00c 100644 --- a/readme.md +++ b/readme.md @@ -330,6 +330,11 @@ rm -rf out/ ## Changelog +### master + +- Introduced the `mill plan foo.bar` command, which shows you what the execution + plan of running the `foo.bar` task looks like without actually evaluating it. + ### 0.1.4 - Speed up Mill client initialization by another 50-100ms -- cgit v1.2.3