diff options
Diffstat (limited to 'main/core/src/mill/define/Task.scala')
-rw-r--r-- | main/core/src/mill/define/Task.scala | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/main/core/src/mill/define/Task.scala b/main/core/src/mill/define/Task.scala new file mode 100644 index 00000000..d5f8680e --- /dev/null +++ b/main/core/src/mill/define/Task.scala @@ -0,0 +1,353 @@ +package mill.define + +import ammonite.main.Router.Overrides +import mill.define.Applicative.Applyable +import mill.eval.{PathRef, Result} +import mill.util.EnclosingClass +import sourcecode.Compat.Context +import upickle.default.{ReadWriter => RW, Reader => R, Writer => W} + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + + +/** + * Models a single node in the Mill build graph, with a list of inputs and a + * single output of type [[T]]. + * + * Generally not instantiated manually, but instead constructed via the + * [[Target.apply]] & similar macros. + */ +abstract class Task[+T] extends Task.Ops[T] with Applyable[Task, T]{ + /** + * What other Targets does this Target depend on? + */ + val inputs: Seq[Task[_]] + + /** + * Evaluate this target + */ + def evaluate(args: mill.util.Ctx): Result[T] + + /** + * Even if this target's inputs did not change, does it need to re-evaluate + * anyway? + */ + def sideHash: Int = 0 + + def flushDest: Boolean = true + + def asTarget: Option[Target[T]] = None + def asCommand: Option[Command[T]] = None + def asWorker: Option[Worker[T]] = None + def self = this +} + +trait NamedTask[+T] extends Task[T]{ + def ctx: mill.define.Ctx + def label = ctx.segment match{case Segment.Label(v) => v} + override def toString = ctx.segments.render +} +trait Target[+T] extends NamedTask[T]{ + override def asTarget = Some(this) + def readWrite: RW[_] +} + +object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Result, mill.util.Ctx] { + + implicit def apply[T](t: T) + (implicit rw: RW[T], + ctx: mill.define.Ctx): Target[T] = macro targetImpl[T] + + def targetImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[T]) + (rw: c.Expr[RW[T]], + ctx: c.Expr[mill.define.Ctx]): c.Expr[Target[T]] = { + import c.universe._ + val lhs = Applicative.impl0[Task, T, mill.util.Ctx](c)(reify(Result.Success(t.splice)).tree) + + mill.moduledefs.Cacher.impl0[TargetImpl[T]](c)( + reify( + new TargetImpl[T](lhs.splice, ctx.splice, rw.splice) + ) + ) + } + + implicit def apply[T](t: Result[T]) + (implicit rw: RW[T], + ctx: mill.define.Ctx): Target[T] = macro targetResultImpl[T] + + def targetResultImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[Result[T]]) + (rw: c.Expr[RW[T]], + ctx: c.Expr[mill.define.Ctx]): c.Expr[Target[T]] = { + import c.universe._ + mill.moduledefs.Cacher.impl0[Target[T]](c)( + reify( + new TargetImpl[T]( + Applicative.impl0[Task, T, mill.util.Ctx](c)(t.tree).splice, + ctx.splice, + rw.splice + ) + ) + ) + } + + def apply[T](t: Task[T]) + (implicit rw: RW[T], + ctx: mill.define.Ctx): Target[T] = macro targetTaskImpl[T] + + def targetTaskImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[Task[T]]) + (rw: c.Expr[RW[T]], + ctx: c.Expr[mill.define.Ctx]): c.Expr[Target[T]] = { + import c.universe._ + mill.moduledefs.Cacher.impl0[Target[T]](c)( + reify( + new TargetImpl[T](t.splice, ctx.splice, rw.splice) + ) + ) + } + + def sources(values: Result[ammonite.ops.Path]*) + (implicit ctx: mill.define.Ctx): Sources = macro sourcesImpl1 + + def sourcesImpl1(c: Context) + (values: c.Expr[Result[ammonite.ops.Path]]*) + (ctx: c.Expr[mill.define.Ctx]): c.Expr[Sources] = { + import c.universe._ + val wrapped = + for (value <- values.toList) + yield Applicative.impl0[Task, PathRef, mill.util.Ctx](c)( + reify(value.splice.map(PathRef(_))).tree + ).tree + + mill.moduledefs.Cacher.impl0[Sources](c)( + reify( + new Sources( + Task.sequence(c.Expr[List[Task[PathRef]]](q"scala.List(..$wrapped)").splice), + ctx.splice + ) + ) + ) + } + + def sources(values: Result[Seq[PathRef]]) + (implicit ctx: mill.define.Ctx): Sources = macro sourcesImpl2 + + def sourcesImpl2(c: Context) + (values: c.Expr[Result[Seq[PathRef]]]) + (ctx: c.Expr[mill.define.Ctx]): c.Expr[Sources] = { + import c.universe._ + + + mill.moduledefs.Cacher.impl0[Sources](c)( + reify( + new Sources( + Applicative.impl0[Task, Seq[PathRef], mill.util.Ctx](c)(values.tree).splice, + ctx.splice + ) + ) + ) + } + def input[T](value: Result[T]) + (implicit rw: RW[T], + ctx: mill.define.Ctx): Input[T] = macro inputImpl[T] + + def inputImpl[T: c.WeakTypeTag](c: Context) + (value: c.Expr[T]) + (rw: c.Expr[RW[T]], + ctx: c.Expr[mill.define.Ctx]): c.Expr[Input[T]] = { + import c.universe._ + + mill.moduledefs.Cacher.impl0[Input[T]](c)( + reify( + new Input[T]( + Applicative.impl[Task, T, mill.util.Ctx](c)(value).splice, + ctx.splice, + rw.splice + ) + ) + ) + } + + def command[T](t: Task[T]) + (implicit ctx: mill.define.Ctx, + w: W[T], + cls: EnclosingClass, + overrides: Overrides): Command[T] = { + new Command(t, ctx, w, cls.value, overrides.value) + } + + def command[T](t: Result[T]) + (implicit w: W[T], + ctx: mill.define.Ctx, + cls: EnclosingClass, + overrides: Overrides): Command[T] = macro commandImpl[T] + + def commandImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[T]) + (w: c.Expr[W[T]], + ctx: c.Expr[mill.define.Ctx], + cls: c.Expr[EnclosingClass], + overrides: c.Expr[Overrides]): c.Expr[Command[T]] = { + import c.universe._ + reify( + new Command[T]( + Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, + ctx.splice, + w.splice, + cls.splice.value, + overrides.splice.value + ) + ) + } + + def worker[T](t: Task[T]) + (implicit ctx: mill.define.Ctx): Worker[T] = new Worker(t, ctx) + + def worker[T](t: Result[T]) + (implicit ctx: mill.define.Ctx): Worker[T] = macro workerImpl[T] + + def workerImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[T]) + (ctx: c.Expr[mill.define.Ctx]): c.Expr[Worker[T]] = { + import c.universe._ + reify( + new Worker[T](Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, ctx.splice) + ) + } + + def task[T](t: Result[T]): Task[T] = macro Applicative.impl[Task, T, mill.util.Ctx] + + def persistent[T](t: Result[T])(implicit rw: RW[T], + ctx: mill.define.Ctx): Persistent[T] = macro persistentImpl[T] + + def persistentImpl[T: c.WeakTypeTag](c: Context) + (t: c.Expr[T]) + (rw: c.Expr[RW[T]], + ctx: c.Expr[mill.define.Ctx]): c.Expr[Persistent[T]] = { + import c.universe._ + + + mill.moduledefs.Cacher.impl0[Persistent[T]](c)( + reify( + new Persistent[T]( + Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, + ctx.splice, + rw.splice + ) + ) + ) + } + + type TT[+X] = Task[X] + def makeT[X](inputs0: Seq[TT[_]], evaluate0: mill.util.Ctx => Result[X]) = new Task[X] { + val inputs = inputs0 + def evaluate(x: mill.util.Ctx) = evaluate0(x) + } + + def underlying[A](v: Task[A]) = v + def mapCtx[A, B](t: Task[A])(f: (A, mill.util.Ctx) => Result[B]) = t.mapDest(f) + def zip() = new Task.Task0(()) + def zip[A](a: Task[A]) = a.map(Tuple1(_)) + def zip[A, B](a: Task[A], b: Task[B]) = a.zip(b) +} + +case class Caller[A](value: A) +object Caller { + def apply[T]()(implicit c: Caller[T]) = c.value + implicit def generate[T]: Caller[T] = macro impl[T] + def impl[T: c.WeakTypeTag](c: Context): c.Tree = { + import c.universe._ + q"new _root_.mill.define.Caller[${weakTypeOf[T]}](this)" + } +} +abstract class NamedTaskImpl[+T](ctx0: mill.define.Ctx, t: Task[T]) extends NamedTask[T]{ + def evaluate(args: mill.util.Ctx) = args[T](0) + val ctx = ctx0.copy(segments = ctx0.segments ++ Seq(ctx0.segment)) + val inputs = Seq(t) +} + +class TargetImpl[+T](t: Task[T], + ctx0: mill.define.Ctx, + val readWrite: RW[_]) extends NamedTaskImpl[T](ctx0, t) with Target[T] { +} + +class Command[+T](t: Task[T], + ctx0: mill.define.Ctx, + val writer: W[_], + val cls: Class[_], + val overrides: Int) extends NamedTaskImpl[T](ctx0, t) { + override def asCommand = Some(this) +} + +class Worker[+T](t: Task[T], ctx0: mill.define.Ctx) extends NamedTaskImpl[T](ctx0, t) { + override def flushDest = false + override def asWorker = Some(this) +} +class Persistent[+T](t: Task[T], + ctx0: mill.define.Ctx, + readWrite: RW[_]) + extends TargetImpl[T](t, ctx0, readWrite) { + + override def flushDest = false +} +class Input[T](t: Task[T], + ctx0: mill.define.Ctx, + val readWrite: RW[_]) extends NamedTaskImpl[T](ctx0, t) with Target[T]{ + override def sideHash = util.Random.nextInt() +} +class Sources(t: Task[Seq[PathRef]], + ctx0: mill.define.Ctx) extends Input[Seq[PathRef]]( + t, + ctx0, + RW.join( + upickle.default.SeqLikeReader[Seq, PathRef], + upickle.default.SeqLikeWriter[Seq, PathRef] + ) +) +object Task { + + class Task0[T](t: T) extends Task[T]{ + lazy val t0 = t + val inputs = Nil + def evaluate(args: mill.util.Ctx) = t0 + } + + abstract class Ops[+T]{ this: Task[T] => + def map[V](f: T => V) = new Task.Mapped(this, f) + def mapDest[V](f: (T, mill.util.Ctx) => Result[V]) = new Task.MappedDest(this, f) + + def filter(f: T => Boolean) = this + def withFilter(f: T => Boolean) = this + def zip[V](other: Task[V]) = new Task.Zipped(this, other) + + } + + def traverse[T, V](source: Seq[T])(f: T => Task[V]) = { + new Sequence[V](source.map(f)) + } + def sequence[T](source: Seq[Task[T]]) = new Sequence[T](source) + + class Sequence[+T](inputs0: Seq[Task[T]]) extends Task[Seq[T]]{ + val inputs = inputs0 + def evaluate(args: mill.util.Ctx) = { + for (i <- 0 until args.length) + yield args(i).asInstanceOf[T] + } + + } + class Mapped[+T, +V](source: Task[T], f: T => V) extends Task[V]{ + def evaluate(args: mill.util.Ctx) = f(args(0)) + val inputs = List(source) + } + class MappedDest[+T, +V](source: Task[T], f: (T, mill.util.Ctx) => Result[V]) extends Task[V]{ + def evaluate(args: mill.util.Ctx) = f(args(0), args) + val inputs = List(source) + } + class Zipped[+T, +V](source1: Task[T], source2: Task[V]) extends Task[(T, V)]{ + def evaluate(args: mill.util.Ctx) = (args(0), args(1)) + val inputs = List(source1, source2) + } +} |