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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package mill.main
import mill.define._
import mill.define.TaskModule
import ammonite.main.Router
import ammonite.main.Router.EntryPoint
object Resolve {
def resolve[T, V](remainingSelector: List[Segment],
obj: mill.Module,
discover: Discover[_],
rest: Seq[String],
remainingCrossSelectors: List[List[String]],
revSelectorsSoFar: List[Segment]): Either[String, Seq[Task[Any]]] = {
remainingSelector match{
case Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment")
case Segment.Label(last) :: Nil =>
val target =
obj
.millInternal
.reflect[Target[_]]
.find(_.label == last)
.map(Right(_))
def invokeCommand(target: mill.Module, name: String) = {
for{
(cls, entryPoints) <- discover.value.filterKeys(_.isAssignableFrom(target.getClass))
ep <- entryPoints
if ep._2.name == name
} yield ep._2.asInstanceOf[EntryPoint[mill.Module]].invoke(target, ammonite.main.Scripts.groupArgs(rest.toList)) match {
case Router.Result.Success(v) => Right(v)
case _ => Left(s"Command failed $last")
}
}
val runDefault = for{
child <- obj.millInternal.reflectNestedObjects[mill.Module]
if child.millOuterCtx.segment == Segment.Label(last)
res <- child match{
case taskMod: TaskModule => Some(invokeCommand(child, taskMod.defaultCommandName()).headOption)
case _ => None
}
} yield res
val command = invokeCommand(obj, last).headOption
command orElse target orElse runDefault.flatten.headOption match{
case None => Left("Cannot resolve task " +
Segments((Segment.Label(last) :: revSelectorsSoFar).reverse:_*).render
)
// Contents of `either` *must* be a `Task`, because we only select
// methods returning `Task` in the discovery process
case Some(either) => either.right.map{ case x: Task[Any] => Seq(x) }
}
case head :: tail =>
val newRevSelectorsSoFar = head :: revSelectorsSoFar
head match{
case Segment.Label(singleLabel) =>
if (singleLabel == "__"){
val matching =
obj.millInternal
.modules
.map(resolve(tail, _, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar))
.collect{case Right(vs) => vs}.flatten
if (matching.nonEmpty) Right(matching.toSeq)
else Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
}else if (singleLabel == "_") {
val matching =
obj.millInternal
.reflectNestedObjects[mill.Module]
.map(resolve(tail, _, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar))
.collect{case Right(vs) => vs}.flatten
if (matching.nonEmpty)Right(matching)
else Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
}else{
obj.millInternal.reflectNestedObjects[mill.Module].find{
_.millOuterCtx.segment == Segment.Label(singleLabel)
} match{
case Some(child: mill.Module) => resolve(tail, child, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
case None => Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
}
}
case Segment.Cross(cross) =>
obj match{
case c: Cross[_] =>
if(cross == Seq("__")){
val matching =
for ((k, v) <- c.items)
yield resolve(tail, v.asInstanceOf[mill.Module], discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
val results = matching.collect{case Right(res) => res}.flatten
if (results.isEmpty) Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
else Right(results)
} else if (cross.contains("_")){
val matching = for {
(k, v) <- c.items
if k.length == cross.length
if k.zip(cross).forall { case (l, r) => l == r || r == "_" }
} yield resolve(tail, v.asInstanceOf[mill.Module], discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
val results = matching.collect{case Right(res) => res}.flatten
if (results.isEmpty) Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
else Right(results)
}else{
c.itemMap.get(cross.toList) match{
case Some(m: mill.Module) => resolve(tail, m, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
case None => Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
}
}
case _ => Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
}
}
case Nil => Left("Selector cannot be empty")
}
}
}
|