From 7238d7340744a5eda74acb6970c2cbf7bedea0e7 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 07:52:31 -0800 Subject: Cross building acyclic now works, using a locally compiled cross-versioned compiler-bridge.jar. For now just hardcode the Scala versions we want to support as part of the build; we can figure out how to do the runtime download&compile thing later --- .../src/main/scala/mill/scalaplugin/ScalaModule.scala | 14 ++++++++++++-- .../src/test/scala/mill/scalaplugin/AcyclicTests.scala | 5 +++-- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'scalaplugin') diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 6b67b708..27aefb12 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -4,6 +4,7 @@ package scalaplugin import java.io.File import java.net.URLClassLoader import java.util.Optional +import java.util.concurrent.Callable import ammonite.ops._ import coursier.{Cache, Fetch, MavenRepository, Repository, Resolution} @@ -17,6 +18,8 @@ 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 @@ -49,7 +52,11 @@ object ScalaModule{ val outerClassLoader = getClass.getClassLoader val compilerJars = compilerClasspath.toArray.map(_.toIO) - val compilerBridgeJar = grepJar(compilerBridge, s"compiler-bridge_$binaryScalaVersion-1.0.5.jar") + + val compilerBridgeJar = new java.io.File( + s"bridge/${scalaVersion.replace('.', '_')}/target/scala-$binaryScalaVersion/mill-bridge_$scalaVersion-0.1-SNAPSHOT.jar" + ) + val zincClassLoader = new URLClassLoader(compilerJars.map(_.toURI.toURL), null){ override def loadClass(name: String): Class[_] = { Option(findLoadedClass(name)) orElse @@ -115,7 +122,8 @@ object ScalaModule{ lookup, skip = false, zincFile, - compilerCache, + new FreshCompilerCache, +// compilerCache, IncOptions.of(), reporter, Some(ignoreProgress), @@ -129,6 +137,8 @@ object ScalaModule{ logger = logger ) + zincClassLoader.close() + store.set( AnalysisContents.create( newResult.analysis(), diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala index 7ba8b267..124c7a0c 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" @@ -46,7 +46,8 @@ object AcyclicTests extends TestSuite{ 'scala210 - check("2.10.6") 'scala211 - check("2.11.8") - 'scala212 - check("2.12.4") + 'scala2123 - check("2.12.3") + 'scala2124 - check("2.12.4") val allBinaryVersions = Seq("2.10", "2.11", "2.12") def check(scalaVersion: String) = { -- cgit v1.2.3 From a9ed3b67cc1d0b0a755159013b28766f436e866a Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 10:17:25 -0800 Subject: Flesh out `bridges` pre-compilation in Mill build, getting the cross-minor-version `AcyclicTests` running using the `mill` test runner Fixed `Discovered` to only pick up public `Target`s, which makes it skip things like the `super$compile` of an overriden `compile` target. Split up `sources` and `allSources` TBD how to properly switch the `compilerBridgeJar` between the different output paths of SBT's compile-dir and Mill's compile-dir, and eventually to a maven-central artifact too --- build.sbt | 9 +----- build.sc | 35 ++++++++++++++++++++++ core/src/main/scala/mill/Main.scala | 19 ++++-------- core/src/main/scala/mill/discover/Discovered.scala | 3 +- core/src/main/scala/mill/discover/Mirror.scala | 9 ++++++ .../main/scala/mill/scalaplugin/ScalaModule.scala | 10 ++++--- 6 files changed, 59 insertions(+), 26 deletions(-) (limited to 'scalaplugin') diff --git a/build.sbt b/build.sbt index c1d8719b..3002eeb7 100644 --- a/build.sbt +++ b/build.sbt @@ -54,15 +54,8 @@ def bridge(bridgeVersion: String) = Project( 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") - if (java.nio.file.Files.exists(curlDest)) { - java.nio.file.Files.walk(curlDest) - .iterator() - .asScala - .toSeq - .reverse - .foreach(java.nio.file.Files.delete) - } + Seq("rm", "-rf", curlDest.toString).! java.nio.file.Files.createDirectories(curlDest) Seq("curl", "-L", "-o", curlDest.resolve("bridge.jar").toString, url).! 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..db7a6c1a 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -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 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/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 27aefb12..3d194190 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -34,7 +34,7 @@ object ScalaModule{ val compilerCache = new CompilerCache(2) def compileScala(scalaVersion: String, - sources: Path, + sources: Seq[Path], compileClasspath: Seq[Path], compilerClasspath: Seq[Path], compilerBridge: Seq[Path], @@ -54,7 +54,8 @@ object ScalaModule{ val compilerJars = compilerClasspath.toArray.map(_.toIO) val compilerBridgeJar = new java.io.File( - s"bridge/${scalaVersion.replace('.', '_')}/target/scala-$binaryScalaVersion/mill-bridge_$scalaVersion-0.1-SNAPSHOT.jar" +// s"bridge/${scalaVersion.replace('.', '_')}/target/scala-$binaryScalaVersion/mill-bridge_$scalaVersion-0.1-SNAPSHOT.jar" + s"out/bridges/$scalaVersion/compile/classes" ) val zincClassLoader = new URLClassLoader(compilerJars.map(_.toURI.toURL), null){ @@ -110,7 +111,7 @@ object ScalaModule{ 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, @@ -334,10 +335,11 @@ 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), -- cgit v1.2.3 From e9f3c71f670f93c95f0ae47860e663b768885067 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 21:35:54 -0800 Subject: Update test case --- scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scalaplugin') diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala index 03b9b285..b1a3b7a3 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala @@ -114,7 +114,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: ") -- cgit v1.2.3 From 422d41498d43ad9b437b2d4460f61849e78bb6fa Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 21:55:01 -0800 Subject: - 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 --- core/src/main/scala/mill/define/Applicative.scala | 13 +++--- core/src/main/scala/mill/define/Task.scala | 49 +++++++++++----------- core/src/main/scala/mill/eval/Evaluator.scala | 8 +++- core/src/main/scala/mill/modules/Jvm.scala | 16 +++---- core/src/main/scala/mill/util/Args.scala | 9 ---- core/src/main/scala/mill/util/Ctx.scala | 34 +++++++++++++++ core/src/test/examples/javac/build.sc | 4 +- .../test/scala/mill/define/ApplicativeTests.scala | 5 +++ core/src/test/scala/mill/util/TestUtil.scala | 2 +- .../main/scala/mill/scalaplugin/ScalaModule.scala | 28 ++++++------- 10 files changed, 100 insertions(+), 68 deletions(-) delete mode 100644 core/src/main/scala/mill/util/Args.scala create mode 100644 core/src/main/scala/mill/util/Ctx.scala (limited to 'scalaplugin') 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()) } -- cgit v1.2.3 From 52f5a07a2b2b3f1885e83d09414aa3da385f4419 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 21:59:13 -0800 Subject: Make more stuff use the implicit `T.ctx()` --- core/src/main/scala/mill/modules/Jvm.scala | 9 +++++---- core/src/test/scala/mill/eval/JavaCompileJarTests.scala | 13 +++++++------ .../src/main/scala/mill/scalaplugin/ScalaModule.scala | 4 +--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'scalaplugin') diff --git a/core/src/main/scala/mill/modules/Jvm.scala b/core/src/main/scala/mill/modules/Jvm.scala index 74eecba4..a2277e36 100644 --- a/core/src/main/scala/mill/modules/Jvm.scala +++ b/core/src/main/scala/mill/modules/Jvm.scala @@ -31,10 +31,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,8 +61,8 @@ object Jvm { jar.close() } - Some(outputPath) } + PathRef(outputPath) } diff --git a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala index 72e8c858..6c32f9b8 100644 --- a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala +++ b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala @@ -5,16 +5,17 @@ import ammonite.ops._ import mill.define.{Target, Task} import mill.discover.Discovered import mill.modules.Jvm.jarUp -import mill.{T, Module} +import mill.util.Ctx.DestCtx +import mill.{Module, T} import mill.util.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,7 +38,7 @@ 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 classFiles = T{ compileAll(allSources()) } def jar = T{ jarUp(resourceRoot, classFiles) } def run(mainClsName: String) = T.command{ diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index e25d13de..eb9026ba 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -358,9 +358,7 @@ trait ScalaModule extends Module with TaskModule{ outer => def classpath = T{ Seq(resources(), compile()) } def jar = T{ - val dest = T.ctx().dest - createJar(dest, Seq(resources(), compile()).map(_.path).filter(exists)) - PathRef(dest) + createJar(Seq(resources(), compile()).map(_.path).filter(exists)) } def run(mainClass: String) = T.command{ -- cgit v1.2.3 From 9aed4601a04a48b3192d1871ff0ebb98fa352726 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 22:28:31 -0800 Subject: Standardize on a `mill.util.Logger` class --- core/src/main/scala/mill/Main.scala | 15 +++-------- core/src/main/scala/mill/eval/Evaluator.scala | 14 ++++++----- core/src/main/scala/mill/modules/Jvm.scala | 8 ------ core/src/main/scala/mill/util/Ctx.scala | 4 +-- core/src/main/scala/mill/util/Logger.scala | 29 ++++++++++++++++++++++ core/src/test/scala/mill/define/CacherTests.scala | 4 +-- .../src/test/scala/mill/eval/EvaluationTests.scala | 4 +-- core/src/test/scala/mill/eval/FailureTests.scala | 4 +-- .../test/scala/mill/eval/JavaCompileJarTests.scala | 10 ++++---- .../src/main/scala/mill/scalaplugin/GenIdea.scala | 4 +-- .../main/scala/mill/scalaplugin/ScalaModule.scala | 6 +++-- .../main/scala/mill/scalaplugin/TestRunner.scala | 21 ++++++++++------ .../scala/mill/scalaplugin/TestEvaluator.scala | 7 +++--- 13 files changed, 76 insertions(+), 54 deletions(-) create mode 100644 core/src/main/scala/mill/util/Logger.scala (limited to 'scalaplugin') diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index db7a6c1a..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 @@ -151,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 @@ -163,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 () @@ -231,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/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index b769c025..619b1521 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.{Ctx, 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) { @@ -166,7 +168,7 @@ class Evaluator(workspacePath: Path, val args = new Ctx( targetInputValues.toArray[Any], targetDestPath.orNull, - System.out + log ) target.evaluate(args) } diff --git a/core/src/main/scala/mill/modules/Jvm.scala b/core/src/main/scala/mill/modules/Jvm.scala index a2277e36..a0f586c3 100644 --- a/core/src/main/scala/mill/modules/Jvm.scala +++ b/core/src/main/scala/mill/modules/Jvm.scala @@ -130,12 +130,4 @@ object Jvm { PathRef(outputPath) } - def jarUp(roots: Task[PathRef]*) = new Task[PathRef]{ - - val inputs = roots - 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/Ctx.scala b/core/src/main/scala/mill/util/Ctx.scala index f583feaf..7a0a5694 100644 --- a/core/src/main/scala/mill/util/Ctx.scala +++ b/core/src/main/scala/mill/util/Ctx.scala @@ -17,7 +17,7 @@ object Ctx{ def dest: Path } trait LogCtx{ - def log: PrintStream + def log: Logger } trait ArgCtx{ def args: IndexedSeq[_] @@ -25,7 +25,7 @@ object Ctx{ } class Ctx(val args: IndexedSeq[_], val dest: Path, - val log: PrintStream) extends DestCtx with LogCtx with ArgCtx{ + 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] 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..d998a601 --- /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{ + val outputStream = new 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/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 6c32f9b8..e0a43c6e 100644 --- a/core/src/test/scala/mill/eval/JavaCompileJarTests.scala +++ b/core/src/test/scala/mill/eval/JavaCompileJarTests.scala @@ -4,10 +4,10 @@ import ammonite.ops.ImplicitWd._ import ammonite.ops._ import mill.define.{Target, Task} import mill.discover.Discovered -import mill.modules.Jvm.jarUp +import mill.modules.Jvm import mill.util.Ctx.DestCtx import mill.{Module, T} -import mill.util.OSet +import mill.util.{DummyLogger, OSet} import utest._ object JavaCompileJarTests extends TestSuite{ @@ -39,7 +39,7 @@ object JavaCompileJarTests extends TestSuite{ def resourceRoot = T.source{ resourceRootPath } def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) } def classFiles = T{ compileAll(allSources()) } - def jar = T{ jarUp(resourceRoot, classFiles) } + def jar = T{ Jvm.createJar(Seq(resourceRoot().path, classFiles().path)) } def run(mainClsName: String) = T.command{ %%('java, "-cp", classFiles().path, mainClsName) @@ -50,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){ @@ -67,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/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 eb9026ba..292c41a6 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -1,7 +1,7 @@ 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 @@ -86,7 +86,9 @@ object ScalaModule{ val logger = { - val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut(ctx.log)) + 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) 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/TestEvaluator.scala b/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala index e54480c9..49c245e4 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} 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, DummyLogger) val evaluated = evaluator.evaluate(OSet(t)) if (evaluated.failing.keyCount == 0) { -- cgit v1.2.3 From 395a856d91b318957963ab24011862653452a101 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 4 Dec 2017 23:30:11 -0800 Subject: Avoid `inheritIO` in `Jvm.subprocess`, and instead feed it into the proper `log.outputStream` --- core/src/main/scala/mill/eval/Evaluator.scala | 15 ++++++++- core/src/main/scala/mill/modules/Jvm.scala | 37 ++++++++++++++++++++-- core/src/main/scala/mill/util/Logger.scala | 2 +- .../main/scala/mill/scalaplugin/ScalaModule.scala | 6 ++-- 4 files changed, 53 insertions(+), 7 deletions(-) (limited to 'scalaplugin') diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index 619b1521..96c868e9 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -170,7 +170,20 @@ class Evaluator(workspacePath: Path, targetDestPath.orNull, log ) - target.evaluate(args) + 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 a0f586c3..43382b8d 100644 --- a/core/src/main/scala/mill/modules/Jvm.scala +++ b/core/src/main/scala/mill/modules/Jvm.scala @@ -9,6 +9,7 @@ import mill.define.Task import mill.eval.PathRef 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]) = { diff --git a/core/src/main/scala/mill/util/Logger.scala b/core/src/main/scala/mill/util/Logger.scala index d998a601..ba8aa95f 100644 --- a/core/src/main/scala/mill/util/Logger.scala +++ b/core/src/main/scala/mill/util/Logger.scala @@ -12,7 +12,7 @@ trait Logger{ } object DummyLogger extends Logger{ - val outputStream = new PrintStream(new OutputStream { + object outputStream extends PrintStream(new OutputStream { def write(b: Int) = () }) def info(s: String) = () diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 292c41a6..472b8c03 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -53,10 +53,10 @@ object ScalaModule{ val outerClassLoader = getClass.getClassLoader val compilerJars = compilerClasspath.toArray.map(_.toIO) - + 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" + s"bridge/${scalaVersion.replace('.', '_')}/target/scala-$binaryScalaVersion/mill-bridge_$scalaVersion-0.1-SNAPSHOT.jar" +// s"out/bridges/$scalaVersion/compile/classes" ) val zincClassLoader = new URLClassLoader(compilerJars.map(_.toURI.toURL), null){ -- cgit v1.2.3