summaryrefslogblamecommitdiff
path: root/main/core/src/mill/define/Task.scala
blob: 64e868f8308ae376a9dac361c52e2dbab7c576ba (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
 
                                     
                                        
                                  
                               
                                

                                                                   


                                            
 






                                                                             
                                                                    







                                                    
                                              





                                                                              

                               


                                          
                                        
                 

 
                                    
                          
                                                           
                                             

                                      
                                    
                      
 
 
                                                                                                   
 
                             
                                           
                                                                              
 

                                                
                                                     
                                                                                       
                       
                                                                                                
 
                                                   
            
                                                            



       
                                     
                                           
                                                                                    
 

                                                              
                                                           
                                                                                             
                       
                                               

                          
                                                                      
                     
                   
         



       
                          
                                  
                                                                         
 

                                                          
                                                         
                                                                                           
                       
                                               
            
                                                          



       





                                                                          
                       






                                                               
            


                                                                                       




         

















                                                                                      
                                
                                  
                                                                    
 
                                             
                                                    
                                                     
                                                                                      

                       
                                              
            
                     
                                                                    
                     
                   



         
 
                            
                                               




                                                      


                                  


                                                                         
 


                                                    


                                                                                         
                       
          






                                                              


     














                                                                                       
                                                                                     
 
                                                     
                                                                                                
 

                                                    
                                                         
                                                                                               

                       
 
                                                   

                          
                                                                
                     
                   
         


       
 
                       
                                                                                          
                        
                                                 

   
                                   
                                                                                 


                                                  
 
 




                                                                                         

                                
                                           
                                                                                             
 
 
                             
                                        


                                                                         
                                     
 
 
                                                                                       
                                

                                    
                                
                                           


                                             

                                
                          
                                     
                                                                                      
                                               
 



                                                                 


                                                

   

             
                                       

                    
                                           
   
 

                                                    
                                                                                     






                                                             

                                                         
   


                                                                 
                        
                                         





                                                                   
                                                  

                             

                                                                                                


                                                                                
                                                          

                                       
 
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)
}

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)
  }
}