From 7589250f87dd70e52cec923dcda5d554a4c7bbcb Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 13 Jan 2018 22:18:05 -0800 Subject: Remove targets generation in Mirror, in favor of just using java.reflect --- core/src/main/scala/mill/define/Module.scala | 9 ++ core/src/main/scala/mill/define/Task.scala | 1 + core/src/main/scala/mill/discover/Discovered.scala | 23 +--- core/src/main/scala/mill/discover/Mirror.scala | 9 -- .../main/scala/mill/main/ReplApplyHandler.scala | 11 +- core/src/main/scala/mill/main/Resolve.scala | 7 +- core/src/main/scala/mill/util/AggWrapper.scala | 116 +++++++++++++++++++++ core/src/main/scala/mill/util/OSet.scala | 116 --------------------- 8 files changed, 138 insertions(+), 154 deletions(-) create mode 100644 core/src/main/scala/mill/util/AggWrapper.scala delete mode 100644 core/src/main/scala/mill/util/OSet.scala diff --git a/core/src/main/scala/mill/define/Module.scala b/core/src/main/scala/mill/define/Module.scala index c9240fa0..064741c4 100644 --- a/core/src/main/scala/mill/define/Module.scala +++ b/core/src/main/scala/mill/define/Module.scala @@ -4,6 +4,7 @@ import ammonite.main.Router.Overrides import ammonite.ops.Path import scala.annotation.implicitNotFound +import scala.reflect.ClassTag sealed trait Segment object Segment{ @@ -55,6 +56,14 @@ class Module(implicit ctx0: Module.Ctx) extends mill.moduledefs.Cacher{ implicit def millModuleSegments: Segments = { ctx.segments0 ++ Seq(ctx.segment) } + def reflect[T: ClassTag] = { + this + .getClass + .getMethods + .filter(_.getParameterCount == 0) + .filter(implicitly[ClassTag[T]].runtimeClass isAssignableFrom _.getReturnType) + .map(_.invoke(this).asInstanceOf[T]) + } } object Module{ @implicitNotFound("Modules, Targets and Commands can only be defined within a mill Module") diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index eac64cd5..2a670d21 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -42,6 +42,7 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[Task, T]{ trait NamedTask[+T] extends Task[T]{ def ctx: Module.Ctx + def label = ctx.segment match{case Segment.Label(v) => v} } trait Target[+T] extends NamedTask[T]{ override def asTarget = Some(this) diff --git a/core/src/main/scala/mill/discover/Discovered.scala b/core/src/main/scala/mill/discover/Discovered.scala index 98d4ebb9..6296645a 100644 --- a/core/src/main/scala/mill/discover/Discovered.scala +++ b/core/src/main/scala/mill/discover/Discovered.scala @@ -3,7 +3,6 @@ package mill.discover import mill.define._ import ammonite.main.Router import ammonite.main.Router.EntryPoint -import mill.discover.Mirror.TargetPoint import mill.util.Ctx.Loader import mill.util.Strict.Agg @@ -30,8 +29,7 @@ object Discovered { val targets = Agg.from( Mirror.traverseNode(base, mirror){ (mirror, segmentsRev, resolvedNode) => - for(target <- mirror.targets) - yield target.asInstanceOf[TargetPoint[Any, Any]].run(resolvedNode) + resolvedNode.asInstanceOf[mill.Module].reflect[Target[_]] } ) @@ -69,24 +67,6 @@ object Discovered { val r = new Router(c) - val targets = for { - m <- t.members.toList - if m.isMethod && - m.typeSignature.paramLists.isEmpty && - m.typeSignature.resultType <:< c.weakTypeOf[Target[_]] && - !m.name.toString.contains(' ') && - m.isPublic - } yield { - val x = Ident(TermName(c.freshName())) - val t = q"""mill.discover.Mirror.TargetPoint( - ${m.name.toString}, - ($x: ${m.typeSignature.resultType}) => $x.${m.name.toTermName} - )""" - - c.internal.setPos(t, m.pos) - t - } - val crossChildren = if (!(t <:< c.weakTypeOf[Cross[_]])) q"None" else { @@ -128,7 +108,6 @@ object Discovered { q"""mill.discover.Mirror[$baseType, $t]( $hierarchySelector, $commands, - $targets, $childHierarchies, $crossChildren )""" diff --git a/core/src/main/scala/mill/discover/Mirror.scala b/core/src/main/scala/mill/discover/Mirror.scala index bb6e44ad..ffa86225 100644 --- a/core/src/main/scala/mill/discover/Mirror.scala +++ b/core/src/main/scala/mill/discover/Mirror.scala @@ -15,13 +15,11 @@ import scala.language.experimental.macros */ case class Mirror[-T, V](node: (T, List[List[Any]]) => V, commands: Seq[EntryPoint[V]], - targets: Seq[Mirror.TargetPoint[V, _]], children: List[(String, Mirror[T, _])], crossChildren: Option[(V => List[List[Any]], Mirror[T, _])]) object Mirror{ - def traverseNode[T, V, R](t: T, hierarchy: Mirror[T, V]) (f: (Mirror[T, _], => Segments, => Any) => Seq[R]): Seq[R] = { traverse(t, hierarchy){ (mirror, segmentsRev) => @@ -48,11 +46,4 @@ object Mirror{ } rec(Nil, hierarchy) } - - - /** - * Represents metadata about a particular target, before the target is - * materialized for a concrete build - */ - case class TargetPoint[T, V](label: String, run: T => Target[V]) } diff --git a/core/src/main/scala/mill/main/ReplApplyHandler.scala b/core/src/main/scala/mill/main/ReplApplyHandler.scala index c239745a..718ca358 100644 --- a/core/src/main/scala/mill/main/ReplApplyHandler.scala +++ b/core/src/main/scala/mill/main/ReplApplyHandler.scala @@ -83,10 +83,13 @@ class ReplApplyHandler(pprinter0: pprint.PPrinter, evaluator: Evaluator[_]) exte c.argSignatures.map(s => s.name + ": " + s.typeString).mkString(", ") + ")()" }) ++ - (if (mirror.targets.isEmpty) Nil - else ctx.applyPrefixColor("\nTargets:").toString +: mirror.targets.sortBy(_.label).map(t => - "\n ." + t.label + "()" - )) + (if (m.reflect[Target[_]].isEmpty) Nil + else { + Seq(ctx.applyPrefixColor("\nTargets:").toString) ++ + m.reflect[Target[_]].sortBy(_.label).map(t => + "\n ." + t.label + "()" + ) + }) ) case t: mill.define.Target[_] if evaluator.mapping.targets.contains(t) => diff --git a/core/src/main/scala/mill/main/Resolve.scala b/core/src/main/scala/mill/main/Resolve.scala index 35b07a26..1567f26a 100644 --- a/core/src/main/scala/mill/main/Resolve.scala +++ b/core/src/main/scala/mill/main/Resolve.scala @@ -1,6 +1,6 @@ package mill.main -import mill.define.{Segment, Segments, Task} +import mill.define.{Segment, Segments, Target, Task} import mill.define.Task.TaskModule import mill.discover.Mirror import ammonite.main.Router @@ -17,9 +17,10 @@ object Resolve { case Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment") case Segment.Label(last) :: Nil => def target = - hierarchy.targets + hierarchy.node(obj, remainingCrossSelectors).asInstanceOf[mill.Module] + .reflect[Target[_]] .find(_.label == last) - .map(x => Right(x.run(hierarchy.node(obj, remainingCrossSelectors)))) + .map(Right(_)) def invokeCommand[V](mirror: Mirror[T, V], name: String) = for{ cmd <- mirror.commands.find(_.name == name) diff --git a/core/src/main/scala/mill/util/AggWrapper.scala b/core/src/main/scala/mill/util/AggWrapper.scala new file mode 100644 index 00000000..c2994a9a --- /dev/null +++ b/core/src/main/scala/mill/util/AggWrapper.scala @@ -0,0 +1,116 @@ +package mill.util + + + +import scala.collection.mutable +object Strict extends AggWrapper(true) +object Loose extends AggWrapper(false) +sealed class AggWrapper(strictUniqueness: Boolean){ + /** + * A collection with enforced uniqueness, fast contains and deterministic + * ordering. Raises an exception if a duplicate is found; call + * `toSeq.distinct` if you explicitly want to make it swallow duplicates + */ + trait Agg[V] extends TraversableOnce[V]{ + def contains(v: V): Boolean + def items: Iterator[V] + def indexed: IndexedSeq[V] + def flatMap[T](f: V => TraversableOnce[T]): Agg[T] + def map[T](f: V => T): Agg[T] + def filter(f: V => Boolean): Agg[V] + def withFilter(f: V => Boolean): Agg[V] + def collect[T](f: PartialFunction[V, T]): Agg[T] + def zipWithIndex: Agg[(V, Int)] + def reverse: Agg[V] + def zip[T](other: Agg[T]): Agg[(V, T)] + def ++[T >: V](other: TraversableOnce[T]): Agg[T] + } + + object Agg{ + def empty[V]: Agg[V] = new Agg.Mutable[V] + implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[Agg[T]] = + upickle.default.ReadWriter[Agg[T]] ( + oset => upickle.default.writeJs(oset.toList), + {case json => Agg.from(upickle.default.readJs[Seq[T]](json))} + ) + def apply[V](items: V*) = from(items) + + implicit def from[V](items: TraversableOnce[V]): Agg[V] = { + val set = new Agg.Mutable[V]() + items.foreach(set.append) + set + } + + + class Mutable[V]() extends Agg[V]{ + + private[this] val set0 = mutable.LinkedHashSet.empty[V] + def contains(v: V) = set0.contains(v) + def append(v: V) = if (!contains(v)){ + set0.add(v) + + }else if (strictUniqueness){ + throw new Exception("Duplicated item inserted into OrderedSet: " + v) + } + def appendAll(vs: Seq[V]) = vs.foreach(append) + def items = set0.iterator + def indexed: IndexedSeq[V] = items.toIndexedSeq + def set: collection.Set[V] = set0 + + def map[T](f: V => T): Agg[T] = { + val output = new Agg.Mutable[T] + for(i <- items) output.append(f(i)) + output + } + def flatMap[T](f: V => TraversableOnce[T]): Agg[T] = { + val output = new Agg.Mutable[T] + for(i <- items) for(i0 <- f(i)) output.append(i0) + output + } + def filter(f: V => Boolean): Agg[V] = { + val output = new Agg.Mutable[V] + for(i <- items) if (f(i)) output.append(i) + output + } + def withFilter(f: V => Boolean): Agg[V] = filter(f) + + def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) + + def zipWithIndex = { + var i = 0 + this.map{ x => + i += 1 + (x, i-1) + } + } + + def reverse = Agg.from(indexed.reverseIterator) + + def zip[T](other: Agg[T]) = Agg.from(items.zip(other.items)) + def ++[T >: V](other: TraversableOnce[T]) = Agg.from(items ++ other) + + // Members declared in scala.collection.GenTraversableOnce + def isTraversableAgain: Boolean = items.isTraversableAgain + def toIterator: Iterator[V] = items.toIterator + def toStream: Stream[V] = items.toStream + + // Members declared in scala.collection.TraversableOnce + def copyToArray[B >: V](xs: Array[B], start: Int,len: Int): Unit = items.copyToArray(xs, start, len) + def exists(p: V => Boolean): Boolean = items.exists(p) + def find(p: V => Boolean): Option[V] = items.find(p) + def forall(p: V => Boolean): Boolean = items.forall(p) + def foreach[U](f: V => U): Unit = items.foreach(f) + def hasDefiniteSize: Boolean = items.hasDefiniteSize + def isEmpty: Boolean = items.isEmpty + def seq: scala.collection.TraversableOnce[V] = items + def toTraversable: Traversable[V] = items.toTraversable + + override def hashCode() = items.map(_.hashCode()).sum + override def equals(other: Any) = other match{ + case s: Agg[_] => items.sameElements(s.items) + case _ => super.equals(other) + } + override def toString = items.mkString("Agg(", ", ", ")") + } + } +} diff --git a/core/src/main/scala/mill/util/OSet.scala b/core/src/main/scala/mill/util/OSet.scala deleted file mode 100644 index d0f41777..00000000 --- a/core/src/main/scala/mill/util/OSet.scala +++ /dev/null @@ -1,116 +0,0 @@ -package mill.util - - - -import scala.collection.mutable -object Strict extends AggWrapper(true) -object Loose extends AggWrapper(false) -sealed class AggWrapper(strictUniqueness: Boolean){ - /** - * A collection with enforced uniqueness, fast contains and deterministic - * ordering. Raises an exception if a duplicate is found; call - * `toSeq.distinct` if you explicitly want to make it swallow duplicates - */ - trait Agg[V] extends TraversableOnce[V]{ - def contains(v: V): Boolean - def items: Iterator[V] - def indexed: IndexedSeq[V] - def flatMap[T](f: V => TraversableOnce[T]): Agg[T] - def map[T](f: V => T): Agg[T] - def filter(f: V => Boolean): Agg[V] - def withFilter(f: V => Boolean): Agg[V] - def collect[T](f: PartialFunction[V, T]): Agg[T] - def zipWithIndex: Agg[(V, Int)] - def reverse: Agg[V] - def zip[T](other: Agg[T]): Agg[(V, T)] - def ++[T >: V](other: TraversableOnce[T]): Agg[T] - } - - object Agg{ - def empty[V]: Agg[V] = new Agg.Mutable[V] - implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[Agg[T]] = - upickle.default.ReadWriter[Agg[T]] ( - oset => upickle.default.writeJs(oset.toList), - {case json => Agg.from(upickle.default.readJs[Seq[T]](json))} - ) - def apply[V](items: V*) = from(items) - - def from[V](items: TraversableOnce[V]): Agg[V] = { - val set = new Agg.Mutable[V]() - items.foreach(set.append) - set - } - - - class Mutable[V]() extends Agg[V]{ - - private[this] val set0 = mutable.LinkedHashSet.empty[V] - def contains(v: V) = set0.contains(v) - def append(v: V) = if (!contains(v)){ - set0.add(v) - - }else if (strictUniqueness){ - throw new Exception("Duplicated item inserted into OrderedSet: " + v) - } - def appendAll(vs: Seq[V]) = vs.foreach(append) - def items = set0.iterator - def indexed: IndexedSeq[V] = items.toIndexedSeq - def set: collection.Set[V] = set0 - - def map[T](f: V => T): Agg[T] = { - val output = new Agg.Mutable[T] - for(i <- items) output.append(f(i)) - output - } - def flatMap[T](f: V => TraversableOnce[T]): Agg[T] = { - val output = new Agg.Mutable[T] - for(i <- items) for(i0 <- f(i)) output.append(i0) - output - } - def filter(f: V => Boolean): Agg[V] = { - val output = new Agg.Mutable[V] - for(i <- items) if (f(i)) output.append(i) - output - } - def withFilter(f: V => Boolean): Agg[V] = filter(f) - - def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) - - def zipWithIndex = { - var i = 0 - this.map{ x => - i += 1 - (x, i-1) - } - } - - def reverse = Agg.from(indexed.reverseIterator) - - def zip[T](other: Agg[T]) = Agg.from(items.zip(other.items)) - def ++[T >: V](other: TraversableOnce[T]) = Agg.from(items ++ other) - - // Members declared in scala.collection.GenTraversableOnce - def isTraversableAgain: Boolean = items.isTraversableAgain - def toIterator: Iterator[V] = items.toIterator - def toStream: Stream[V] = items.toStream - - // Members declared in scala.collection.TraversableOnce - def copyToArray[B >: V](xs: Array[B], start: Int,len: Int): Unit = items.copyToArray(xs, start, len) - def exists(p: V => Boolean): Boolean = items.exists(p) - def find(p: V => Boolean): Option[V] = items.find(p) - def forall(p: V => Boolean): Boolean = items.forall(p) - def foreach[U](f: V => U): Unit = items.foreach(f) - def hasDefiniteSize: Boolean = items.hasDefiniteSize - def isEmpty: Boolean = items.isEmpty - def seq: scala.collection.TraversableOnce[V] = items - def toTraversable: Traversable[V] = items.toTraversable - - override def hashCode() = items.map(_.hashCode()).sum - override def equals(other: Any) = other match{ - case s: Agg[_] => items.sameElements(s.items) - case _ => super.equals(other) - } - override def toString = items.mkString("Agg(", ", ", ")") - } - } -} -- cgit v1.2.3