diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-12-04 21:55:01 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-12-04 21:55:15 -0800 |
commit | 422d41498d43ad9b437b2d4460f61849e78bb6fa (patch) | |
tree | 167ebadc8dab617bbc6388d1ff4d13b5b08115d1 | |
parent | e9f3c71f670f93c95f0ae47860e663b768885067 (diff) | |
download | mill-422d41498d43ad9b437b2d4460f61849e78bb6fa.tar.gz mill-422d41498d43ad9b437b2d4460f61849e78bb6fa.tar.bz2 mill-422d41498d43ad9b437b2d4460f61849e78bb6fa.zip |
- Make `T.ctx()` available implicitly
- Convert `ScalaModule.{compile,assembly}` to use the new implicit `T.ctx()`
- Add a `log: PrintStream` to the `T.ctx()`, in preparation for per-task logging
-rw-r--r-- | core/src/main/scala/mill/define/Applicative.scala | 13 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Task.scala | 49 | ||||
-rw-r--r-- | core/src/main/scala/mill/eval/Evaluator.scala | 8 | ||||
-rw-r--r-- | core/src/main/scala/mill/modules/Jvm.scala | 16 | ||||
-rw-r--r-- | core/src/main/scala/mill/util/Args.scala | 9 | ||||
-rw-r--r-- | core/src/main/scala/mill/util/Ctx.scala | 34 | ||||
-rw-r--r-- | core/src/test/examples/javac/build.sc | 4 | ||||
-rw-r--r-- | core/src/test/scala/mill/define/ApplicativeTests.scala | 5 | ||||
-rw-r--r-- | core/src/test/scala/mill/util/TestUtil.scala | 2 | ||||
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala | 28 |
10 files changed, 100 insertions, 68 deletions
diff --git a/core/src/main/scala/mill/define/Applicative.scala b/core/src/main/scala/mill/define/Applicative.scala index 4973dfd0..f8193742 100644 --- a/core/src/main/scala/mill/define/Applicative.scala +++ b/core/src/main/scala/mill/define/Applicative.scala @@ -1,9 +1,7 @@ package mill.define -import mill.util.Args -import scala.annotation.compileTimeOnly -import scala.collection.mutable +import scala.annotation.{StaticAnnotation, compileTimeOnly} import scala.reflect.macros.blackbox.Context /** @@ -20,11 +18,11 @@ object Applicative { @compileTimeOnly("Target#apply() can only be used with a T{...} block") def apply(): T = ??? } + class ImplicitStub extends StaticAnnotation type Id[+T] = T trait Applyer[W[_], T[_], Z[_], Ctx]{ - @compileTimeOnly("Target.ctx() can only be used with a T{...} block") - def ctx(): Ctx = ??? + def ctx()(implicit c: Ctx) = c def underlying[A](v: W[A]): T[_] def mapCtx[A, B](a: T[A])(f: (A, Ctx) => Z[B]): T[B] @@ -92,8 +90,9 @@ object Applicative { c.internal.setFlag(tempSym, (1L << 44).asInstanceOf[c.universe.FlagSet]) bound.append((q"${c.prefix}.underlying($fun)", c.internal.valDef(tempSym))) tempIdent - case (t @ q"$prefix.ctx()", api) - if prefix.tpe.baseClasses.exists(_.fullName == "mill.define.Applicative.Applyer") => + case (t, api) + if t.symbol != null + && t.symbol.annotations.exists(_.tree.tpe =:= typeOf[ImplicitStub]) => val tempIdent = Ident(ctxSym) c.internal.setType(tempIdent, t.tpe) diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index c54634db..451cc1d4 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -2,7 +2,7 @@ package mill.define import mill.define.Applicative.Applyable import mill.eval.{PathRef, Result} -import mill.util.Args +import mill.util.Ctx import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context @@ -16,7 +16,7 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ /** * Evaluate this target */ - def evaluate(args: Args): Result[T] + def evaluate(args: Ctx): Result[T] /** * Even if this target's inputs did not change, does it need to re-evaluate @@ -34,7 +34,8 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ trait Target[+T] extends Task[T]{ override def asTarget = Some(this) } -object Target extends Applicative.Applyer[Task, Task, Result, Args]{ + +object Target extends Applicative.Applyer[Task, Task, Result, Ctx]{ implicit def apply[T](t: T): Target[T] = macro targetImpl[T] @@ -48,7 +49,7 @@ object Target extends Applicative.Applyer[Task, Task, Result, Args]{ def command[T](t: Task[T]): Command[T] = new Command(t) - def task[T](t: Result[T]): Task[T] = macro Applicative.impl[Task, T, Args] + def task[T](t: Result[T]): Task[T] = macro Applicative.impl[Task, T, Ctx] def task[T](t: Task[T]): Task[T] = t def persistent[T](t: Result[T]): Target[T] = macro persistentImpl[T] @@ -57,7 +58,7 @@ object Target extends Applicative.Applyer[Task, Task, Result, Args]{ c.Expr[Persistent[T]]( mill.define.Cacher.wrapCached(c)( - q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree})" + q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree})" ) ) } @@ -65,7 +66,7 @@ object Target extends Applicative.Applyer[Task, Task, Result, Args]{ import c.universe._ c.Expr[Command[T]]( - q"new ${weakTypeOf[Command[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree})" + q"new ${weakTypeOf[Command[T]]}(${Applicative.impl[Task, T, Ctx](c)(t).tree})" ) } @@ -81,50 +82,50 @@ object Target extends Applicative.Applyer[Task, Task, Result, Args]{ import c.universe._ c.Expr[Target[T]]( mill.define.Cacher.wrapCached(c)( - q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Args](c)(q"mill.eval.Result.Success($t)").tree}, _root_.sourcecode.Enclosing())" + q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl0[Task, T, Ctx](c)(q"mill.eval.Result.Success($t)").tree}, _root_.sourcecode.Enclosing())" ) ) } def underlying[A](v: Task[A]) = v - def mapCtx[A, B](t: Task[A])(f: (A, Args) => Result[B]) = t.mapDest(f) + def mapCtx[A, B](t: Task[A])(f: (A, 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) def zip[A, B, C](a: Task[A], b: Task[B], c: Task[C]) = new Task[(A, B, C)]{ val inputs = Seq(a, b, c) - def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2)) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2)) } def zip[A, B, C, D](a: Task[A], b: Task[B], c: Task[C], d: Task[D]) = new Task[(A, B, C, D)]{ val inputs = Seq(a, b, c, d) - def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3)) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3)) } def zip[A, B, C, D, E](a: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E]) = new Task[(A, B, C, D, E)]{ val inputs = Seq(a, b, c, d, e) - def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4)) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4)) } def zip[A, B, C, D, E, F](a: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F]) = new Task[(A, B, C, D, E, F)]{ val inputs = Seq(a, b, c, d, e, f) - def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5)) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5)) } def zip[A, B, C, D, E, F, G](a: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F], g: Task[G]) = new Task[(A, B, C, D, E, F, G)]{ val inputs = Seq(a, b, c, d, e, f, g) - def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5), args[G](6)) + def evaluate(args: Ctx) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5), args[G](6)) } } class TargetImpl[+T](t: Task[T], enclosing: String) extends Target[T] { val inputs = Seq(t) - def evaluate(args: Args) = args[T](0) + def evaluate(args: Ctx) = args[T](0) override def toString = enclosing + "@" + Integer.toHexString(System.identityHashCode(this)) } class Command[+T](t: Task[T]) extends Task[T] { val inputs = Seq(t) - def evaluate(args: Args) = args[T](0) + def evaluate(args: Ctx) = args[T](0) override def asCommand = Some(this) } class Persistent[+T](t: Task[T]) extends Target[T] { val inputs = Seq(t) - def evaluate(args: Args) = args[T](0) + def evaluate(args: Ctx) = args[T](0) override def flushDest = false override def asPersistent = Some(this) } @@ -133,7 +134,7 @@ object Source{ } class Source(path: ammonite.ops.Path) extends Task[PathRef]{ def handle = PathRef(path) - def evaluate(args: Args) = handle + def evaluate(args: Ctx) = handle override def sideHash = handle.hashCode() val inputs = Nil } @@ -151,7 +152,7 @@ object Task { class Task0[T](t: T) extends Task[T]{ lazy val t0 = t val inputs = Nil - def evaluate(args: Args) = t0 + def evaluate(args: Ctx) = t0 } @@ -159,7 +160,7 @@ object Task { abstract class Ops[+T]{ this: Task[T] => def map[V](f: T => V) = new Task.Mapped(this, f) - def mapDest[V](f: (T, Args) => Result[V]) = new Task.MappedDest(this, f) + def mapDest[V](f: (T, Ctx) => Result[V]) = new Task.MappedDest(this, f) def filter(f: T => Boolean) = this def withFilter(f: T => Boolean) = this @@ -172,22 +173,22 @@ object Task { } class Traverse[+T](inputs0: Seq[Task[T]]) extends Task[Seq[T]]{ val inputs = inputs0 - def evaluate(args: Args) = { + def evaluate(args: 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: Args) = f(args(0)) + def evaluate(args: Ctx) = f(args(0)) val inputs = List(source) } - class MappedDest[+T, +V](source: Task[T], f: (T, Args) => Result[V]) extends Task[V]{ - def evaluate(args: Args) = f(args(0), args) + class MappedDest[+T, +V](source: Task[T], f: (T, Ctx) => Result[V]) extends Task[V]{ + def evaluate(args: 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: Args) = (args(0), args(1)) + def evaluate(args: Ctx) = (args(0), args(1)) val inputs = List(source1, source2) } diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index db74445c..b769c025 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -6,7 +6,7 @@ import mill.define.{Graph, Target, Task} import mill.discover.Mirror import mill.discover.Mirror.LabelledTarget import mill.util -import mill.util.{Args, MultiBiMap, OSet} +import mill.util.{Ctx, MultiBiMap, OSet} import scala.collection.mutable class Evaluator(workspacePath: Path, @@ -163,7 +163,11 @@ class Evaluator(workspacePath: Path, val res = if (targetInputValues.length != target.inputs.length) Result.Skipped else { - val args = new Args(targetInputValues.toArray[Any], targetDestPath.orNull) + val args = new Ctx( + targetInputValues.toArray[Any], + targetDestPath.orNull, + System.out + ) target.evaluate(args) } diff --git a/core/src/main/scala/mill/modules/Jvm.scala b/core/src/main/scala/mill/modules/Jvm.scala index 69dfcda8..74eecba4 100644 --- a/core/src/main/scala/mill/modules/Jvm.scala +++ b/core/src/main/scala/mill/modules/Jvm.scala @@ -7,7 +7,7 @@ import java.util.jar.{JarEntry, JarFile, JarOutputStream} import ammonite.ops._ import mill.define.Task import mill.eval.PathRef -import mill.util.Args +import mill.util.Ctx import scala.collection.mutable @@ -65,14 +65,14 @@ object Jvm { } - def createAssembly(outputPath: Path, - inputPaths: Seq[Path], + def createAssembly(inputPaths: Seq[Path], mainClass: Option[String] = None, - prependShellScript: String = ""): Option[Path] = { + prependShellScript: String = "") + (implicit ctx: Ctx.DestCtx): PathRef = { + val outputPath = ctx.dest rm(outputPath) - if(inputPaths.isEmpty) None - else { + if(inputPaths.nonEmpty) { mkdir(outputPath/up) val output = new FileOutputStream(outputPath.toIO) @@ -125,14 +125,14 @@ object Jvm { output.close() } - Some(outputPath) } + PathRef(outputPath) } def jarUp(roots: Task[PathRef]*) = new Task[PathRef]{ val inputs = roots - def evaluate(args: Args) = { + def evaluate(args: Ctx) = { createJar(args.dest, args.args.map(_.asInstanceOf[PathRef].path)) PathRef(args.dest) } diff --git a/core/src/main/scala/mill/util/Args.scala b/core/src/main/scala/mill/util/Args.scala deleted file mode 100644 index 4ac49df5..00000000 --- a/core/src/main/scala/mill/util/Args.scala +++ /dev/null @@ -1,9 +0,0 @@ -package mill.util - -class Args(val args: IndexedSeq[_], val dest: ammonite.ops.Path){ - def length = args.length - def apply[T](index: Int): T = { - if (index >= 0 && index < args.length) args(index).asInstanceOf[T] - else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") - } -} diff --git a/core/src/main/scala/mill/util/Ctx.scala b/core/src/main/scala/mill/util/Ctx.scala new file mode 100644 index 00000000..f583feaf --- /dev/null +++ b/core/src/main/scala/mill/util/Ctx.scala @@ -0,0 +1,34 @@ +package mill.util + +import java.io.PrintStream + +import ammonite.ops.Path +import mill.define.Applicative.ImplicitStub +import mill.util.Ctx.{ArgCtx, DestCtx, LogCtx} + +import scala.annotation.compileTimeOnly + +object Ctx{ + @compileTimeOnly("Target.ctx() can only be used with a T{...} block") + @ImplicitStub + implicit def taskCtx: Ctx = ??? + + trait DestCtx{ + def dest: Path + } + trait LogCtx{ + def log: PrintStream + } + trait ArgCtx{ + def args: IndexedSeq[_] + } +} +class Ctx(val args: IndexedSeq[_], + val dest: Path, + val log: PrintStream) extends DestCtx with LogCtx with ArgCtx{ + def length = args.length + def apply[T](index: Int): T = { + if (index >= 0 && index < args.length) args(index).asInstanceOf[T] + else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") + } +} diff --git a/core/src/test/examples/javac/build.sc b/core/src/test/examples/javac/build.sc index a54e2110..e4f7ea01 100644 --- a/core/src/test/examples/javac/build.sc +++ b/core/src/test/examples/javac/build.sc @@ -8,7 +8,7 @@ object Foo { import ammonite.ops.{ls, pwd, read} import mill.discover.Discovered - import mill.util.Args + import mill.util.Ctx val workspacePath = pwd / 'target / 'workspace / 'javac val javacSrcPath = pwd / 'src / 'test / 'examples / 'javac @@ -45,7 +45,7 @@ object Foo { val inputs = roots - def evaluate(args: Args): PathRef = { + def evaluate(args: Ctx): PathRef = { val output = new java.util.jar.JarOutputStream(new FileOutputStream(args.dest.toIO)) for { diff --git a/core/src/test/scala/mill/define/ApplicativeTests.scala b/core/src/test/scala/mill/define/ApplicativeTests.scala index 7e31b08e..7e325184 100644 --- a/core/src/test/scala/mill/define/ApplicativeTests.scala +++ b/core/src/test/scala/mill/define/ApplicativeTests.scala @@ -1,7 +1,9 @@ package mill.define +import mill.define.Applicative.ImplicitStub import utest._ +import scala.annotation.compileTimeOnly import scala.language.experimental.macros @@ -44,6 +46,9 @@ object ApplicativeTests extends TestSuite { value } } + @compileTimeOnly("Target.ctx() can only be used with a T{...} block") + @ImplicitStub + implicit def taskCtx: String = ??? val tests = Tests{ diff --git a/core/src/test/scala/mill/util/TestUtil.scala b/core/src/test/scala/mill/util/TestUtil.scala index be6bb8e9..a456b22b 100644 --- a/core/src/test/scala/mill/util/TestUtil.scala +++ b/core/src/test/scala/mill/util/TestUtil.scala @@ -21,7 +21,7 @@ object TestUtil { var counter = 0 var failure = Option.empty[String] var exception = Option.empty[Throwable] - override def evaluate(args: Args) = { + override def evaluate(args: Ctx) = { failure.map(Result.Failure) orElse exception.map(Result.Exception) getOrElse Result.Success(counter + args.args.map(_.asInstanceOf[Int]).sum) diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 3d194190..e25d13de 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -13,6 +13,7 @@ import mill.define.Task.{Module, TaskModule} import mill.eval.{PathRef, Result} import mill.modules.Jvm import mill.modules.Jvm.{createAssembly, createJar, subprocess} +import mill.util.Ctx import sbt.internal.inc._ import sbt.internal.util.{ConsoleOut, MainAppender} import sbt.util.{InterfaceUtil, LogExchange} @@ -39,10 +40,10 @@ object ScalaModule{ compilerClasspath: Seq[Path], compilerBridge: Seq[Path], scalacOptions: Seq[String], - javacOptions: Seq[String], - outputPath: Path): PathRef = { + javacOptions: Seq[String]) + (implicit ctx: Ctx): PathRef = { val compileClasspathFiles = compileClasspath.map(_.toIO).toArray - val binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".") + def grepJar(classPath: Seq[Path], s: String) = { classPath .find(_.toString.endsWith(s)) @@ -79,13 +80,13 @@ object ScalaModule{ val scalac = ZincUtil.scalaCompiler(scalaInstance, compilerBridgeJar) - mkdir(outputPath) + mkdir(ctx.dest) val ic = new sbt.internal.inc.IncrementalCompilerImpl() val logger = { - val console = ConsoleOut.systemOut - val consoleAppender = MainAppender.defaultScreen(console) + + val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut(ctx.log)) val l = LogExchange.logger("Hello") LogExchange.unbindLoggerAppenders("Hello") LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Info) :: Nil) @@ -105,9 +106,9 @@ object ScalaModule{ override def startUnit(phase: String, unitPath: String): Unit = () } - val zincFile = (outputPath/'zinc).toIO + val zincFile = (ctx.dest/'zinc).toIO val store = FileAnalysisStore.binary(zincFile) - val classesDir = (outputPath / 'classes).toIO + val classesDir = (ctx.dest / 'classes).toIO val newResult = ic.compile( ic.inputs( classpath = classesDir +: compileClasspathFiles, @@ -147,7 +148,7 @@ object ScalaModule{ ) ) - PathRef(outputPath/'classes) + PathRef(ctx.dest/'classes) } def resolveDependencies(repositories: Seq[Repository], @@ -344,18 +345,15 @@ trait ScalaModule extends Module with TaskModule{ outer => scalaCompilerClasspath().map(_.path), compilerBridgeClasspath().map(_.path), scalacOptions(), - javacOptions(), - T.ctx().dest + javacOptions() ) } def assembly = T{ - val dest = T.ctx().dest createAssembly( - dest, - (runDepClasspath().filter(_.path.ext != "pom") ++ Seq(resources(), compile())).map(_.path).filter(exists), + (runDepClasspath().filter(_.path.ext != "pom") ++ + Seq(resources(), compile())).map(_.path).filter(exists), prependShellScript = prependShellScript() ) - PathRef(dest) } def classpath = T{ Seq(resources(), compile()) } |