diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-12 16:04:40 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-12 16:04:40 -0800 |
commit | 9470a824de5be5dd633e7b6598a2a2f56f2cad63 (patch) | |
tree | d88277db69995ee48b0ace9bccc2608716590b57 /core/src/main | |
parent | 51aa1f11de43808c4604d15b23523867d13d9e44 (diff) | |
download | mill-9470a824de5be5dd633e7b6598a2a2f56f2cad63.tar.gz mill-9470a824de5be5dd633e7b6598a2a2f56f2cad63.tar.bz2 mill-9470a824de5be5dd633e7b6598a2a2f56f2cad63.zip |
Tests are passing under the new group evaluation model
Diffstat (limited to 'core/src/main')
-rw-r--r-- | core/src/main/scala/mill/eval/Evaluator.scala | 127 | ||||
-rw-r--r-- | core/src/main/scala/mill/util/MultiBiMap.scala | 2 |
2 files changed, 46 insertions, 83 deletions
diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index da6e2656..8163a304 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -10,44 +10,43 @@ import scala.collection.mutable class Evaluator(workspacePath: Path, labeling: Map[Task[_], Labelled[_]]){ - def evaluate(targets: OSet[Task[_]]): Evaluator.Results = { + def evaluate(goals: OSet[Task[_]]): Evaluator.Results = { mkdir(workspacePath) - val transitive = Evaluator.transitiveTargets(targets) + val transitive = Evaluator.transitiveTargets(goals) val topoSorted = Evaluator.topoSorted(transitive) - val sortedGroups = Evaluator.groupAroundNamedTargets(topoSorted, labeling) + val sortedGroups = Evaluator.groupAroundImportantTargets( + topoSorted, + t => labeling.contains(t) || goals.contains(t) + ) val evaluated = new OSet.Mutable[Task[_]] val results = mutable.LinkedHashMap.empty[Task[_], Any] - for (groupIndex <- sortedGroups.keys()){ - val group = sortedGroups.lookupKey(groupIndex) - - val (newResults, newEvaluated) = evaluateGroupCached( - group, - results, - sortedGroups - ) - evaluated.appendAll(newEvaluated) + for ((terminal, group)<- sortedGroups.items()){ + val (newResults, newEvaluated) = evaluateGroupCached(terminal, group, results) + for(ev <- newEvaluated){ + evaluated.append(ev) + } for((k, v) <- newResults) results.put(k, v) } - Evaluator.Results(targets.items.map(results), evaluated, transitive) + Evaluator.Results(goals.items.map(results), evaluated, transitive) } - def evaluateGroupCached(group: OSet[Task[_]], - results: collection.Map[Task[_], Any], - sortedGroups: MultiBiMap[Int, Task[_]]): (collection.Map[Task[_], Any], Seq[Task[_]]) = { + def evaluateGroupCached(terminal: Task[_], + group: OSet[Task[_]], + results: collection.Map[Task[_], Any]): (collection.Map[Task[_], Any], Seq[Task[_]]) = { - val (externalInputs, terminals) = partitionGroupInputOutput(group, results) + val externalInputs = group.items.flatMap(_.inputs).filter(!group.contains(_)) val inputsHash = externalInputs.toIterator.map(results).toVector.hashCode + group.toIterator.map(_.sideHash).toVector.hashCode() - val (targetDestPath, metadataPath) = labeling.get(terminals.items(0)) match{ + val (targetDestPath, metadataPath) = labeling.get(terminal) match{ case Some(labeling) => val targetDestPath = workspacePath / labeling.segments val metadataPath = targetDestPath / up / (targetDestPath.last + ".mill.json") @@ -58,16 +57,14 @@ class Evaluator(workspacePath: Path, val cached = for{ metadataPath <- metadataPath json <- scala.util.Try(Json.parse(read.getInputStream(metadataPath))).toOption - (cachedHash, terminalResults) <- Json.fromJson[(Int, Seq[JsValue])](json).asOpt + (cachedHash, terminalResult) <- Json.fromJson[(Int, JsValue)](json).asOpt if cachedHash == inputsHash - } yield terminalResults + } yield terminalResult cached match{ - case Some(terminalResults) => + case Some(terminalResult) => val newResults = mutable.LinkedHashMap.empty[Task[_], Any] - for((terminal, res) <- terminals.items.zip(terminalResults)){ - newResults(terminal) = labeling(terminal).format.reads(res).get - } + newResults(terminal) = labeling(terminal).format.reads(terminalResult).get (newResults, Nil) case _ => @@ -76,13 +73,13 @@ class Evaluator(workspacePath: Path, if (labeled.nonEmpty){ println(fansi.Color.Blue("Running " + labeled.map(_.segments.mkString(".")).mkString(", "))) } - val (newResults, newEvaluated, terminalResults) = evaluateGroup(group, results, targetDestPath) + val (newResults, newEvaluated, terminalResult) = evaluateGroup(group, results, targetDestPath) metadataPath.foreach( write.over( _, Json.prettyPrint( - Json.toJson(inputsHash -> terminals.toList.map(terminalResults)) + Json.toJson(inputsHash -> terminalResult) ), ) ) @@ -91,24 +88,17 @@ class Evaluator(workspacePath: Path, } } - def partitionGroupInputOutput(group: OSet[Task[_]], - results: collection.Map[Task[_], Any]) = { - val allInputs = group.items.flatMap(_.inputs) - val (internalInputs, externalInputs) = allInputs.partition(group.contains) - val internalInputSet = internalInputs.toSet - val terminals = group.filter(x => !internalInputSet(x) || labeling.contains(x)) - (OSet.from(externalInputs.distinct), terminals) - } def evaluateGroup(group: OSet[Task[_]], results: collection.Map[Task[_], Any], targetDestPath: Option[Path]) = { targetDestPath.foreach(rm) - val terminalResults = mutable.LinkedHashMap.empty[Task[_], JsValue] + var terminalResult: JsValue = null val newEvaluated = mutable.Buffer.empty[Task[_]] val newResults = mutable.LinkedHashMap.empty[Task[_], Any] - for (target <- group.items) { + for (target <- group.items if !results.contains(target)) { + newEvaluated.append(target) val targetInputValues = target.inputs.toVector.map(x => newResults.getOrElse(x, results(x)) @@ -117,7 +107,7 @@ class Evaluator(workspacePath: Path, val args = new Args(targetInputValues, targetDestPath.orNull) val res = target.evaluate(args) for(targetLabel <- labeling.get(target)){ - terminalResults(target) = targetLabel + terminalResult = targetLabel .format .asInstanceOf[Format[Any]] .writes(res.asInstanceOf[Any]) @@ -125,7 +115,7 @@ class Evaluator(workspacePath: Path, newResults(target) = res } - (newResults, newEvaluated, terminalResults) + (newResults, newEvaluated, terminalResult) } } @@ -134,52 +124,23 @@ class Evaluator(workspacePath: Path, object Evaluator{ class TopoSorted private[Evaluator](val values: OSet[Task[_]]) case class Results(values: Seq[Any], evaluated: OSet[Task[_]], transitive: OSet[Task[_]]) - def groupAroundNamedTargets(topoSortedTargets: TopoSorted, - labeling: Map[Task[_], Labelled[_]]): MultiBiMap[Int, Task[_]] = { - - val grouping = new MultiBiMap.Mutable[Int, Task[_]]() - - var groupCount = 0 - - for(target <- topoSortedTargets.values.items.reverseIterator){ - if (!grouping.containsValue(target)){ - grouping.add(groupCount, target) - groupCount += 1 - } - - val targetGroup = grouping.lookupValue(target) - for(upstream <- target.inputs){ - grouping.lookupValueOpt(upstream) match{ - case None if !labeling.contains(upstream) => - grouping.add(targetGroup, upstream) - case Some(upstreamGroup) - if !labeling.contains(upstream) && upstreamGroup != targetGroup => - val upstreamTargets = grouping.removeAll(upstreamGroup) - grouping.addAll(targetGroup, upstreamTargets) - case _ => //donothing + def groupAroundImportantTargets(topoSortedTargets: TopoSorted, + important: Task[_] => Boolean): MultiBiMap[Task[_], Task[_]] = { + + val output = new MultiBiMap.Mutable[Task[_], Task[_]]() + for (target <- topoSortedTargets.values if important(target)) { + + val transitiveTargets = new OSet.Mutable[Task[_]] + def rec(t: Task[_]): Unit = { + if (transitiveTargets.contains(t)) () // do nothing + else if (important(t) && t != target) () // do nothing + else { + transitiveTargets.append(t) + t.inputs.foreach(rec) } } - } - - - // Sort groups amongst themselves, and sort the contents of each group - // before aggregating it into the final output - val groupGraph = mutable.Buffer.fill[Seq[Int]](groupCount)(Nil) - for((groupId, groupTasks) <- grouping.items()){ - groupGraph(groupId) = - groupTasks.toIterator.flatMap(_.inputs).map(grouping.lookupValue).toArray.distinct.toSeq - } - // Given input topoSortedTargets has no cycles, group graph should not have cycles - val groupOrdering = Tarjans.apply(groupGraph) - - - val targetOrdering = topoSortedTargets.values.items.zipWithIndex.toMap - val output = new MultiBiMap.Mutable[Int, Task[_]] - for((groupIndices, i) <- groupOrdering.zipWithIndex){ - val sortedGroup = OSet.from( - groupIndices.flatMap(grouping.lookupKeyOpt).flatten.sortBy(targetOrdering) - ) - output.addAll(i, sortedGroup) + rec(target) + output.addAll(target, topoSorted(transitiveTargets).values) } output } @@ -207,7 +168,7 @@ object Evaluator{ val numberedEdges = for(t <- transitiveTargets.items) - yield t.inputs.map(targetIndices) + yield t.inputs.collect(targetIndices) val sortedClusters = Tarjans(numberedEdges) val nonTrivialClusters = sortedClusters.filter(_.length > 1) diff --git a/core/src/main/scala/mill/util/MultiBiMap.scala b/core/src/main/scala/mill/util/MultiBiMap.scala index 2052ef90..ef5359bc 100644 --- a/core/src/main/scala/mill/util/MultiBiMap.scala +++ b/core/src/main/scala/mill/util/MultiBiMap.scala @@ -16,9 +16,11 @@ trait MultiBiMap[K, V]{ def removeAll(k: K): OSet[V] def addAll(k: K, vs: TraversableOnce[V]): Unit def keys(): Iterator[K] + def items(): Iterator[(K, OSet[V])] def values(): Iterator[OSet[V]] def keyCount: Int } + object MultiBiMap{ class Mutable[K, V]() extends MultiBiMap[K, V]{ private[this] val valueToKey = mutable.LinkedHashMap.empty[V, K] |