diff options
-rw-r--r-- | core/src/main/scala/mill/Main.scala | 190 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Cross.scala | 6 |
2 files changed, 119 insertions, 77 deletions
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index ef4a78a6..66034e81 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -22,93 +22,133 @@ object Main { } query.parse(input) } - def apply[T: Discovered](args: Seq[String], - obj: T, - watch: Path => Unit, - coloredOutput: Boolean): Int = { - val log = new Logger(coloredOutput) + def parseArgs(args: Seq[String]): Either[Throwable, List[scala.util.Either[String,Seq[String]]]] = { + import fastparse.all.Parsed val Seq(selectorString, rest @_*) = args - parseSelector(selectorString) match{ - case f: fastparse.all.Parsed.Failure => - log.error(f.msg) - 1 - case fastparse.all.Parsed.Success(selector, idx) => - val discovered = implicitly[Discovered[T]] - val consistencyErrors = Discovered.consistencyCheck(obj, discovered) - if (consistencyErrors.nonEmpty) { - log.error("Failed Discovered.consistencyCheck: " + consistencyErrors) - 1 - } else { - val mapping = Discovered.mapping(obj)(discovered) - val workspacePath = pwd / 'out - - val crossSelectors = selector.collect{case Right(x) => x.toList} - def resolve[V](selector: List[Either[String, Seq[String]]], - hierarchy: Mirror[T, V]): Option[Task[Any]] = { - selector match{ - case Right(_) :: Nil => ??? - case Left(last) :: Nil => - def target: Option[Task[Any]] = - hierarchy.targets.find(_.label == last).map(_.run(hierarchy.node(obj, crossSelectors))) - def command: Option[Task[Any]] = hierarchy.commands.find(_.name == last).flatMap( - _.invoke(hierarchy.node(obj, crossSelectors), ammonite.main.Scripts.groupArgs(rest.toList)) match{ - case Router.Result.Success(v) => Some(v) - case _ => None - } - ) - target orElse command - case head :: tail => - head match{ - case Left(singleLabel) => - hierarchy.children - .collectFirst{ case (label, child) if label == singleLabel => resolve(tail, child) } - .flatten - case Right(cross) => - resolve(tail, hierarchy.crossChildren.get._2) - } - - case Nil => ??? - } - } - resolve(selector, discovered.mirror) match{ - case Some(target) => - val evaluator = new Evaluator(workspacePath, mapping, log.info) - val evaluated = evaluator.evaluate(OSet(target)) - evaluated.transitive.foreach{ - case t: define.Source => watch(t.handle.path) - case _ => // do nothing - } - val failing = evaluated.failing.items - evaluated.failing.keyCount match{ - case 0 => // do nothing - case n => log.error(n + " targets failed") + parseSelector(selectorString) match { + case f: Parsed.Failure => + Left(new Exception("Parsing exception"+f.msg)) + case Parsed.Success(selector, _) => + Right(selector) + } + } + + def resolve[T, V]( + selector: List[Either[String, Seq[String]]], + hierarchy: Mirror[T, V])(implicit + obj: T, + rest: Seq[String], + crossSelectors: List[List[String]]): Either[Throwable, Task[Any]] = { + + selector match{ + case Right(_) :: Nil => + Left(new Exception("No target or command selected")) + case Left(last) :: Nil => + def target: Option[Task[Any]] = + hierarchy.targets.find(_.label == last).map(_.run(hierarchy.node(obj, crossSelectors))) + + def command: Either[Throwable, Task[Any]] = + hierarchy.commands.find(_.name == last).map{ x => + Option(hierarchy.node(obj, crossSelectors)).map(inst => + x.invoke(inst, ammonite.main.Scripts.groupArgs(rest.toList)) match { + case Router.Result.Success(v) => + Right(v) + case _ => + Left(new Exception(s"Method not found $last")) } + ).getOrElse( + Left(new Exception(s"Instance not found for calling $last")) + ) + }.getOrElse(Left(new Exception(s"Command not found last"))) + + target.map(Right(_)) getOrElse command + case head :: tail => + head match{ + case Left(singleLabel) => + hierarchy.children + .find{ case (label, child) => label == singleLabel } + .map{ case (label, child) => resolve(tail, child) } + .getOrElse( + Left(new Exception(s"Single label not found $singleLabel")) + ) + case Right(cross) => + resolve(tail, hierarchy.crossChildren.get._2) + } + case Nil => Left(new Exception("Nothing to run")) + } + } - for((k, fs) <- failing){ - val ks = k match{ - case Left(t) => t.toString - case Right(t) => t.segments.mkString(".") - } - val fss = fs.map{ - case Result.Exception(t) => t.toString - case Result.Failure(t) => t - } - log.error(ks + " " + fss.mkString(", ")) - } + def discoverMirror[T: Discovered](obj: T): Either[Throwable, Discovered[T]] = { + val discovered = implicitly[Discovered[T]] + val consistencyErrors = Discovered.consistencyCheck(obj, discovered) + if (consistencyErrors.nonEmpty) { + Left(new Exception(s"Failed Discovered.consistencyCheck: $consistencyErrors")) + } else { + Right(discovered) + } + } + + def evaluate(evaluator: Evaluator, + target: Task[Any], + watch: Path => Unit): Either[Throwable, Int] = { + val evaluated = evaluator.evaluate(OSet(target)) + evaluated.transitive.foreach { + case t: define.Source => watch(t.handle.path) + case _ => // do nothing + } - if (evaluated.failing.keyCount == 0) 0 else 1 - case None => - log.error("Unknown selector: " + selector.mkString(".")) - 1 - } + val errorStr = + (for((k, fs) <- evaluated.failing.items) yield { + val ks = k match{ + case Left(t) => t.toString + case Right(t) => t.segments.mkString(".") } + val fss = fs.map{ + case Result.Exception(t) => t.toString + case Result.Failure(t) => t + } + s"$ks ${fss.mkString(", ")}" + }).mkString("\n") + + evaluated.failing.keyCount match { + case 0 => + Right(0) + case n => + Left(new Exception(s"$n targets failed\n$errorStr")) } + } + def apply[T: Discovered](args: Seq[String], + obj: T, + watch: Path => Unit, + coloredOutput: Boolean): Int = { + + val log = new Logger(coloredOutput) + val Seq(_, rest @_*) = args + + (for { + sel <- parseArgs(args) + disc <- discoverMirror(obj) + val crossSelectors = sel.collect{case Right(x) => x.toList} + target <- resolve(sel, disc.mirror)(obj, rest, crossSelectors) + val mapping = Discovered.mapping(obj)(disc) + val workspacePath = pwd / 'out + val evaluator = new Evaluator(workspacePath, mapping, log.info) + r <- evaluate(evaluator, target, watch) + } yield { + r + }) match { + case Left(err) => + log.error(err.getMessage) + 1 + case Right(n) => + n + } } case class Config(home: ammonite.ops.Path = pwd/'out/'ammonite, diff --git a/core/src/main/scala/mill/define/Cross.scala b/core/src/main/scala/mill/define/Cross.scala index 0ab87802..ccee459c 100644 --- a/core/src/main/scala/mill/define/Cross.scala +++ b/core/src/main/scala/mill/define/Cross.scala @@ -9,8 +9,10 @@ case class Cross[+T](items: List[(List[Any], T)]){ def map[V](f: T => V): Cross[V] = new Cross(items.map{case (l, v) => (l, f(v))}) def withFilter(f: T => Boolean): Cross[T] = new Cross(items.filter(t => f(t._2))) - def apply(input: List[Any]): T = items.find(_._1 == input).get._2 + def apply(input: List[Any]): T = + items.find(_._1 == input).map(_._2) + .getOrElse(null.asInstanceOf[T]) } object Cross{ def apply[T](t: T*) = new Cross(t.map(i => List(i) -> i).toList) -}
\ No newline at end of file +} |