diff options
-rw-r--r-- | core/src/main/scala/mill/Main.scala | 13 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Applicative.scala | 15 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Task.scala | 3 | ||||
-rw-r--r-- | core/src/main/scala/mill/main/ReplApplyHandler.scala | 20 | ||||
-rw-r--r-- | core/src/test/scala/mill/define/ApplicativeTests.scala | 4 | ||||
-rw-r--r-- | readme.md | 55 |
6 files changed, 99 insertions, 11 deletions
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index 711f251e..df9e0dc6 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -118,9 +118,13 @@ object Main { s"""import $$file.^.build |import mill._ | - |@main def run(args: String*) = mill.Main(args, build, interp.watch, true/*interp.colors()*/) + |val discovered = implicitly[mill.discover.Discovered[build.type]] | - |@main def idea() = mill.scalaplugin.GenIdea(build)""".stripMargin + |@main def run(args: String*) = mill.Main(args, build, interp.watch, true)(discovered) + | + |@main def idea() = mill.scalaplugin.GenIdea(build)(discovered) + | + |implicit val replApplyHandler = new mill.main.ReplApplyHandler(build)(discovered)""".stripMargin ) import ammonite.main.Cli @@ -147,8 +151,9 @@ object Main { val runner = new ammonite.MainRunner( cliConfig.copy( - predefFile = Some(pwd / "build.sc"), - welcomeBanner = Some("") + predefFile = Some(pwd / 'out / "run.sc"), + predefCode = "import build._", + welcomeBanner = None ), System.out, System.err, System.in, System.out, System.err diff --git a/core/src/main/scala/mill/define/Applicative.scala b/core/src/main/scala/mill/define/Applicative.scala index 6d8ae3e2..686220f7 100644 --- a/core/src/main/scala/mill/define/Applicative.scala +++ b/core/src/main/scala/mill/define/Applicative.scala @@ -14,9 +14,16 @@ import scala.reflect.macros.blackbox.Context * Applier.zipMap(applyable1, applyable2){ (a1, a2, ctx) => ... a1 ... a2 ... } */ object Applicative { - trait Applyable[+T]{ + trait ApplyHandler[M[+_]]{ + def apply[T](t: M[T]): T + } + object ApplyHandler{ @compileTimeOnly("Target#apply() can only be used with a T{...} block") - def apply(): T = ??? + implicit def defaultApplyHandler[M[+_]]: ApplyHandler[M] = ??? + } + trait Applyable[M[+_], +T]{ + def self: M[T] + def apply()(implicit handler: ApplyHandler[M]): T = handler(self) } class ImplicitStub extends StaticAnnotation type Id[+T] = T @@ -64,7 +71,7 @@ object Applicative { def rec(t: Tree): Iterator[c.Tree] = Iterator(t) ++ t.children.flatMap(rec(_)) val bound = collection.mutable.Buffer.empty[(c.Tree, ValDef)] - val targetApplySym = typeOf[Applyable[_]].member(TermName("apply")) + val targetApplySym = typeOf[Applyable[Nothing, _]].member(TermName("apply")) // Derived from @olafurpg's // https://gist.github.com/olafurpg/596d62f87bf3360a29488b725fbc7608 @@ -75,7 +82,7 @@ object Applicative { c.internal.setInfo(ctxSym, weakTypeOf[Ctx]) val transformed = c.internal.typingTransform(t) { - case (t @ q"$fun.apply()", api) if t.symbol == targetApplySym => + case (t @ q"$fun.apply()($handler)", api) if t.symbol == targetApplySym => val localDefs = rec(fun).filter(_.isDef).map(_.symbol).toSet val banned = rec(t).filter(x => defs(x.symbol) && !localDefs(x.symbol)) diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index 3c170bab..8c91997b 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -7,7 +7,7 @@ import mill.util.Ctx import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context -abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ +abstract class Task[+T] extends Task.Ops[T] with Applyable[Task, T]{ /** * What other Targets does this Target depend on? */ @@ -29,6 +29,7 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ def asTarget: Option[Target[T]] = None def asCommand: Option[Command[T]] = None def asPersistent: Option[Persistent[T]] = None + def self = this } trait Target[+T] extends Task[T]{ diff --git a/core/src/main/scala/mill/main/ReplApplyHandler.scala b/core/src/main/scala/mill/main/ReplApplyHandler.scala new file mode 100644 index 00000000..fe8c13b6 --- /dev/null +++ b/core/src/main/scala/mill/main/ReplApplyHandler.scala @@ -0,0 +1,20 @@ +package mill.main + +import ammonite.ops.pwd +import mill.Main.discoverMirror +import mill.define.Applicative.ApplyHandler +import mill.define.Task +import mill.discover.Discovered +import mill.eval.Evaluator +import mill.util.{OSet, PrintLogger} + +class ReplApplyHandler[T: Discovered](obj: T) extends ApplyHandler[Task] { + override def apply[V](t: Task[V]) = discoverMirror(obj) match{ + case Left(err) => + throw new Exception("Failed discovery consistency check: " + err) + case Right(mirror) => + val log = new PrintLogger(true) + val evaluator = new Evaluator(pwd / 'out, Discovered.mapping(obj)(mirror), log) + evaluator.evaluate(OSet(t)).values.head.asInstanceOf[V] + } +} diff --git a/core/src/test/scala/mill/define/ApplicativeTests.scala b/core/src/test/scala/mill/define/ApplicativeTests.scala index 29177a03..9991b9f0 100644 --- a/core/src/test/scala/mill/define/ApplicativeTests.scala +++ b/core/src/test/scala/mill/define/ApplicativeTests.scala @@ -9,11 +9,11 @@ import scala.language.experimental.macros object ApplicativeTests extends TestSuite { implicit def optionToOpt[T](o: Option[T]): Opt[T] = new Opt(o) - class Opt[T](val o: Option[T]) extends Applicative.Applyable[T] + class Opt[T](val self: Option[T]) extends Applicative.Applyable[Option, T] object Opt extends Applicative.Applyer[Opt, Option, Applicative.Id, String]{ val injectedCtx = "helloooo" - def underlying[A](v: Opt[A]) = v.o + def underlying[A](v: Opt[A]) = v.self def apply[T](t: T): Option[T] = macro Applicative.impl[Option, T, String] type O[+T] = Option[T] @@ -44,6 +44,61 @@ Lastly, you can generate IntelliJ Scala project files using Mill via Allowing you to import a Mill project into Intellij without using SBT +### REPL + +Mill provides a build REPL, which lets you explore the build interactively and +run `Target`s from Scala code: + +```scala +lihaoyi mill$ scalaplugin/target/mill --repl +Loading... +Compiling (synthetic)/ammonite/predef/interpBridge.sc +Compiling (synthetic)/ammonite/predef/replBridge.sc +Compiling (synthetic)/ammonite/predef/DefaultPredef.sc +Compiling /Users/lihaoyi/Dropbox/Workspace/mill/build.sc +Compiling /Users/lihaoyi/Dropbox/Workspace/mill/out/run.sc +Compiling (synthetic)/ammonite/predef/CodePredef.sc + +@ build +res0: build.type = build + +@ build. +!= Core ScalaPlugin bridges getClass isInstanceOf |> +== MillModule asInstanceOf equals hashCode toString +@ build.Core +res1: Core.type = ammonite.predef.$up.build$Core$@5600c124 + +@ Core +res2: Core.type = ammonite.predef.$up.build$Core$@5600c124 + +@ Core.scalaV +scalaVersion +@ Core.scalaVersion +res3: define.Target[String] = ammonite.predef.^.build.MillModule#scalaVersion@4b7d16 + +@ Core.scalaVersion() +Running Core.scalaVersion +res4: String = "2.12.4" + +@ Core.ivyDeps() +Running Core.ivyDeps +res5: Seq[scalaplugin.Dep] = List( + Scala( + Dependency( + Module("com.lihaoyi", "sourcecode", Map()), + "0.1.4", +... + +@ Core.ivyDeps().foreach(println) +Running Core.ivyDeps +Scala(Dependency(com.lihaoyi:sourcecode,0.1.4,,Set(),Attributes(,),false,true)) +Scala(Dependency(com.lihaoyi:pprint,0.5.3,,Set(),Attributes(,),false,true)) +Point(Dependency(com.lihaoyi:ammonite,1.0.3,,Set(),Attributes(,),false,true)) +Scala(Dependency(com.typesafe.play:play-json,2.6.6,,Set(),Attributes(,),false,true)) +Scala(Dependency(org.scala-sbt:zinc,1.0.5,,Set(),Attributes(,),false,true)) +Java(Dependency(org.scala-sbt:test-interface,1.0,,Set(),Attributes(,),false,true)) +``` + ### build.sc Into a `build.sc` file you can define separate `Module`s (e.g. `ScalaModule`). |