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
|
package mill.define
import language.experimental.macros
import scala.reflect.macros.blackbox
object Cross{
case class Factory[T](make: (Product, mill.define.Ctx) => T)
object Factory{
implicit def make[T]: Factory[T] = macro makeImpl[T]
def makeImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Factory[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val primaryConstructorArgs =
tpe.typeSymbol.asClass.primaryConstructor.typeSignature.paramLists.head
val argTupleValues =
for((a, n) <- primaryConstructorArgs.zipWithIndex)
yield q"v.productElement($n).asInstanceOf[${a.info}]"
val instance = c.Expr[(Product, mill.define.Ctx) => T](
q"{ (v, ctx0) => new $tpe(..$argTupleValues){ override def ctx = ctx0 } }"
)
reify { mill.define.Cross.Factory[T](instance.splice) }
}
}
trait Resolver[-T]{
def resolve[V <: T](c: Cross[V]): V
}
}
/**
* Models "cross-builds": sets of duplicate builds which differ only in the
* value of one or more "case" variables whose values are determined at runtime.
* Used via:
*
* object foo extends Cross[FooModule]("bar", "baz", "qux")
* class FooModule(v: String) extends Module{
* ...
* }
*/
class Cross[T](cases: Any*)
(implicit ci: Cross.Factory[T],
ctx: mill.define.Ctx) extends mill.define.Module()(ctx) {
override lazy val modules = this.reflectNestedObjects[Module] ++ items.collect{case (k, v: mill.define.Module) => v}
val items = for(c0 <- cases.toList) yield{
val c = c0 match{
case p: Product => p
case v => Tuple1(v)
}
val crossValues = c.productIterator.toList.reverse
val relPath = ctx.segment match{
case Segment.Label(s) => ammonite.ops.empty / s
case Segment.Cross(vs) => ammonite.ops.empty / vs.map(_.toString)
}
val sub = ci.make(
c,
ctx.copy(
segments0 = ctx.segments0 ++ Seq(ctx.segment),
basePath = ctx.basePath / relPath,
segment = Segment.Cross(crossValues)
)
)
(crossValues, sub)
}
val itemMap = items.toMap
/**
* Fetch the cross module corresponding to the given cross values
*/
def get(args: Seq[Any]) = itemMap(args.toList)
/**
* Fetch the cross module corresponding to the given cross values
*/
def apply(arg0: Any, args: Any*) = itemMap(arg0 :: args.toList)
/**
* Fetch the relevant cross module given the implicit resolver you have in
* scope. This is often the first cross module whose cross-version is
* compatible with the current module.
*/
def apply[V >: T]()(implicit resolver: Cross.Resolver[V]): T = {
resolver.resolve(this.asInstanceOf[Cross[V]]).asInstanceOf[T]
}
}
|