From 24f60cc893f0ca8e37992a2cf48bad20c923a2d8 Mon Sep 17 00:00:00 2001 From: rockjam <5min4eq.unity@gmail.com> Date: Fri, 1 Dec 2017 23:27:18 +0300 Subject: pass compile analysis of projectDeps to zinc, fixes #29 --- build.sc | 13 ++-- core/src/main/scala/mill/define/Applicative.scala | 6 +- core/src/main/scala/mill/define/Task.scala | 5 ++ .../test/scala/mill/define/ApplicativeTests.scala | 3 + .../main/scala/mill/scalaplugin/ScalaModule.scala | 80 ++++++++++++++-------- .../test/scala/mill/scalaplugin/AcyclicTests.scala | 2 +- .../scala/mill/scalaplugin/HelloWorldTests.scala | 4 +- 7 files changed, 70 insertions(+), 43 deletions(-) diff --git a/build.sc b/build.sc index 5d581364..f58c160e 100755 --- a/build.sc +++ b/build.sc @@ -82,16 +82,13 @@ object ScalaPlugin extends MillModule { override def projectDeps = Seq(Core) def basePath = pwd / 'scalaplugin - override def compile = T.persistent[mill.eval.PathRef]{ - super.compile() - } override def testArgs = T{ val mapping = Map( - "MILL_COMPILER_BRIDGE_2_10_6" -> bridges("2.10.6").compile().path, - "MILL_COMPILER_BRIDGE_2_11_8" -> bridges("2.11.8").compile().path, - "MILL_COMPILER_BRIDGE_2_11_11" -> bridges("2.11.11").compile().path, - "MILL_COMPILER_BRIDGE_2_12_3" -> bridges("2.12.3").compile().path, - "MILL_COMPILER_BRIDGE_2_12_4" -> bridges("2.12.4").compile().path, + "MILL_COMPILER_BRIDGE_2_10_6" -> bridges("2.10.6").compile().classes.path, + "MILL_COMPILER_BRIDGE_2_11_8" -> bridges("2.11.8").compile().classes.path, + "MILL_COMPILER_BRIDGE_2_11_11" -> bridges("2.11.11").compile().classes.path, + "MILL_COMPILER_BRIDGE_2_12_3" -> bridges("2.12.3").compile().classes.path, + "MILL_COMPILER_BRIDGE_2_12_4" -> bridges("2.12.4").compile().classes.path, ) for((k, v) <- mapping.toSeq) yield s"-D$k=$v" } diff --git a/core/src/main/scala/mill/define/Applicative.scala b/core/src/main/scala/mill/define/Applicative.scala index f8193742..38a98015 100644 --- a/core/src/main/scala/mill/define/Applicative.scala +++ b/core/src/main/scala/mill/define/Applicative.scala @@ -37,8 +37,8 @@ object Applicative { (cb: (A, B, C, D, E, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e)){case ((a, b, c, d, e), x) => cb(a, b, c, d, e, x)} def zipMap[A, B, C, D, E, F, R](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F]) (cb: (A, B, C, D, E, F, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f)){case ((a, b, c, d, e, f), x) => cb(a, b, c, d, e, f, x)} - def zipMap[A, B, C, D, E, F, G, R](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G]) - (cb: (A, B, C, D, E, F, G, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f, g)){case ((a, b, c, d, e, f, g), x) => cb(a, b, c, d, e, f, g, x)} + def zipMap[A, B, C, D, E, F, G, H, R](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H]) + (cb: (A, B, C, D, E, F, G, H, Ctx) => Z[R]) = mapCtx(zip(a, b, c, d, e, f, g, h)){case ((a, b, c, d, e, f, g, h), x) => cb(a, b, c, d, e, f, g, h, x)} def zip(): T[Unit] def zip[A](a: T[A]): T[Tuple1[A]] def zip[A, B](a: T[A], b: T[B]): T[(A, B)] @@ -46,7 +46,7 @@ object Applicative { def zip[A, B, C, D](a: T[A], b: T[B], c: T[C], d: T[D]): T[(A, B, C, D)] def zip[A, B, C, D, E](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E]): T[(A, B, C, D, E)] def zip[A, B, C, D, E, F](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F]): T[(A, B, C, D, E, F)] - def zip[A, B, C, D, E, F, G](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G]): T[(A, B, C, D, E, F, G)] + def zip[A, B, C, D, E, F, G, H](a: T[A], b: T[B], c: T[C], d: T[D], e: T[E], f: T[F], g: T[G], h: T[H]): T[(A, B, C, D, E, F, G, H)] } def impl[M[_], T: c.WeakTypeTag, Ctx: c.WeakTypeTag](c: Context) diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index 451cc1d4..8b811bdc 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -112,6 +112,11 @@ object Target extends Applicative.Applyer[Task, Task, Result, Ctx]{ val inputs = Seq(a, b, c, d, e, f, g) 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)) } + + def zip[A, B, C, D, E, F, G, H](a: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F], g: Task[G], h: Task[H]) = new Task[(A, B, C, D, E, F, G, H)]{ + val inputs = Seq(a, b, c, d, e, f, g, h) + 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), args[H](7)) + } } class TargetImpl[+T](t: Task[T], enclosing: String) extends Target[T] { val inputs = Seq(t) diff --git a/core/src/test/scala/mill/define/ApplicativeTests.scala b/core/src/test/scala/mill/define/ApplicativeTests.scala index 7e325184..14b566b3 100644 --- a/core/src/test/scala/mill/define/ApplicativeTests.scala +++ b/core/src/test/scala/mill/define/ApplicativeTests.scala @@ -38,6 +38,9 @@ object ApplicativeTests extends TestSuite { def zip[A, B, C, D, E, F, G](a: O[A], b: O[B], c: O[C], d: O[D], e: O[E], f: O[F], g: O[G]) = { for(a <- a; b <- b; c <- c; d <- d; e <- e; f <- f; g <- g) yield (a, b, c, d, e, f, g) } + def zip[A, B, C, D, E, F, G, H](a: O[A], b: O[B], c: O[C], d: O[D], e: O[E], f: O[F], g: O[G], h: O[H]) = { + for(a <- a; b <- b; c <- c; d <- d; e <- e; f <- f; g <- g; h <- h) yield (a, b, c, d, e, f, g, h) + } } class Counter{ var value = 0 diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 0686f131..4de2f416 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -1,10 +1,9 @@ package mill package scalaplugin -import java.io.{File, PrintStream, PrintWriter, Writer} +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} @@ -18,11 +17,13 @@ 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 +object CompilationResult { + implicit val jsonFormatter: upickle.default.ReadWriter[CompilationResult] = upickle.default.macroRW +} +// analysisFile is represented by Path, so we won't break caches after file changes +case class CompilationResult(analysisFile: Path, classes: PathRef) object ScalaModule{ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { @@ -41,8 +42,9 @@ object ScalaModule{ compilerClasspath: Seq[Path], compilerBridge: Seq[Path], scalacOptions: Seq[String], - javacOptions: Seq[String]) - (implicit ctx: Ctx): PathRef = { + javacOptions: Seq[String], + upstreamCompileOutput: Seq[CompilationResult]) + (implicit ctx: Ctx): CompilationResult = { val compileClasspathFiles = compileClasspath.map(_.toIO).toArray def grepJar(classPath: Seq[Path], s: String) = { @@ -89,17 +91,32 @@ object ScalaModule{ l } - val lookup = MockedLookup(Function.const(Optional.empty[CompileAnalysis])) + def analysisMap(f: File): Optional[CompileAnalysis] = { + if (f.isFile) { + Optional.empty[CompileAnalysis] + } else { + upstreamCompileOutput.collectFirst { + case CompilationResult(zincPath, classFiles) if classFiles.path.toNIO == f.toPath => + FileAnalysisStore.binary(zincPath.toIO).get().map[CompileAnalysis](_.getAnalysis) + }.getOrElse(Optional.empty[CompileAnalysis]) + } + } + + val lookup = MockedLookup(analysisMap) + + val zincFile = ctx.dest / 'zinc + val classesDir = ctx.dest / 'classes - val zincFile = (ctx.dest/'zinc).toIO - val store = FileAnalysisStore.binary(zincFile) - val classesDir = (ctx.dest / 'classes).toIO + val zincIOFile = zincFile.toIO + val classesIODir = classesDir.toIO + + val store = FileAnalysisStore.binary(zincIOFile) val newResult = ic.compile( ic.inputs( - classpath = classesDir +: compileClasspathFiles, + classpath = classesIODir +: compileClasspathFiles, sources = sources.flatMap(ls.rec).filter(x => x.isFile && x.ext == "scala").map(_.toIO).toArray, - classesDirectory = classesDir, + classesDirectory = classesIODir, scalacOptions = scalacOptions.toArray, javacOptions = javacOptions.toArray, maxErrors = 10, @@ -114,7 +131,7 @@ object ScalaModule{ setup = ic.setup( lookup, skip = false, - zincFile, + zincIOFile, new FreshCompilerCache, IncOptions.of(), new ManagedLoggedReporter(10, logger), @@ -136,7 +153,7 @@ object ScalaModule{ ) ) - PathRef(ctx.dest/'classes) + CompilationResult(zincFile, PathRef(classesDir)) } def resolveDependencies(repositories: Seq[Repository], @@ -194,8 +211,8 @@ trait TestScalaModule extends ScalaModule with TaskModule { jvmOptions = forkArgs(), options = Seq( testFramework(), - (runDepClasspath().map(_.path) :+ compile().path).mkString(" "), - Seq(compile().path).mkString(" "), + (runDepClasspath().map(_.path) :+ compile().classes.path).mkString(" "), + Seq(compile().classes.path).mkString(" "), args.mkString(" "), outputPath.toString ), @@ -209,8 +226,8 @@ trait TestScalaModule extends ScalaModule with TaskModule { def test(args: String*) = T.command{ TestRunner( testFramework(), - runDepClasspath().map(_.path) :+ compile().path, - Seq(compile().path), + runDepClasspath().map(_.path) :+ compile().classes.path, + Seq(compile().classes.path), args ) match{ case Some(errMsg) => Result.Failure(errMsg) @@ -248,7 +265,7 @@ trait ScalaModule extends Module with TaskModule{ outer => def upstreamRunClasspath = T{ Task.traverse( for (p <- projectDeps) - yield T.task(p.runDepClasspath() ++ Seq(p.compile())) + yield T.task(p.runDepClasspath() ++ Seq(p.compile().classes)) ) } @@ -258,7 +275,8 @@ trait ScalaModule extends Module with TaskModule{ outer => def upstreamCompileDepSources = T{ Task.traverse(projectDeps.map(_.externalCompileDepSources)) } - def upstreamCompileOutputClasspath = T{ + + def upstreamCompileOutput = T{ Task.traverse(projectDeps.map(_.compile)) } @@ -288,7 +306,7 @@ trait ScalaModule extends Module with TaskModule{ outer => * might be less than the runtime classpath */ def compileDepClasspath: T[Seq[PathRef]] = T{ - upstreamCompileOutputClasspath() ++ + upstreamCompileOutput().map(_.classes) ++ depClasspath() ++ externalCompileDepClasspath() } @@ -327,7 +345,7 @@ 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{ + def compile: T[CompilationResult] = T.persistent{ compileScala( scalaVersion(), allSources().map(_.path), @@ -335,35 +353,37 @@ trait ScalaModule extends Module with TaskModule{ outer => scalaCompilerClasspath().map(_.path), compilerBridgeClasspath().map(_.path), scalacOptions(), - javacOptions() + javacOptions(), + upstreamCompileOutput() ) } def assembly = T{ createAssembly( (runDepClasspath().filter(_.path.ext != "pom") ++ - Seq(resources(), compile())).map(_.path).filter(exists), + Seq(resources(), compile().classes)).map(_.path).filter(exists), prependShellScript = prependShellScript() ) } - def classpath = T{ Seq(resources(), compile()) } + def classpath = T{ Seq(resources(), compile().classes) } + def jar = T{ - createJar(Seq(resources(), compile()).map(_.path).filter(exists), mainClass()) + createJar(Seq(resources(), compile().classes).map(_.path).filter(exists), mainClass()) } def run() = T.command{ val main = mainClass().getOrElse(throw new RuntimeException("No mainClass provided!")) - subprocess(main, runDepClasspath().map(_.path) :+ compile().path) + subprocess(main, runDepClasspath().map(_.path) :+ compile().classes.path) } def runMain(mainClass: String) = T.command{ - subprocess(mainClass, runDepClasspath().map(_.path) :+ compile().path) + subprocess(mainClass, runDepClasspath().map(_.path) :+ compile().classes.path) } def console() = T.command{ subprocess( mainClass = "scala.tools.nsc.MainGenericRunner", - classPath = externalCompileDepClasspath().map(_.path) :+ compile().path, + classPath = externalCompileDepClasspath().map(_.path) :+ compile().classes.path, options = Seq("-usejavacp") ) } diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala index 856e9508..7c10cb6b 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala @@ -63,7 +63,7 @@ object AcyclicTests extends TestSuite{ // We can compile val Right((pathRef, evalCount)) = eval(AcyclicBuild.acyclic(scalaVersion).compile) - val outputPath = pathRef.path + val outputPath = pathRef.classes.path val outputFiles = ls.rec(outputPath) assert( evalCount > 0, diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala index 916dd7ca..7f672f12 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala @@ -95,11 +95,13 @@ object HelloWorldTests extends TestSuite { val Right((result, evalCount)) = eval(HelloWorld.compile, helloWorldMapping) - val outPath = result.path + val outPath = result.classes.path + val analysisFile = result.analysisFile val outputFiles = ls.rec(outPath) val expectedClassfiles = compileClassfiles(outputPath / 'compile / 'classes) assert( outPath == outputPath / 'compile / 'classes, + exists(analysisFile), outputFiles.nonEmpty, outputFiles.forall(expectedClassfiles.contains), evalCount > 0 -- cgit v1.2.3