diff options
-rw-r--r-- | build.sbt | 2 | ||||
-rwxr-xr-x | build.sc | 32 | ||||
-rw-r--r-- | core/src/mill/eval/Evaluator.scala | 3 | ||||
-rw-r--r-- | core/src/mill/modules/Jvm.scala | 12 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/ScalaModule.scala | 21 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/ScalaWorkerApi.scala | 33 | ||||
-rw-r--r-- | scalaworker/src/mill/scalaworker/ScalaWorker.scala | 37 |
7 files changed, 79 insertions, 61 deletions
@@ -246,7 +246,7 @@ lazy val integration = project "MILL_JAWN_REPO" -> testRepos("MILL_JAWN_REPO").value, "MILL_BETTERFILES_REPO" -> testRepos("MILL_BETTERFILES_REPO").value ) - for((k, v) <- kvs) yield s"-D$k=$v" + scalaWorkerProps.value ++ (for((k, v) <- kvs) yield s"-D$k=$v") } ) @@ -99,6 +99,20 @@ class BridgeModule(crossVersion: String) extends PublishModule { ) } + +object scalaworker extends MillModule{ + def moduleDeps = Seq(core, scalalib) + + def ivyDeps = Agg( + ivy"org.scala-sbt::zinc:1.0.5", + ivy"org.scala-sbt:test-interface:1.0" + ) + def testArgs = Seq( + "-DMILL_SCALA_WORKER=" + runClasspath().map(_.path).mkString(",") + ) +} + + object scalalib extends MillModule { def moduleDeps = Seq(core) @@ -106,25 +120,17 @@ object scalalib extends MillModule { def testArgs = T{ val bridgeVersions = bridges.items.map(_._1.head.toString) - for((version, compile) <- bridgeVersions.zip(bridgeCompiles())) + val bridgeArgs = for((version, compile) <- bridgeVersions.zip(bridgeCompiles())) yield { val underscored = version.replace('.', '_') val key = s"MILL_COMPILER_BRIDGE_$underscored" val value = compile.classes.path s"-D$key=$value" } + scalaworker.testArgs() ++ bridgeArgs } } -object scalaworker extends MillModule{ - def moduleDeps = Seq(core, scalalib) - - def ivyDeps = Agg( - ivy"org.scala-sbt::zinc:1.0.5", - ivy"org.scala-sbt:test-interface:1.0" - ) -} - object scalajslib extends MillModule { @@ -137,7 +143,7 @@ object scalajslib extends MillModule { "MILL_SCALAJS_BRIDGE_0_6" -> bridgeClasspath(jsbridges("0.6").runDepClasspath(), jsbridges("0.6").compile().classes), "MILL_SCALAJS_BRIDGE_1_0" -> bridgeClasspath(jsbridges("1.0").runDepClasspath(), jsbridges("1.0").compile().classes) ) - for((k, v) <- mapping.toSeq) yield s"-D$k=$v" + scalaworker.testArgs() ++ (for((k, v) <- mapping.toSeq) yield s"-D$k=$v") } object jsbridges extends Cross[JsBridgeModule]("0.6", "1.0") @@ -167,7 +173,7 @@ def testRepos = T{ object integration extends MillModule{ def moduleDeps = Seq(moduledefs, scalalib, scalajslib) def testArgs = T{ - for((k, v) <- testRepos()) yield s"-D$k=$v" + scalaworker.testArgs() ++ (for((k, v) <- testRepos()) yield s"-D$k=$v") } def forkArgs() = testArgs() } @@ -193,7 +199,7 @@ def assemblyBase(classpath: Agg[Path], extraArgs: String) def devAssembly = T{ assemblyBase( Agg.from(assemblyClasspath().flatten.map(_.path)), - (scalalib.testArgs() ++ scalajslib.testArgs() ++ Seq(scalaworker.jar())).mkString(" ") + (scalalib.testArgs() ++ scalajslib.testArgs() ++ scalaworker.testArgs()).mkString(" ") ) } diff --git a/core/src/mill/eval/Evaluator.scala b/core/src/mill/eval/Evaluator.scala index cf4b32cf..0e8709e0 100644 --- a/core/src/mill/eval/Evaluator.scala +++ b/core/src/mill/eval/Evaluator.scala @@ -44,7 +44,8 @@ class Evaluator[T](val workspacePath: Path, case t: NamedTask[Any] => val segments = t.ctx.segments val (finalTaskOverrides, enclosing) = t match{ - case t: Target[_] => rootModule.millInternal.segmentsToTargets(segments).ctx.overrides -> t.ctx.enclosing + case t: Target[_] => + rootModule.millInternal.segmentsToTargets.get(segments).fold(0)(_.ctx.overrides) -> t.ctx.enclosing case c: mill.define.Command[_] => 0 -> c.ctx.enclosing case c: mill.define.Worker[_] => 0 -> c.ctx.enclosing } diff --git a/core/src/mill/modules/Jvm.scala b/core/src/mill/modules/Jvm.scala index 0fa7e3e3..d9abff86 100644 --- a/core/src/mill/modules/Jvm.scala +++ b/core/src/mill/modules/Jvm.scala @@ -20,18 +20,6 @@ import scala.reflect.ClassTag object Jvm { - def gatherClassloaderJars(): Agg[Path] = { - val allJars = new Agg.Mutable[Path]() - var currentClassloader = Thread.currentThread().getContextClassLoader - while(currentClassloader != null){ - currentClassloader match{ - case u: URLClassLoader => allJars.appendAll(u.getURLs.map(x => Path(x.getFile))) - case _ => - } - currentClassloader = currentClassloader.getParent - } - allJars - } def interactiveSubprocess(mainClass: String, classPath: Agg[Path], diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index 77ebc417..848e0318 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -295,12 +295,11 @@ trait TestModule extends ScalaModule with TaskModule { def forkWorkingDir = ammonite.ops.pwd def test(args: String*) = T.command{ - mkdir(T.ctx().dest) val outputPath = T.ctx().dest/"out.json" Jvm.subprocess( - mainClass = "mill.scalalib.TestRunner", - classPath = Jvm.gatherClassloaderJars(), + mainClass = "mill.scalaworker.ScalaWorker", + classPath = mill.scalalib.ScalaWorkerApi.scalaWorkerClasspath(), jvmArgs = forkArgs(), envArgs = forkEnv(), mainArgs = Seq( @@ -323,17 +322,11 @@ trait TestModule extends ScalaModule with TaskModule { mkdir(T.ctx().dest) val outputPath = T.ctx().dest/"out.json" - Jvm.runLocal( - mainClass = "mill.scalalib.TestRunner", - classPath = Jvm.gatherClassloaderJars(), - mainArgs = Seq( - testFramework(), - runClasspath().map(_.path).mkString(" "), - Seq(compile().classes.path).mkString(" "), - args.mkString(" "), - outputPath.toString, - T.ctx().log.colored.toString - ) + mill.scalalib.ScalaWorkerApi.scalaWorker().apply( + testFramework(), + runClasspath().map(_.path), + Agg(compile().classes.path), + args ) val jsonOutput = upickle.json.read(outputPath.toIO) diff --git a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala index a032ab32..43b82460 100644 --- a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala +++ b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala @@ -12,25 +12,24 @@ import mill.define.{Task, Worker} import mill.eval.PathRef import mill.scalalib.Lib.resolveDependencies import mill.util.Loose - +import mill.util.JsonFormatters._ object ScalaWorkerApi extends mill.define.BaseModule(ammonite.ops.pwd){ - def scalaWorker: Worker[ScalaWorkerApi] = T.worker{ - + def scalaWorkerClasspath = T{ val scalaWorkerJar = sys.props("MILL_SCALA_WORKER") - val scalaWorkerClasspath = - if (scalaWorkerJar != null) Loose.Agg.from(scalaWorkerJar.split(',').map(Path(_))) - else { - val mill.eval.Result.Success(v) = resolveDependencies( - Seq(MavenRepository("https://repo1.maven.org/maven2")), - "2.12.4", - "2.12", - Seq(ivy"com.lihaoyi::mill-scalaworker:0.1-SNAPSHOT") - ) - v.map(_.path) - } - + if (scalaWorkerJar != null) Loose.Agg.from(scalaWorkerJar.split(',').map(Path(_))) + else { + val mill.eval.Result.Success(v) = resolveDependencies( + Seq(MavenRepository("https://repo1.maven.org/maven2")), + "2.12.4", + "2.12", + Seq(ivy"com.lihaoyi::mill-scalaworker:0.1-SNAPSHOT") + ) + v.map(_.path) + } + } + def scalaWorker: Worker[ScalaWorkerApi] = T.worker{ val cl = new java.net.URLClassLoader( - scalaWorkerClasspath.map(_.toNIO.toUri.toURL).toArray, + scalaWorkerClasspath().map(_.toNIO.toUri.toURL).toArray, getClass.getClassLoader ) val cls = cl.loadClass("mill.scalaworker.ScalaWorker") @@ -56,5 +55,5 @@ trait ScalaWorkerApi { entireClasspath: Agg[Path], testClassfilePath: Agg[Path], args: Seq[String]) - (implicit ctx: mill.util.Ctx): (String, Seq[Result]) + (implicit ctx: mill.util.Ctx.LogCtx): (String, Seq[Result]) } diff --git a/scalaworker/src/mill/scalaworker/ScalaWorker.scala b/scalaworker/src/mill/scalaworker/ScalaWorker.scala index df92cd0f..6c6cb504 100644 --- a/scalaworker/src/mill/scalaworker/ScalaWorker.scala +++ b/scalaworker/src/mill/scalaworker/ScalaWorker.scala @@ -7,15 +7,16 @@ import java.util.Optional import java.util.zip.ZipInputStream import ammonite.ops.{Path, exists, ls, mkdir} +import ammonite.util.Colors import mill.Agg import mill.define.Worker import mill.eval.PathRef import mill.modules.Jvm -import mill.scalalib.CompilationResult +import mill.scalalib.{CompilationResult, TestRunner} import xsbti.compile.{CompilerCache => _, FileAnalysisStore => _, ScalaInstance => _, _} import mill.scalalib.Lib.grepJar import mill.scalalib.TestRunner.Result -import mill.util.Ctx +import mill.util.{Ctx, PrintLogger} import sbt.internal.inc._ import sbt.internal.util.{ConsoleOut, MainAppender} import sbt.testing._ @@ -31,7 +32,37 @@ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClassp Locate.definesClass(classpathEntry) } +object ScalaWorker{ + + def main(args: Array[String]): Unit = { + try{ + val result = new ScalaWorker(null).apply( + frameworkName = args(0), + entireClasspath = Agg.from(args(1).split(" ").map(Path(_))), + testClassfilePath = Agg.from(args(2).split(" ").map(Path(_))), + args = args(3) match{ case "" => Nil case x => x.split(" ").toList } + )(new PrintLogger( + args(5) == "true", + if(args(5) == "true") Colors.Default + else Colors.BlackWhite, + System.out, + System.err, + System.err + )) + val outputPath = args(4) + ammonite.ops.write(Path(outputPath), upickle.default.write(result)) + }catch{case e: Throwable => + println(e) + e.printStackTrace() + } + // Tests are over, kill the JVM whether or not anyone's threads are still running + // Always return 0, even if tests fail. The caller can pick up the detailed test + // results from the outputPath + System.exit(0) + } + +} class ScalaWorker(ctx0: mill.util.Ctx) extends mill.scalalib.ScalaWorkerApi{ @volatile var scalaClassloaderCache = Option.empty[(Long, ClassLoader)] @volatile var scalaInstanceCache = Option.empty[(Long, ScalaInstance)] @@ -167,7 +198,7 @@ class ScalaWorker(ctx0: mill.util.Ctx) extends mill.scalalib.ScalaWorkerApi{ entireClasspath: Agg[Path], testClassfilePath: Agg[Path], args: Seq[String]) - (implicit ctx: mill.util.Ctx): (String, Seq[Result]) = { + (implicit ctx: mill.util.Ctx.LogCtx): (String, Seq[Result]) = { Jvm.inprocess(entireClasspath, classLoaderOverrideSbtTesting = true, cl => { val framework = cl.loadClass(frameworkName) |