summaryrefslogtreecommitdiff
path: root/core/src/mill/main/MagicScopt.scala
blob: acba57cb97b7f8fd62d972245685ee9965464fdf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package mill.main
import mill.define.ExternalModule
import mill.main.ParseArgs

object MagicScopt{
  // This needs to be a ThreadLocal because we need to pass it into the body of
  // the TargetScopt#read call, which does not accept additional parameters.
  // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule
  // in directly) we are forced to pass it in via a ThreadLocal
  val currentEvaluator = new ThreadLocal[mill.eval.Evaluator[_]]

  case class Tasks[T](items: Seq[mill.define.NamedTask[T]])
}
class EvaluatorScopt[T]()
  extends scopt.Read[mill.eval.Evaluator[T]]{
  def arity = 0
  def reads = s => try{
    MagicScopt.currentEvaluator.get.asInstanceOf[mill.eval.Evaluator[T]]
  }
}
class TargetScopt[T]()
  extends scopt.Read[MagicScopt.Tasks[T]]{
  def arity = 0
  def reads = s => {
    val rootModule = MagicScopt.currentEvaluator.get.rootModule
    val d = rootModule.millDiscover
    val (expanded, leftover) = ParseArgs(Seq(s)).fold(e => throw new Exception(e), identity)
    val resolved = expanded.map{
      case (Some(scoping), segments) =>
        val moduleCls = rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
        val externalRootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
        val crossSelectors = segments.value.map {
          case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
          case _ => Nil
        }
        mill.main.Resolve.resolve(segments.value.toList, externalRootModule, d, leftover, crossSelectors.toList, Nil)
      case (None, segments) =>
        val crossSelectors = segments.value.map {
          case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
          case _ => Nil
        }
        mill.main.Resolve.resolve(segments.value.toList, rootModule, d, leftover, crossSelectors.toList, Nil)
    }
    mill.util.EitherOps.sequence(resolved) match{
      case Left(s) => throw new Exception(s)
      case Right(ts) => MagicScopt.Tasks(ts.flatten).asInstanceOf[MagicScopt.Tasks[T]]
    }
  }
}