summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/mill/Main.scala13
-rw-r--r--core/src/main/scala/mill/define/Applicative.scala15
-rw-r--r--core/src/main/scala/mill/define/Task.scala3
-rw-r--r--core/src/main/scala/mill/main/ReplApplyHandler.scala20
-rw-r--r--core/src/test/scala/mill/define/ApplicativeTests.scala4
-rw-r--r--readme.md55
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]
diff --git a/readme.md b/readme.md
index f76bf6ea..feef9e03 100644
--- a/readme.md
+++ b/readme.md
@@ -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`).