diff options
-rw-r--r-- | core/src/main/scala/mill/Main.scala | 2 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Cacher.scala | 11 | ||||
-rw-r--r-- | core/src/main/scala/mill/define/Task.scala | 34 | ||||
-rw-r--r-- | core/src/main/scala/mill/eval/Evaluator.scala | 3 | ||||
-rw-r--r-- | core/src/test/scala/mill/JavaCompileJarTests.scala | 6 | ||||
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala | 152 |
6 files changed, 138 insertions, 70 deletions
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala index f4042ae8..c4df0ee5 100644 --- a/core/src/main/scala/mill/Main.scala +++ b/core/src/main/scala/mill/Main.scala @@ -12,6 +12,7 @@ import ammonite.main.Scripts.pathScoptRead import ammonite.repl.Repl object Main { + def apply[T: Discovered](args: Seq[String], obj: T, watch: Path => Unit) = { val Seq(selectorString, rest @_*) = args @@ -131,6 +132,7 @@ class Main(config: Main.Config){ case Res.Failure(msg) => printError(msg) false + case Res.Exception(ex, s) => printError( Repl.showException(ex, fansi.Color.Red, fansi.Attr.Reset, fansi.Color.Green) diff --git a/core/src/main/scala/mill/define/Cacher.scala b/core/src/main/scala/mill/define/Cacher.scala index 224704ce..09200203 100644 --- a/core/src/main/scala/mill/define/Cacher.scala +++ b/core/src/main/scala/mill/define/Cacher.scala @@ -4,12 +4,12 @@ import scala.collection.mutable import scala.reflect.macros.blackbox.Context -trait Cacher[C[_], V[_]]{ - private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, V[_]] - def wrapCached[T](in: C[T], enclosing: String): V[T] +trait Cacher[C[_]]{ + private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, C[_]] + def wrapCached[T](in: C[T], enclosing: String): C[T] protected[this] def cachedTarget[T](t: => C[T]) - (implicit c: sourcecode.Enclosing): V[T] = synchronized{ - cacherLazyMap.getOrElseUpdate(c, wrapCached(t, c.value)).asInstanceOf[V[T]] + (implicit c: sourcecode.Enclosing): C[T] = synchronized{ + cacherLazyMap.getOrElseUpdate(c, wrapCached(t, c.value)).asInstanceOf[C[T]] } } object Cacher{ @@ -17,6 +17,7 @@ object Cacher{ c.Expr[M[T]](wrapCached(c)(t.tree)) } def wrapCached(c: Context)(t: c.Tree) = { + import c.universe._ val owner = c.internal.enclosingOwner val ownerIsCacherClass = diff --git a/core/src/main/scala/mill/define/Task.scala b/core/src/main/scala/mill/define/Task.scala index 0e2591c6..70f93d35 100644 --- a/core/src/main/scala/mill/define/Task.scala +++ b/core/src/main/scala/mill/define/Task.scala @@ -24,6 +24,8 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ * anyway? */ def sideHash: Int = 0 + + def flushDest: Boolean = true } trait Target[+T] extends Task[T] @@ -31,7 +33,7 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ implicit def apply[T](t: T): Target[T] = macro targetImpl[T] - def apply[T](t: Task[T]): Target[T] = macro Cacher.impl0[Task, T] + def apply[T](t: Task[T]): Target[T] = macro targetTaskImpl[T] def command[T](t: T): Command[T] = macro commandImpl[T] @@ -42,6 +44,16 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ def task[T](t: T): Task[T] = macro Applicative.impl[Task, T, Args] def task[T](t: Task[T]): Task[T] = t + def persistent[T](t: T): Target[T] = macro persistentImpl[T] + def persistentImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Persistent[T]] = { + import c.universe._ + + c.Expr[Persistent[T]]( + mill.define.Cacher.wrapCached(c)( + q"new ${weakTypeOf[Persistent[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree})" + ) + ) + } def commandImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Command[T]] = { import c.universe._ @@ -50,10 +62,19 @@ object Target extends Applicative.Applyer[Task, Task, Args]{ ) } + def targetTaskImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]]): c.Expr[Target[T]] = { + import c.universe._ + c.Expr[Target[T]]( + mill.define.Cacher.wrapCached(c)( + q"new ${weakTypeOf[TargetImpl[T]]}($t, _root_.sourcecode.Enclosing())" + ) + ) + } def targetImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = { + import c.universe._ c.Expr[Target[T]]( mill.define.Cacher.wrapCached(c)( - Applicative.impl[Task, T, Args](c)(t).tree + q"new ${weakTypeOf[TargetImpl[T]]}(${Applicative.impl[Task, T, Args](c)(t).tree}, _root_.sourcecode.Enclosing())" ) ) } @@ -93,6 +114,11 @@ class Command[+T](t: Task[T]) extends Task[T] { val inputs = Seq(t) def evaluate(args: Args) = args[T](0) } +class Persistent[+T](t: Task[T]) extends Target[T] { + val inputs = Seq(t) + def evaluate(args: Args) = args[T](0) + override def flushDest = false +} object Source{ implicit def apply(p: ammonite.ops.Path) = new Source(p) } @@ -107,8 +133,8 @@ object Task { - trait Module extends mill.define.Cacher[Task, Target]{ - def wrapCached[T](t: Task[T], enclosing: String): Target[T] = new TargetImpl(t, enclosing) + trait Module extends mill.define.Cacher[Target]{ + def wrapCached[T](t: Target[T], enclosing: String): Target[T] = t } class Task0[T](t: T) extends Task[T]{ lazy val t0 = t diff --git a/core/src/main/scala/mill/eval/Evaluator.scala b/core/src/main/scala/mill/eval/Evaluator.scala index 22861847..ef81515c 100644 --- a/core/src/main/scala/mill/eval/Evaluator.scala +++ b/core/src/main/scala/mill/eval/Evaluator.scala @@ -77,6 +77,7 @@ class Evaluator(workspacePath: Path, if (labeled.nonEmpty){ println(fansi.Color.Blue("Running " + labeled.map(_.segments.mkString(".")).mkString(", "))) } + if (terminal.flushDest) targetDestPath.foreach(rm) val (newResults, newEvaluated, terminalResult) = evaluateGroup(group, results, targetDestPath) metadataPath.foreach( @@ -95,7 +96,7 @@ class Evaluator(workspacePath: Path, results: collection.Map[Task[_], Any], targetDestPath: Option[Path]) = { - targetDestPath.foreach(rm) + var terminalResult: upickle.Js.Value = null val newEvaluated = mutable.Buffer.empty[Task[_]] val newResults = mutable.LinkedHashMap.empty[Task[_], Any] diff --git a/core/src/test/scala/mill/JavaCompileJarTests.scala b/core/src/test/scala/mill/JavaCompileJarTests.scala index 3e470b9d..8050ef6a 100644 --- a/core/src/test/scala/mill/JavaCompileJarTests.scala +++ b/core/src/test/scala/mill/JavaCompileJarTests.scala @@ -16,11 +16,8 @@ object JavaCompileJarTests extends TestSuite{ import ammonite.ops._ %("javac", sources.map(_.path.toString()), "-d", dest)(wd = dest) PathRef(dest) -// } - - val tests = Tests{ 'javac { val workspacePath = pwd / 'target / 'workspace / 'javac @@ -48,10 +45,10 @@ object JavaCompileJarTests extends TestSuite{ %%('java, "-cp", classFiles().path, mainClsName) } } + import Build._ val mapping = Discovered.mapping(Build) - def eval[T](t: Task[T]): (T, Int) = { val evaluator = new Evaluator(workspacePath, mapping) val evaluated = evaluator.evaluate(OSet(t)) @@ -163,7 +160,6 @@ object JavaCompileJarTests extends TestSuite{ runOutput3.out.string == "New Cls!\n", evalCount3 == 1 ) - } } } diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index 80929088..e1b3c130 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -2,88 +2,130 @@ package mill package scalaplugin import java.io.File +import java.util.Optional import ammonite.ops._ import coursier.{Cache, Fetch, MavenRepository, Repository, Resolution} import mill.define.Task import mill.define.Task.Module -import mill.discover.{Discovered, Mirror} import mill.eval.{Evaluator, PathRef} -import mill.modules.Jvm.{createJar, createAssembly} +import mill.modules.Jvm.{createAssembly, createJar} import mill.util.OSet -import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil} +import sbt.internal.inc._ import sbt.internal.util.{ConsoleOut, MainAppender} -import sbt.util.LogExchange -import xsbti.api.{ClassLike, DependencyContext} -import xsbti.compile.DependencyChanges +import sbt.util.{InterfaceUtil, LogExchange} +import xsbti.compile.{CompilerCache => _, FileAnalysisStore => _, ScalaInstance => _, _} + object ScalaModule{ + case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { + override def analysis(classpathEntry: File): Optional[CompileAnalysis] = + am(classpathEntry) + + override def definesClass(classpathEntry: File): DefinesClass = + Locate.definesClass(classpathEntry) + } + + val compilerCache = new CompilerCache(10) def compileScala(scalaVersion: String, - sources: PathRef, - compileClasspath: Seq[PathRef], + sources: Path, + compileClasspath: Seq[Path], outputPath: Path): PathRef = { val binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".") def grepJar(s: String) = { compileClasspath - .find(_.path.toString.endsWith(s)) + .find(_.toString.endsWith(s)) .getOrElse(throw new Exception("Cannot find " + s)) - .path .toIO } + val scalaInstance = new ScalaInstance( + version = scalaVersion, + loader = getClass.getClassLoader, + libraryJar = grepJar(s"scala-library-$scalaVersion.jar"), + compilerJar = grepJar(s"scala-compiler-$scalaVersion.jar"), + allJars = compileClasspath.toArray.map(_.toIO), + explicitActual = None + ) val scalac = ZincUtil.scalaCompiler( - new ScalaInstance( - version = scalaVersion, - loader = getClass.getClassLoader, - libraryJar = grepJar(s"scala-library-$scalaVersion.jar"), - compilerJar = grepJar(s"scala-compiler-$scalaVersion.jar"), - allJars = compileClasspath.toArray.map(_.path.toIO), - explicitActual = None - ), + scalaInstance, grepJar(s"compiler-bridge_$binaryScalaVersion-1.0.3.jar") ) mkdir(outputPath) + val ic = new sbt.internal.inc.IncrementalCompilerImpl() + + val logger = { + val console = ConsoleOut.systemOut + val consoleAppender = MainAppender.defaultScreen(console) + val l = LogExchange.logger("Hello") + LogExchange.unbindLoggerAppenders("Hello") + LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Warn) :: Nil) + l + } + val compiler = new IncrementalCompilerImpl + + + val cs = compiler.compilers(scalaInstance, ClasspathOptionsUtil.boot, None, scalac) - scalac.apply( - sources = ls.rec(sources.path).filter(_.isFile).map(_.toIO).toArray, - changes = new DependencyChanges { - def isEmpty = true - def modifiedBinaries() = Array[File]() - def modifiedClasses() = Array[String]() - }, - classpath = compileClasspath.map(_.path.toIO).toArray, - singleOutput = outputPath.toIO, - options = Array(), - callback = new xsbti.AnalysisCallback { - def startSource(source: File) = () - def apiPhaseCompleted() = () - def enabled() = true - def binaryDependency(onBinaryEntry: File, onBinaryClassName: String, fromClassName: String, fromSourceFile: File, context: DependencyContext) = () - def generatedNonLocalClass(source: File, classFile: File, binaryClassName: String, srcClassName: String) = () - def problem(what: String, pos: xsbti.Position, msg: String, severity: xsbti.Severity, reported: Boolean) = () - def dependencyPhaseCompleted() = () - def classDependency(onClassName: String, sourceClassName: String, context: DependencyContext) = () - def generatedLocalClass(source: File, classFile: File) = () - def api(sourceFile: File, classApi: ClassLike) = () - - def mainClass(sourceFile: File, className: String) = () - def usedName(className: String, name: String, useScopes: java.util.EnumSet[xsbti.UseScope]) = () - }, - maximumErrors = 10, - cache = new FreshCompilerCache(), - log = { - val console = ConsoleOut.systemOut - val consoleAppender = MainAppender.defaultScreen(console) - val l = LogExchange.logger("Hello") - LogExchange.unbindLoggerAppenders("Hello") - LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Warn) :: Nil) - l + val lookup = MockedLookup(Function.const(Optional.empty[CompileAnalysis])) + val reporter = new ManagedLoggedReporter(10, logger) + val extra = Array(InterfaceUtil.t2(("key", "value"))) + + var lastCompiledUnits: Set[String] = Set.empty + val progress = new CompileProgress { + override def advance(current: Int, total: Int): Boolean = true + + override def startUnit(phase: String, unitPath: String): Unit = { + println(unitPath) + lastCompiledUnits += unitPath } + } + + println("Running Compile") + println(outputPath/'zinc) + println(exists(outputPath/'zinc)) + val store = FileAnalysisStore.binary((outputPath/'zinc).toIO) + val newResult = ic.compile( + ic.inputs( + classpath = compileClasspath.map(_.toIO).toArray, + sources = ls.rec(sources).filter(_.isFile).map(_.toIO).toArray, + classesDirectory = (outputPath / 'classes).toIO, + scalacOptions = Array(), + javacOptions = Array(), + maxErrors = 10, + sourcePositionMappers = Array(), + order = CompileOrder.Mixed, + compilers = cs, + setup = ic.setup( + lookup, + skip = false, + (outputPath/'zinc_cache).toIO, + compilerCache, + IncOptions.of(), + reporter, + Some(progress), + extra + ), + pr = { + val prev = store.get() + println(prev) + PreviousResult.of(prev.map(_.getAnalysis), prev.map(_.getMiniSetup)) + } + ), + logger = logger ) - PathRef(outputPath) + + store.set( + AnalysisContents.create( + newResult.analysis(), + newResult.setup() + ) + ) + + PathRef(outputPath/'classes) } def resolveDependencies(repositories: Seq[Repository], @@ -193,8 +235,8 @@ trait ScalaModule extends Module{ def sources = T.source{ basePath / 'src } def resources = T.source{ basePath / 'resources } - def compile = T{ - compileScala(scalaVersion(), sources(), compileDepClasspath(), T.ctx().dest) + def compile = T.persistent{ + compileScala(scalaVersion(), sources().path, compileDepClasspath().map(_.path), T.ctx().dest) } def assembly = T{ val dest = T.ctx().dest |