summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridge.sc4
-rw-r--r--build.sbt63
-rwxr-xr-xbuild.sc35
-rw-r--r--core/src/main/scala/mill/Main.scala34
-rw-r--r--core/src/main/scala/mill/define/Applicative.scala13
-rw-r--r--core/src/main/scala/mill/define/Task.scala49
-rw-r--r--core/src/main/scala/mill/discover/Discovered.scala3
-rw-r--r--core/src/main/scala/mill/discover/Mirror.scala9
-rw-r--r--core/src/main/scala/mill/eval/Evaluator.scala33
-rw-r--r--core/src/main/scala/mill/modules/Jvm.scala68
-rw-r--r--core/src/main/scala/mill/util/Args.scala9
-rw-r--r--core/src/main/scala/mill/util/Ctx.scala34
-rw-r--r--core/src/main/scala/mill/util/Logger.scala29
-rw-r--r--core/src/test/examples/javac/build.sc4
-rw-r--r--core/src/test/scala/mill/define/ApplicativeTests.scala5
-rw-r--r--core/src/test/scala/mill/define/CacherTests.scala4
-rw-r--r--core/src/test/scala/mill/eval/EvaluationTests.scala4
-rw-r--r--core/src/test/scala/mill/eval/FailureTests.scala4
-rw-r--r--core/src/test/scala/mill/eval/JavaCompileJarTests.scala23
-rw-r--r--core/src/test/scala/mill/util/TestUtil.scala2
-rw-r--r--scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala4
-rw-r--r--scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala93
-rw-r--r--scalaplugin/src/main/scala/mill/scalaplugin/TestRunner.scala21
-rw-r--r--scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala50
-rw-r--r--scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala2
-rw-r--r--scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala7
26 files changed, 410 insertions, 196 deletions
diff --git a/bridge.sc b/bridge.sc
new file mode 100644
index 00000000..bdfbe26a
--- /dev/null
+++ b/bridge.sc
@@ -0,0 +1,4 @@
+import ammonite.ops._
+val zippedBytes = scalaj.http.Http()
+ .asBytes
+ .body \ No newline at end of file
diff --git a/build.sbt b/build.sbt
index 3031ffef..3002eeb7 100644
--- a/build.sbt
+++ b/build.sbt
@@ -35,6 +35,54 @@ val sharedSettings = Seq(
)
+def bridge(bridgeVersion: String) = Project(
+ id = "bridge" + bridgeVersion.replace('.', '_'),
+ base = file("bridge/" + bridgeVersion.replace('.', '_')),
+ settings = Seq(
+ organization := "com.lihaoyi",
+ scalaVersion := bridgeVersion,
+ name := "mill-bridge",
+ crossVersion := CrossVersion.full,
+ libraryDependencies ++= Seq(
+ "org.scala-lang" % "scala-compiler" % scalaVersion.value,
+ "org.scala-sbt" % "compiler-interface" % "1.0.5"
+ ),
+ (sourceGenerators in Compile) += Def.task{
+ import sys.process._
+ import collection.JavaConverters._
+ val v = scalaBinaryVersion.value
+ val url =
+ s"http://repo1.maven.org/maven2/org/scala-sbt/compiler-bridge_$v/1.0.5/compiler-bridge_$v-1.0.5-sources.jar"
+ val curlDest = java.nio.file.Paths.get(target.value.toString, "sources")
+
+ Seq("rm", "-rf", curlDest.toString).!
+ java.nio.file.Files.createDirectories(curlDest)
+
+ Seq("curl", "-L", "-o", curlDest.resolve("bridge.jar").toString, url).!
+ Seq("unzip", curlDest.resolve("bridge.jar").toString, "-d", curlDest.toString).!
+
+ val sources = java.nio.file.Files.walk(curlDest)
+ .iterator
+ .asScala
+ .filter(_.toString.endsWith(".scala"))
+ .map(_.toFile)
+ .toSeq
+
+ sources
+ }.taskValue
+ )
+)
+lazy val bridge2_10_6 = bridge("2.10.6")
+lazy val bridge2_11_8 = bridge("2.11.8")
+//lazy val bridge2_11_9 = bridge("2.11.9")
+//lazy val bridge2_11_10 = bridge("2.11.10")
+lazy val bridge2_11_11 = bridge("2.11.11")
+//lazy val bridge2_12_0 = bridge("2.12.0")
+//lazy val bridge2_12_1 = bridge("2.12.1")
+//lazy val bridge2_12_2 = bridge("2.12.2")
+lazy val bridge2_12_3 = bridge("2.12.3")
+lazy val bridge2_12_4 = bridge("2.12.4")
+
lazy val core = project
.settings(
sharedSettings,
@@ -53,5 +101,18 @@ lazy val scalaplugin = project
.dependsOn(core % "compile->compile;test->test")
.settings(
sharedSettings,
- name := "mill-scalaplugin"
+ name := "mill-scalaplugin",
+ (compile in Test) := {
+ val a = (packageBin in (bridge2_10_6, Compile)).value
+ val b = (packageBin in (bridge2_11_8, Compile)).value
+// val c = (packageBin in (bridge2_11_9, Compile)).value
+// val d = (packageBin in (bridge2_11_10, Compile)).value
+ val e = (packageBin in (bridge2_11_11, Compile)).value
+// val f = (packageBin in (bridge2_12_0, Compile)).value
+// val g = (packageBin in (bridge2_12_1, Compile)).value
+// val h = (packageBin in (bridge2_12_2, Compile)).value
+ val i = (packageBin in (bridge2_12_3, Compile)).value
+ val j = (packageBin in (bridge2_12_4, Compile)).value
+ (compile in Test).value
+ }
)
diff --git a/build.sc b/build.sc
index 6eb3de2b..7b261892 100755
--- a/build.sc
+++ b/build.sc
@@ -48,10 +48,45 @@ object Core extends MillModule {
}
}
+
+val bridges = for{
+ crossVersion <- mill.define.Cross("2.10.6", "2.11.8", "2.11.11", "2.12.3", "2.12.4")
+} yield new ScalaModule{
+ def basePath = pwd / 'bridge
+ def scalaVersion = crossVersion
+ override def allSources = T{
+
+ val v = crossVersion.split('.').dropRight(1).mkString(".")
+ val url =
+ s"http://repo1.maven.org/maven2/org/scala-sbt/compiler-bridge_$v/1.0.5/compiler-bridge_$v-1.0.5-sources.jar"
+ val curlDest = T.ctx().dest
+ implicit val pwd = curlDest
+ mkdir(curlDest)
+ rm(curlDest/"bridge.jar")
+
+ %("curl", "-L", "-o", curlDest / "bridge.jar", url)
+ %("unzip", curlDest / "bridge.jar" , "-d", curlDest / 'classes)
+
+
+ Seq(PathRef(curlDest / 'classes))
+ }
+ override def ivyDeps = Seq(
+ Dep.Java("org.scala-lang", "scala-compiler", crossVersion),
+ Dep.Java("org.scala-sbt", "compiler-interface", "1.0.5")
+ )
+}
object ScalaPlugin extends MillModule {
override def projectDeps = Seq(Core)
def basePath = pwd / 'scalaplugin
+ override def compile = T.persistent[mill.eval.PathRef]{
+ bridges("2.10.6").compile()
+ bridges("2.11.8").compile()
+ bridges("2.11.11").compile()
+ bridges("2.12.3").compile()
+ bridges("2.12.4").compile()
+ super.compile()
+ }
override def prependShellScript =
"#!/usr/bin/env sh\n" +
"""exec java $JAVA_OPTS -cp "$0" mill.Main "$@" """
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala
index 1dbae4c3..24cd7ed1 100644
--- a/core/src/main/scala/mill/Main.scala
+++ b/core/src/main/scala/mill/Main.scala
@@ -7,7 +7,7 @@ import ammonite.util.{Colors, Res}
import mill.define.Task
import mill.discover._
import mill.eval.{Evaluator, Result}
-import mill.util.OSet
+import mill.util.{Logger, OSet, PrintLogger}
import ammonite.main.Scripts.pathScoptRead
import ammonite.repl.Repl
import mill.define.Task.TaskModule
@@ -26,14 +26,7 @@ object Main {
query.parse(input)
}
- def renderSelector(selector: List[Mirror.Segment]) = {
- val Mirror.Segment.Label(head) :: rest = selector
- val stringSegments = rest.map{
- case Mirror.Segment.Label(s) => "." + s
- case Mirror.Segment.Cross(vs) => "[" + vs.mkString(",") + "]"
- }
- head + stringSegments.mkString
- }
+
def parseArgs(selectorString: String): Either[String, List[Mirror.Segment]] = {
import fastparse.all.Parsed
@@ -81,7 +74,7 @@ object Main {
def command = invokeCommand(hierarchy, last)
command orElse target orElse runDefault.headOption.flatten match{
- case None => Left("Cannot resolve task " + renderSelector(
+ case None => Left("Cannot resolve task " + Mirror.renderSelector(
(Mirror.Segment.Label(last) :: revSelectorsSoFar).reverse)
)
case Some(either) => either
@@ -96,7 +89,7 @@ object Main {
case (label, child) if label == singleLabel => child
} match{
case Some(child) => resolve(tail, child, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
- case None => Left("Cannot resolve module " + renderSelector(newRevSelectorsSoFar.reverse))
+ case None => Left("Cannot resolve module " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
}
case Mirror.Segment.Cross(cross) =>
@@ -105,7 +98,7 @@ object Main {
if (crossOptions.contains(cross)){
resolve(tail, childMirror, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
}else{
- Left("Cannot resolve cross " + renderSelector(newRevSelectorsSoFar.reverse))
+ Left("Cannot resolve cross " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
}
@@ -119,7 +112,7 @@ object Main {
val discovered = implicitly[Discovered[T]]
val consistencyErrors = Discovered.consistencyCheck(obj, discovered)
if (consistencyErrors.nonEmpty) {
- Left(s"Failed Discovered.consistencyCheck: $consistencyErrors")
+ Left(s"Failed Discovered.consistencyCheck: ${consistencyErrors.map(Mirror.renderSelector)}")
} else {
Right(discovered)
}
@@ -138,7 +131,7 @@ object Main {
(for((k, fs) <- evaluated.failing.items()) yield {
val ks = k match{
case Left(t) => t.toString
- case Right(t) => renderSelector(t.segments.toList)
+ case Right(t) => Mirror.renderSelector(t.segments.toList)
}
val fss = fs.map{
case Result.Exception(t) => t.toString
@@ -158,7 +151,7 @@ object Main {
watch: Path => Unit,
coloredOutput: Boolean): Int = {
- val log = new Logger(coloredOutput)
+ val log = new PrintLogger(coloredOutput)
val Seq(selectorString, rest @_*) = args
@@ -170,7 +163,7 @@ object Main {
case _ => Nil
}
target <- resolve(sel, disc.mirror, obj, rest, crossSelectors, Nil)
- evaluator = new Evaluator(pwd / 'out, Discovered.mapping(obj)(disc), log.info)
+ evaluator = new Evaluator(pwd / 'out, Discovered.mapping(obj)(disc), log)
_ <- evaluate(evaluator, target, watch).toLeft(())
} yield ()
@@ -238,17 +231,10 @@ object Main {
}
}
-class Logger(coloredOutput: Boolean){
- val colors =
- if(coloredOutput) Colors.Default
- else Colors.BlackWhite
- def info(s: String) = System.err.println(colors.info()(s))
- def error(s: String) = System.err.println(colors.error()(s))
-}
class Main(config: Main.Config){
val coloredOutput = config.colored.getOrElse(ammonite.Main.isInteractive())
- val log = new Logger(coloredOutput)
+ val log = new PrintLogger(coloredOutput)
def watchAndWait(watched: Seq[(Path, Long)]) = {
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/discover/Discovered.scala b/core/src/main/scala/mill/discover/Discovered.scala
index aef5f14f..753ac141 100644
--- a/core/src/main/scala/mill/discover/Discovered.scala
+++ b/core/src/main/scala/mill/discover/Discovered.scala
@@ -47,7 +47,8 @@ object Discovered {
if m.isMethod &&
m.typeSignature.paramLists.isEmpty &&
m.typeSignature.resultType <:< c.weakTypeOf[Target[_]] &&
- !m.name.toString.contains(' ')
+ !m.name.toString.contains(' ') &&
+ m.isPublic
} yield {
val x = Ident(TermName(c.freshName()))
val t = q"""mill.discover.Mirror.makeTargetPoint(
diff --git a/core/src/main/scala/mill/discover/Mirror.scala b/core/src/main/scala/mill/discover/Mirror.scala
index 4dfeaa25..6293e599 100644
--- a/core/src/main/scala/mill/discover/Mirror.scala
+++ b/core/src/main/scala/mill/discover/Mirror.scala
@@ -25,6 +25,15 @@ case class Mirror[-T, V](node: (T, List[List[Any]]) => V,
}
object Mirror{
+ def renderSelector(selector: Seq[Mirror.Segment]) = {
+ val Mirror.Segment.Label(head) :: rest = selector.toList
+ val stringSegments = rest.map{
+ case Mirror.Segment.Label(s) => "." + s
+ case Mirror.Segment.Cross(vs) => "[" + vs.mkString(",") + "]"
+ }
+ head + stringSegments.mkString
+ }
+
sealed trait Segment
object Segment{
case class Label(value: String) extends Segment
diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala
index db74445c..96c868e9 100644
--- a/core/src/main/scala/mill/eval/Evaluator.scala
+++ b/core/src/main/scala/mill/eval/Evaluator.scala
@@ -1,17 +1,20 @@
package mill.eval
+import java.io.PrintStream
+
import ammonite.ops._
import ammonite.runtime.SpecialClassLoader
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._
+
import scala.collection.mutable
class Evaluator(workspacePath: Path,
labeling: Map[Target[_], LabelledTarget[_]],
- log: String => Unit){
+ log: Logger){
def evaluate(goals: OSet[Task[_]]): Evaluator.Results = {
mkdir(workspacePath)
@@ -133,8 +136,7 @@ class Evaluator(workspacePath: Path,
def evaluateGroup(group: OSet[Task[_]],
results: collection.Map[Task[_], Result[Any]],
targetDestPath: Option[Path],
- maybeTargetLabel: Option[String]
- ) = {
+ maybeTargetLabel: Option[String]) = {
val newEvaluated = mutable.Buffer.empty[Task[_]]
@@ -150,7 +152,7 @@ class Evaluator(workspacePath: Path,
val logRun = inputResults.forall(_.isInstanceOf[Result.Success[_]])
- if(logRun) { log("Running " + targetLabel) }
+ if(logRun) { log.info("Running " + targetLabel) }
}
for (target <- nonEvaluatedTargets) {
@@ -163,8 +165,25 @@ class Evaluator(workspacePath: Path,
val res =
if (targetInputValues.length != target.inputs.length) Result.Skipped
else {
- val args = new Args(targetInputValues.toArray[Any], targetDestPath.orNull)
- target.evaluate(args)
+ val args = new Ctx(
+ targetInputValues.toArray[Any],
+ targetDestPath.orNull,
+ log
+ )
+ val out = System.out
+ val err = System.err
+ try{
+ System.setErr(log.outputStream)
+ System.setOut(log.outputStream)
+ Console.withOut(log.outputStream){
+ Console.withErr(log.outputStream){
+ target.evaluate(args)
+ }
+ }
+ }finally{
+ System.setErr(err)
+ System.setOut(out)
+ }
}
newResults(target) = res
diff --git a/core/src/main/scala/mill/modules/Jvm.scala b/core/src/main/scala/mill/modules/Jvm.scala
index 69dfcda8..43382b8d 100644
--- a/core/src/main/scala/mill/modules/Jvm.scala
+++ b/core/src/main/scala/mill/modules/Jvm.scala
@@ -7,8 +7,9 @@ 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.annotation.tailrec
import scala.collection.mutable
@@ -17,8 +18,40 @@ object Jvm {
def subprocess(mainClass: String,
classPath: Seq[Path],
options: Seq[String] = Seq.empty,
- workingDir: Path = ammonite.ops.pwd) = {
- %("java", "-cp", classPath.mkString(":"), mainClass, options)(workingDir)
+ workingDir: Path = ammonite.ops.pwd)
+ (implicit ctx: Ctx) = {
+ val proc =
+ new java.lang.ProcessBuilder()
+ .directory(workingDir.toIO)
+ .command(Vector("java", "-cp", classPath.mkString(":"), mainClass) ++ options:_*)
+ .redirectOutput(ProcessBuilder.Redirect.PIPE)
+ .redirectError(ProcessBuilder.Redirect.PIPE)
+ .start()
+
+ val stdout = proc.getInputStream
+ val stderr = proc.getErrorStream
+ val sources = Seq(stdout , stderr)
+ while(
+ // Process.isAlive doesn't exist on JDK 7 =/
+ util.Try(proc.exitValue).isFailure ||
+ stdout.available() > 0 ||
+ stderr.available() > 0
+ ){
+ var readSomething = false
+ for (std <- sources){
+ while (std.available() > 0){
+ readSomething = true
+ val array = new Array[Byte](std.available())
+ val actuallyRead = std.read(array)
+ ctx.log.outputStream.write(array, 0, actuallyRead)
+ }
+ }
+ // if we did not read anything sleep briefly to avoid spinning
+ if(!readSomething)
+ Thread.sleep(2)
+ }
+
+ if (proc.exitValue() != 0) throw new InteractiveShelloutException()
}
private def createManifest(mainClass: Option[String]) = {
@@ -31,10 +64,11 @@ object Jvm {
m
}
- def createJar(outputPath: Path, inputPaths: Seq[Path], mainClass: Option[String] = None): Option[Path] = {
+ def createJar(inputPaths: Seq[Path], mainClass: Option[String] = None)
+ (implicit ctx: Ctx.DestCtx): PathRef = {
+ val outputPath = ctx.dest
rm(outputPath)
- if(inputPaths.isEmpty) None
- else {
+ if(inputPaths.nonEmpty) {
mkdir(outputPath/up)
val jar = new JarOutputStream(
@@ -60,19 +94,19 @@ object Jvm {
jar.close()
}
- Some(outputPath)
}
+ PathRef(outputPath)
}
- 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,16 +159,8 @@ object Jvm {
output.close()
}
- Some(outputPath)
}
+ PathRef(outputPath)
}
- def jarUp(roots: Task[PathRef]*) = new Task[PathRef]{
-
- val inputs = roots
- def evaluate(args: Args) = {
- 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..7a0a5694
--- /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: Logger
+ }
+ trait ArgCtx{
+ def args: IndexedSeq[_]
+ }
+}
+class Ctx(val args: IndexedSeq[_],
+ val dest: Path,
+ val log: Logger) 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/main/scala/mill/util/Logger.scala b/core/src/main/scala/mill/util/Logger.scala
new file mode 100644
index 00000000..ba8aa95f
--- /dev/null
+++ b/core/src/main/scala/mill/util/Logger.scala
@@ -0,0 +1,29 @@
+package mill.util
+
+import java.io.{OutputStream, PrintStream}
+
+import ammonite.util.Colors
+
+
+trait Logger{
+ val outputStream: PrintStream
+ def info(s: String): Unit
+ def error(s: String): Unit
+}
+
+object DummyLogger extends Logger{
+ object outputStream extends PrintStream(new OutputStream {
+ def write(b: Int) = ()
+ })
+ def info(s: String) = ()
+ def error(s: String) = ()
+}
+class PrintLogger(coloredOutput: Boolean) extends Logger{
+ val outputStream = System.err
+ val colors =
+ if(coloredOutput) Colors.Default
+ else Colors.BlackWhite
+
+ def info(s: String) = System.err.println(colors.info()(s))
+ def error(s: String) = System.err.println(colors.error()(s))
+} \ No newline at end of file
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/define/CacherTests.scala b/core/src/test/scala/mill/define/CacherTests.scala
index bb86ae65..bacfa598 100644
--- a/core/src/test/scala/mill/define/CacherTests.scala
+++ b/core/src/test/scala/mill/define/CacherTests.scala
@@ -2,7 +2,7 @@ package mill.define
import mill.discover.Discovered
import mill.eval.Evaluator
-import mill.util.OSet
+import mill.util.{DummyLogger, OSet}
import mill.T
import utest._
import utest.framework.TestPath
@@ -27,7 +27,7 @@ object CacherTests extends TestSuite{
def eval[T: Discovered, V](base: T, v: Task[V])(implicit tp: TestPath) = {
val workspace = ammonite.ops.pwd / 'target / 'workspace / tp.value
- val evaluator = new Evaluator(workspace, Discovered.mapping(base), _ => ())
+ val evaluator = new Evaluator(workspace, Discovered.mapping(base), DummyLogger)
evaluator.evaluate(OSet(v)).values(0)
}
diff --git a/core/src/test/scala/mill/eval/EvaluationTests.scala b/core/src/test/scala/mill/eval/EvaluationTests.scala
index d3c1861f..3b136ba0 100644
--- a/core/src/test/scala/mill/eval/EvaluationTests.scala
+++ b/core/src/test/scala/mill/eval/EvaluationTests.scala
@@ -5,7 +5,7 @@ import mill.util.TestUtil.{Test, test}
import mill.define.{Graph, Target, Task}
import mill.{Module, T}
import mill.discover.Discovered
-import mill.util.{OSet, TestGraphs, TestUtil}
+import mill.util.{DummyLogger, OSet, TestGraphs, TestUtil}
import utest._
import utest.framework.TestPath
@@ -14,7 +14,7 @@ object EvaluationTests extends TestSuite{
val workspace = ammonite.ops.pwd / 'target / 'workspace / tp.value
ammonite.ops.rm(ammonite.ops.Path(workspace, ammonite.ops.pwd))
// Make sure data is persisted even if we re-create the evaluator each time
- def evaluator = new Evaluator(workspace, Discovered.mapping(base), _ => ())
+ def evaluator = new Evaluator(workspace, Discovered.mapping(base), DummyLogger)
def apply(target: Task[_], expValue: Any,
expEvaled: OSet[Task[_]],
diff --git a/core/src/test/scala/mill/eval/FailureTests.scala b/core/src/test/scala/mill/eval/FailureTests.scala
index 6977334d..2279d931 100644
--- a/core/src/test/scala/mill/eval/FailureTests.scala
+++ b/core/src/test/scala/mill/eval/FailureTests.scala
@@ -2,7 +2,7 @@ package mill.eval
import mill.define.Target
import mill.discover.Discovered
-import mill.util.OSet
+import mill.util.{DummyLogger, OSet}
import utest._
import utest.framework.TestPath
@@ -17,7 +17,7 @@ object FailureTests extends TestSuite{
def check[T: Discovered](base: T)
(target: T => Target[_], expectedFailCount: Int, expectedRawValues: Seq[Result[_]])
(implicit tp: TestPath) = {
- val evaluator = new Evaluator(workspace, Discovered.mapping(base), _ => ())
+ val evaluator = new Evaluator(workspace, Discovered.mapping(base), DummyLogger)
val res = evaluator.evaluate(OSet(target(base)))
assert(
res.rawValues == expectedRawValues,
diff --git a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala
index 72e8c858..e0a43c6e 100644
--- a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala
+++ b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala
@@ -4,17 +4,18 @@ import ammonite.ops.ImplicitWd._
import ammonite.ops._
import mill.define.{Target, Task}
import mill.discover.Discovered
-import mill.modules.Jvm.jarUp
-import mill.{T, Module}
-import mill.util.OSet
+import mill.modules.Jvm
+import mill.util.Ctx.DestCtx
+import mill.{Module, T}
+import mill.util.{DummyLogger, OSet}
import utest._
object JavaCompileJarTests extends TestSuite{
- def compileAll(dest: Path, sources: Seq[PathRef]) = {
- mkdir(dest)
+ def compileAll(sources: Seq[PathRef])(implicit ctx: DestCtx) = {
+ mkdir(ctx.dest)
import ammonite.ops._
- %("javac", sources.map(_.path.toString()), "-d", dest)(wd = dest)
- PathRef(dest)
+ %("javac", sources.map(_.path.toString()), "-d", ctx.dest)(wd = ctx.dest)
+ PathRef(ctx.dest)
}
val tests = Tests{
@@ -37,8 +38,8 @@ object JavaCompileJarTests extends TestSuite{
def sourceRoot = T.source{ sourceRootPath }
def resourceRoot = T.source{ resourceRootPath }
def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) }
- def classFiles = T{ compileAll(T.ctx().dest, allSources()) }
- def jar = T{ jarUp(resourceRoot, classFiles) }
+ def classFiles = T{ compileAll(allSources()) }
+ def jar = T{ Jvm.createJar(Seq(resourceRoot().path, classFiles().path)) }
def run(mainClsName: String) = T.command{
%%('java, "-cp", classFiles().path, mainClsName)
@@ -49,7 +50,7 @@ object JavaCompileJarTests extends TestSuite{
val mapping = Discovered.mapping(Build)
def eval[T](t: Task[T]): Either[Result.Failing, (T, Int)] = {
- val evaluator = new Evaluator(workspacePath, mapping, _ => ())
+ val evaluator = new Evaluator(workspacePath, mapping, DummyLogger)
val evaluated = evaluator.evaluate(OSet(t))
if (evaluated.failing.keyCount == 0){
@@ -66,7 +67,7 @@ object JavaCompileJarTests extends TestSuite{
}
def check(targets: OSet[Task[_]], expected: OSet[Task[_]]) = {
- val evaluator = new Evaluator(workspacePath, mapping, _ => ())
+ val evaluator = new Evaluator(workspacePath, mapping, DummyLogger)
val evaluated = evaluator.evaluate(targets)
.evaluated
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/GenIdea.scala b/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala
index 87a42d04..4ccb71cd 100644
--- a/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala
+++ b/scalaplugin/src/main/scala/mill/scalaplugin/GenIdea.scala
@@ -4,7 +4,7 @@ import ammonite.ops._
import mill.discover.Mirror.Segment
import mill.discover.{Discovered, Mirror}
import mill.eval.{Evaluator, PathRef}
-import mill.util.OSet
+import mill.util.{OSet, PrintLogger}
object GenIdea {
@@ -22,7 +22,7 @@ object GenIdea {
val discovered = implicitly[Discovered[T]]
val mapping = Discovered.mapping(obj)(discovered)
val workspacePath = pwd / 'out
- val evaluator = new Evaluator(workspacePath, mapping, _ => ())
+ val evaluator = new Evaluator(workspacePath, mapping, new PrintLogger(true))
val modules = Mirror
.traverse(obj, discovered.mirror){ (h, p) =>
diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala
index c9cf4a49..001f5844 100644
--- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala
+++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala
@@ -1,9 +1,10 @@
package mill
package scalaplugin
-import java.io.File
+import java.io.{File, PrintStream, PrintWriter, Writer}
import java.net.URLClassLoader
import java.util.Optional
+import java.util.concurrent.Callable
import ammonite.ops._
import coursier.{Cache, Fetch, MavenRepository, Repository, Resolution}
@@ -12,11 +13,14 @@ 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}
import xsbti.compile.{CompilerCache => _, FileAnalysisStore => _, ScalaInstance => _, _}
import mill.util.JsonFormatters._
+import sbt.librarymanagement.DependencyResolution
+import xsbti.GlobalLock
@@ -29,17 +33,17 @@ object ScalaModule{
Locate.definesClass(classpathEntry)
}
- val compilerCache = new CompilerCache(2)
+ var scalaInstanceCache = Option.empty[(Long, ScalaInstance)]
def compileScala(scalaVersion: String,
- sources: Path,
+ sources: Seq[Path],
compileClasspath: Seq[Path],
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))
@@ -47,37 +51,44 @@ object ScalaModule{
.toIO
}
- val outerClassLoader = getClass.getClassLoader
+
val compilerJars = compilerClasspath.toArray.map(_.toIO)
- val compilerBridgeJar = grepJar(compilerBridge, s"compiler-bridge_$binaryScalaVersion-1.0.5.jar")
- val zincClassLoader = new URLClassLoader(compilerJars.map(_.toURI.toURL), null){
- override def loadClass(name: String): Class[_] = {
- Option(findLoadedClass(name)) orElse
- (try Some(findClass(name)) catch {case e: ClassNotFoundException => None}) getOrElse {
- // Try to limit `outerClassLoader` to only stuff from the compiler-bridge jar
- if (name.startsWith("xsbt.")) outerClassLoader.loadClass(name)
- else super.loadClass(name)
- }
- }
- }
- val scalaInstance = new ScalaInstance(
- version = scalaVersion,
- loader = zincClassLoader,
- libraryJar = grepJar(compilerClasspath, s"scala-library-$scalaVersion.jar"),
- compilerJar = grepJar(compilerClasspath, s"scala-compiler-$scalaVersion.jar"),
- allJars = compilerJars,
- explicitActual = None
+ def binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".")
+ val compilerBridgeJar = new java.io.File(
+ s"bridge/${scalaVersion.replace('.', '_')}/target/scala-$binaryScalaVersion/mill-bridge_$scalaVersion-0.1-SNAPSHOT.jar"
+// s"out/bridges/$scalaVersion/compile/classes"
)
+ val classloaderSig = compilerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum
+ println("classloaderSig: " + classloaderSig)
+ val scalaInstance = scalaInstanceCache match{
+ case Some((k, v)) if k == classloaderSig => v
+ case _ =>
+ val scalaInstance = new ScalaInstance(
+ version = scalaVersion,
+ loader = new URLClassLoader(compilerJars.map(_.toURI.toURL), null),
+ libraryJar = grepJar(compilerClasspath, s"scala-library-$scalaVersion.jar"),
+ compilerJar = grepJar(compilerClasspath, s"scala-compiler-$scalaVersion.jar"),
+ allJars = compilerJars,
+ explicitActual = None
+ )
+ scalaInstanceCache = Some((classloaderSig, scalaInstance))
+ scalaInstance
+ }
+
+
+
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.outputStream
+ ))
val l = LogExchange.logger("Hello")
LogExchange.unbindLoggerAppenders("Hello")
LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Info) :: Nil)
@@ -97,13 +108,13 @@ 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,
- sources = ls.rec(sources).filter(_.isFile).map(_.toIO).toArray,
+ sources = sources.flatMap(ls.rec).filter(x => x.isFile && x.ext == "scala").map(_.toIO).toArray,
classesDirectory = classesDir,
scalacOptions = scalacOptions.toArray,
javacOptions = javacOptions.toArray,
@@ -115,7 +126,7 @@ object ScalaModule{
lookup,
skip = false,
zincFile,
- compilerCache,
+ new FreshCompilerCache,
IncOptions.of(),
reporter,
Some(ignoreProgress),
@@ -136,7 +147,7 @@ object ScalaModule{
)
)
- PathRef(outputPath/'classes)
+ PathRef(ctx.dest/'classes)
}
def resolveDependencies(repositories: Seq[Repository],
@@ -325,33 +336,29 @@ trait ScalaModule extends Module with TaskModule{ outer =>
def sources = T.source{ basePath / 'src }
def resources = T.source{ basePath / 'resources }
+ def allSources = T{ Seq(sources()) }
def compile = T.persistent{
compileScala(
scalaVersion(),
- sources().path,
+ allSources().map(_.path),
compileDepClasspath().map(_.path),
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()) }
def jar = T{
- val dest = T.ctx().dest
- createJar(dest, Seq(resources(), compile()).map(_.path).filter(exists), mainClass())
- PathRef(dest)
+ createJar(Seq(resources(), compile()).map(_.path).filter(exists), mainClass())
}
def run() = T.command{
diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/TestRunner.scala b/scalaplugin/src/main/scala/mill/scalaplugin/TestRunner.scala
index 03292b68..43e15974 100644
--- a/scalaplugin/src/main/scala/mill/scalaplugin/TestRunner.scala
+++ b/scalaplugin/src/main/scala/mill/scalaplugin/TestRunner.scala
@@ -6,6 +6,8 @@ import java.net.URLClassLoader
import java.util.zip.ZipInputStream
import ammonite.ops.{Path, ls, pwd}
+import mill.util.Ctx.LogCtx
+import mill.util.PrintLogger
import sbt.testing._
import scala.collection.mutable
@@ -43,14 +45,17 @@ object TestRunner {
entireClasspath = args(1).split(" ").map(Path(_)),
testClassfilePath = args(2).split(" ").map(Path(_)),
args = args(3) match{ case "" => Nil case x => x.split(" ").toList }
- )
+ )(new LogCtx {
+ def log = new PrintLogger(true)
+ })
val outputPath = args(4)
ammonite.ops.write(Path(outputPath), upickle.default.write(result))
}
def apply(frameworkName: String,
entireClasspath: Seq[Path],
testClassfilePath: Seq[Path],
- args: Seq[String]): Option[String] = {
+ args: Seq[String])
+ (implicit ctx: LogCtx): Option[String] = {
val outerClassLoader = getClass.getClassLoader
val cl = new URLClassLoader(
entireClasspath.map(_.toIO.toURI.toURL).toArray,
@@ -86,17 +91,17 @@ object TestRunner {
},
Array(
new Logger {
- def debug(msg: String) = println(msg)
+ def debug(msg: String) = ctx.log.info(msg)
- def error(msg: String) = println(msg)
+ def error(msg: String) = ctx.log.error(msg)
def ansiCodesSupported() = true
- def warn(msg: String) = println(msg)
+ def warn(msg: String) = ctx.log.info(msg)
- def trace(t: Throwable) = println(t)
+ def trace(t: Throwable) = t.printStackTrace(ctx.log.outputStream)
- def info(msg: String) = println(msg)
+ def info(msg: String) = ctx.log.info(msg)
})
)
}
@@ -107,7 +112,7 @@ object TestRunner {
val grouped = events.groupBy(x => x).mapValues(_.length).filter(_._2 != 0).toList.sorted
grouped.map{case (k, v) => k + ": " + v}.mkString(",")
}
- println(msg)
+ ctx.log.info(msg)
if (events.count(Set(Status.Error, Status.Failure)) == 0) None
else Some(msg)
}
diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala
index 7ba8b267..856e9508 100644
--- a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala
+++ b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala
@@ -9,7 +9,7 @@ import utest._
import mill.util.JsonFormatters._
object AcyclicBuild{
val acyclic =
- for(crossVersion <- Cross("2.10.6", "2.11.8", "2.12.4"))
+ for(crossVersion <- Cross("2.10.6", "2.11.8", "2.12.3", "2.12.4"))
yield new ScalaModule{outer =>
def basePath = AcyclicTests.workspacePath
def organization = "com.lihaoyi"
@@ -44,12 +44,13 @@ object AcyclicTests extends TestSuite{
val packageScala = workspacePath/'src/'main/'scala/'acyclic/"package.scala"
- 'scala210 - check("2.10.6")
- 'scala211 - check("2.11.8")
- 'scala212 - check("2.12.4")
+ 'scala210 - check("2.10.6", full = false)
+ 'scala211 - check("2.11.8", full = false)
+ 'scala2123 - check("2.12.3", full = true)
+ 'scala2124 - check("2.12.4", full = false)
val allBinaryVersions = Seq("2.10", "2.11", "2.12")
- def check(scalaVersion: String) = {
+ def check(scalaVersion: String, full: Boolean) = {
// Dependencies are right; make sure every dependency is of the correct
// binary Scala version, except for the compiler-bridge which is of the
// same version as the host classpath.
@@ -74,30 +75,31 @@ object AcyclicTests extends TestSuite{
val Right((_, evalCount2)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
assert(evalCount2 == 0)
- write.append(packageScala, "\n")
+ if (full){
+ // Caches are invalidated if code is changed
+ write.append(packageScala, "\n")
+ val Right((_, evalCount3)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
+ assert(evalCount3 > 0)
- // Caches are invalidated if code is changed
- val Right((_, evalCount3)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
- assert(evalCount3 > 0)
+ // Compilation can fail on broken code, and work when fixed
+ write.append(packageScala, "\n}}")
+ val Left(Result.Exception(ex)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
+ assert(ex.isInstanceOf[sbt.internal.inc.CompileFailed])
- // Compilation can fail on broken code, and work when fixed
- write.append(packageScala, "\n}}")
- val Left(Result.Exception(ex)) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
- assert(ex.isInstanceOf[sbt.internal.inc.CompileFailed])
+ write.write(packageScala, read(packageScala).dropRight(3))
+ val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
- write.write(packageScala, read(packageScala).dropRight(3))
- val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).compile)
+ // Tests compile & run
+ val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
- // Tests compile & run
- val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
+ // Tests can be broken
+ write.append(packageScala, "\n}}")
+ val Left(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
- // Tests can be broken
- write.append(packageScala, "\n}}")
- val Left(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
-
- // Tests can be fixed
- write.write(packageScala, read(packageScala).dropRight(3))
- val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
+ // Tests can be fixed
+ write.write(packageScala, read(packageScala).dropRight(3))
+ val Right(_) = eval(AcyclicBuild.acyclic(scalaVersion).test.forkTest())
+ }
}
}
diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala
index c2f5a7b8..916dd7ca 100644
--- a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala
+++ b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala
@@ -119,7 +119,7 @@ object HelloWorldTests extends TestSuite {
val Right((_, incCompileCount)) =
eval(HelloWorld.compile, helloWorldMapping)
- assert(incCompileCount == 1)
+ assert(incCompileCount > 0, incCompileCount < freshCount)
}
'failOnError - {
write.append(mainObject, "val x: ")
diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala b/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala
index e54480c9..242b4e8b 100644
--- a/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala
+++ b/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala
@@ -4,20 +4,19 @@ import ammonite.ops.Path
import mill.define.{Target, Task}
import mill.discover.Mirror
import mill.eval.{Evaluator, Result}
-import mill.util.OSet
+import mill.util.{DummyLogger, OSet, PrintLogger}
object TestEvaluator {
- private val noopLogger: String => Unit = _ => ()
def resolveDestPaths(workspacePath: Path)(t: Mirror.LabelledTarget[_]): (Path, Path) = {
- new Evaluator(workspacePath, Map.empty, noopLogger).resolveDestPaths(t)
+ new Evaluator(workspacePath, Map.empty, DummyLogger).resolveDestPaths(t)
}
def eval[T](
mapping: Map[Target[_], Mirror.LabelledTarget[_]],
workspacePath: Path)(t: Task[T]): Either[Result.Failing, (T, Int)] = {
- val evaluator = new Evaluator(workspacePath, mapping, noopLogger)
+ val evaluator = new Evaluator(workspacePath, mapping, new PrintLogger(true))
val evaluated = evaluator.evaluate(OSet(t))
if (evaluated.failing.keyCount == 0) {