diff options
-rw-r--r-- | main/src/mill/main/MainModule.scala | 76 |
1 files changed, 71 insertions, 5 deletions
diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 33eddbe4..9fa6e4dd 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -1,6 +1,6 @@ package mill.main -import mill.define.NamedTask +import mill.define.{NamedTask, Task} import mill.eval.{Evaluator, Result} import mill.util.{EitherOps, ParseArgs, PrintLogger, Watched} import pprint.{Renderer, Truncated} @@ -31,6 +31,9 @@ trait MainModule extends mill.Module{ implicit def millScoptTasksReads[T] = new mill.main.Tasks.Scopt[T]() implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]() + /** + * Resolves a mill query string and prints out the tasks it resolves to. + */ def resolve(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ val resolved = RunScript.resolveTasks( mill.main.ResolveMetadata, evaluator, targets, multiSelect = true @@ -46,6 +49,10 @@ trait MainModule extends mill.Module{ } } + /** + * Given a set of tasks, prints out the execution plan of what tasks will be + * executed in what order, without actually executing them. + */ def plan(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ val resolved = RunScript.resolveTasks( mill.main.ResolveTasks, evaluator, targets, multiSelect = true @@ -55,14 +62,64 @@ trait MainModule extends mill.Module{ 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) + val labels = sortedGroups + .keys() + .collect{ case Right(r) => r.segments.render} + .toArray + + labels.foreach(println) + Result.Success(labels) + } + } + + /** + * Prints out some dependency path from the `src` task to the `dest` task. + * + * If there are multiple dependency paths between `src` and `dest`, the path + * chosen is arbitrary. + */ + def path(evaluator: Evaluator[Any], src: String, dest: String) = mill.T.command{ + val resolved = RunScript.resolveTasks( + mill.main.ResolveTasks, evaluator, List(src, dest), multiSelect = true + ) + + resolved match{ + case Left(err) => Result.Failure(err) + case Right(Seq(src1, dest1)) => + val queue = collection.mutable.Queue[List[Task[_]]](List(src1)) + var found = Option.empty[List[Task[_]]] + val seen = collection.mutable.Set.empty[Task[_]] + while(queue.nonEmpty && found.isEmpty){ + val current = queue.dequeue() + if (current.head == dest1) found = Some(current) + else{ + for{ + next <- current.head.inputs + if !seen.contains(next) + }{ + seen.add(next) + queue.enqueue(next :: current) + } + } + } + found match{ + case None => + Result.Failure(s"No path found between $src and $dest") + case Some(list) => + val labels = list + .collect{case n: NamedTask[_] => n.ctx.segments.render} + + labels.foreach(mill.T.ctx().log.outputStream.println(_)) + + Result.Success(labels) } - Result.Success(()) } } - def describe(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ + /** + * Displays metadata about the given task without actually running it. + */ + def inspect(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ MainModule.resolveTasks(evaluator, targets, multiSelect = true){ tasks => for{ task <- tasks @@ -83,12 +140,21 @@ trait MainModule extends mill.Module{ } } + /** + * Runs multiple tasks in a single call. + * + * + */ def all(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ MainModule.evaluateTasks(evaluator, targets, multiSelect = true) {res => res.flatMap(_._2) } } + /** + * Runs a given task and prints the JSON result to stdout. This is useful + * to integrate Mill into external scripts and tooling. + */ def show(evaluator: Evaluator[Any], targets: String*) = mill.T.command{ MainModule.evaluateTasks( evaluator.copy( |