diff --git a/bsp/src/mill/bsp/BSP.scala b/bsp/src/mill/bsp/BSP.scala index 6b7825146cd..3442ee7e6af 100644 --- a/bsp/src/mill/bsp/BSP.scala +++ b/bsp/src/mill/bsp/BSP.scala @@ -49,9 +49,10 @@ object BSP extends ExternalModule with CoursierModule { * @param ev The Evaluator * @return The server result, indicating if mill should re-run this command or just exit. */ - def startSession(ev: Evaluator): Command[BspServerResult] = T.command { + def startSession(allBootstrapEvaluators: Evaluator.AllBootstrapEvaluators) + : Command[BspServerResult] = T.command { T.log.errorStream.println("BSP/startSession: Starting BSP session") - val res = BspContext.bspServerHandle.runSession(ev) + val res = BspContext.bspServerHandle.runSession(allBootstrapEvaluators.value) T.log.errorStream.println(s"BSP/startSession: Finished BSP session, result: ${res}") res } diff --git a/bsp/src/mill/bsp/BspServerHandle.scala b/bsp/src/mill/bsp/BspServerHandle.scala index fd52d799a4e..b818bb22766 100644 --- a/bsp/src/mill/bsp/BspServerHandle.scala +++ b/bsp/src/mill/bsp/BspServerHandle.scala @@ -11,7 +11,7 @@ trait BspServerHandle { * Runs a new session with the given evaluator. This one blocks until the session ends. * @return The reason which the session ended, possibly indictating the wish for restart (e.g. in case of workspace reload). */ - def runSession(evaluator: Evaluator): BspServerResult + def runSession(evaluators: Seq[Evaluator]): BspServerResult /** * The result of the latest started session. Once a new session was started but not finished, this may be [[None]]. diff --git a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala index af2cf803451..b48d244a5d1 100644 --- a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala +++ b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala @@ -56,9 +56,9 @@ private class BspWorkerImpl() extends BspWorker { val bspServerHandle = new BspServerHandle { private[this] var lastResult0: Option[BspServerResult] = None - override def runSession(evaluator: Evaluator): BspServerResult = { + override def runSession(evaluators: Seq[Evaluator]): BspServerResult = { lastResult0 = None - millServer.updateEvaluator(Option(evaluator)) + millServer.updateEvaluator(Option(evaluators)) val onReload = Promise[BspServerResult]() millServer.onSessionEnd = Some { serverResult => if (!onReload.isCompleted) { diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 293cf06b070..1b972f05dc4 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -58,7 +58,7 @@ import com.google.gson.JsonObject import mill.T import mill.api.{DummyTestReporter, Result, Strict} import mill.define.Segment.Label -import mill.define.{Args, Discover, ExternalModule, Task} +import mill.define.{Args, BaseModule, Discover, ExternalModule, Task} import mill.eval.Evaluator import mill.main.MainModule import mill.scalalib.{JavaModule, SemanticDbJavaModule, TestModule} @@ -94,23 +94,15 @@ private class MillBuildServer( protected var clientIsIntelliJ = false private[this] var statePromise: Promise[State] = Promise[State]() - var evaluatorOpt: Option[Evaluator] = None - def evaluator = evaluatorOpt.get - def updateEvaluator(evaluator: Option[Evaluator]): Unit = { - debug(s"Updating Evaluator: $evaluator") + def updateEvaluator(evaluatorsOpt: Option[Seq[Evaluator]]): Unit = { + debug(s"Updating Evaluator: $evaluatorsOpt") if (statePromise.isCompleted) statePromise = Promise[State]() // replace the promise - evaluatorOpt = evaluator - evaluatorOpt.foreach(e => + evaluatorsOpt.foreach { evaluators => statePromise.success( - new State( - e.rootModule.millSourcePath, - e.baseLogger, - debug, - e.disableCallgraphInvalidation - ) + new State(evaluators, debug) ) - ) + } } def debug(msg: String) = logStream.println(msg) @@ -207,7 +199,7 @@ private class MillBuildServer( "workspaceBuildTargets", targetIds = _.bspModulesById.keySet.toSeq, tasks = { case m: JavaModule => T.task { m.bspBuildTargetData() } } - ) { (state, id, m, bspBuildTargetData) => + ) { (ev, state, id, m, bspBuildTargetData) => val s = m.bspBuildTarget val deps = m match { case jm: JavaModule => @@ -296,7 +288,7 @@ private class MillBuildServer( } } ) { - case (state, id, module, items) => new SourcesItem(id, items.asJava) + case (ev, state, id, module, items) => new SourcesItem(id, items.asJava) } { new SourcesResult(_) } @@ -306,18 +298,23 @@ private class MillBuildServer( override def buildTargetInverseSources(p: InverseSourcesParams) : CompletableFuture[InverseSourcesResult] = { completable(s"buildtargetInverseSources ${p}") { state => - val tasks = state.bspModulesById.iterator.collect { - case (id, m: JavaModule) => + val tasksEvaluators = state.bspModulesById.iterator.collect { + case (id, (m: JavaModule, ev)) => T.task { val src = m.allSourceFiles() val found = src.map(sanitizeUri).contains( p.getTextDocument.getUri ) - if (found) Seq((id)) else Seq() - } + if (found) Seq(id) else Seq() + } -> ev }.toSeq - val ids = evaluator.evalOrThrow()(tasks).flatten + val ids = tasksEvaluators + .groupMap(_._2)(_._1) + .flatMap { case (ev, ts) => ev.evalOrThrow()(ts) } + .flatten + .toSeq + new InverseSourcesResult(ids.asJava) } } @@ -342,7 +339,7 @@ private class MillBuildServer( } } ) { - case (state, id, m: JavaModule, (resolveDepsSources, unmanagedClasspath)) => + case (ev, state, id, m: JavaModule, (resolveDepsSources, unmanagedClasspath)) => val buildSources = if (!m.isInstanceOf[MillBuildRootModule]) Nil else mill.scalalib.Lib @@ -368,6 +365,7 @@ private class MillBuildServer( } ) { case ( + ev, state, id, m: JavaModule, @@ -394,7 +392,7 @@ private class MillBuildServer( case _ => T.task { Nil } } ) { - case (state, id, m, resources) => + case (ev, state, id, m, resources) => val resourcesUrls = resources.map(_.path).filter(os.exists).map(sanitizeUri) new ResourcesItem(id, resourcesUrls.asJava) @@ -408,22 +406,28 @@ private class MillBuildServer( completable(s"buildTargetCompile ${p}") { state => val params = TaskParameters.fromCompileParams(p) val taskId = params.hashCode() - val compileTasks = params.getTargets.distinct.map(state.bspModulesById).map { - case m: SemanticDbJavaModule if clientWantsSemanticDb => m.compiledClassesAndSemanticDbFiles - case m: JavaModule => m.compile - case m => T.task { + val compileTasksEvs = params.getTargets.distinct.map(state.bspModulesById).map { + case (m: SemanticDbJavaModule, ev) if clientWantsSemanticDb => + (m.compiledClassesAndSemanticDbFiles, ev) + case (m: JavaModule, ev) => (m.compile, ev) + case (m, ev) => T.task { Result.Failure( s"Don't know how to compile non-Java target ${m.bspBuildTarget.displayName}" ) - } + } -> ev } - val result = evaluator.evaluate( - compileTasks, - Utils.getBspLoggedReporterPool(p.getOriginId, state.bspIdByModule, client), - DummyTestReporter, - new MillBspLogger(client, taskId, evaluator.baseLogger) - ) + val result = compileTasksEvs + .groupMap(_._2)(_._1) + .map { case (ev, ts) => + ev.evaluate( + ts, + Utils.getBspLoggedReporterPool(p.getOriginId, state.bspIdByModule, client), + DummyTestReporter, + new MillBspLogger(client, taskId, ev.baseLogger) + ) + } + .toSeq val compileResult = new CompileResult(Utils.getStatusCode(result)) compileResult.setOriginId(p.getOriginId) compileResult // TODO: See in what form IntelliJ expects data about products of compilation in order to set data field @@ -432,25 +436,25 @@ private class MillBuildServer( override def buildTargetOutputPaths(params: OutputPathsParams) : CompletableFuture[OutputPathsResult] = completable(s"buildTargetOutputPaths ${params}") { state => - val outItems = new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(evaluator.outPath) + "/", - OutputPathItemKind.DIRECTORY - ) - - val extItems = new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(evaluator.externalOutPath) + "/", - OutputPathItemKind.DIRECTORY - ) - val items = for { target <- params.getTargets.asScala - module <- state.bspModulesById.get(target) + (module, ev) <- state.bspModulesById.get(target) } yield { val items = - if (module.millOuterCtx.external) List(extItems) - else List(outItems) + if (module.millOuterCtx.external) List( + new OutputPathItem( + // Spec says, a directory must end with a forward slash + sanitizeUri(ev.externalOutPath) + "/", + OutputPathItemKind.DIRECTORY + ) + ) + else List( + new OutputPathItem( + // Spec says, a directory must end with a forward slash + sanitizeUri(ev.outPath) + "/", + OutputPathItemKind.DIRECTORY + ) + ) new OutputPathsItem(target, items.asJava) } @@ -460,15 +464,16 @@ private class MillBuildServer( override def buildTargetRun(runParams: RunParams): CompletableFuture[RunResult] = completable(s"buildTargetRun ${runParams}") { state => val params = TaskParameters.fromRunParams(runParams) - val module = params.getTargets.map(state.bspModulesById).collectFirst { - case m: JavaModule => m + val (module, ev) = params.getTargets.map(state.bspModulesById).collectFirst { + case (m: JavaModule, ev) => (m, ev) }.get + val args = params.getArguments.getOrElse(Seq.empty[String]) val runTask = module.run(T.task(Args(args))) - val runResult = evaluator.evaluate( + val runResult = ev.evaluate( Strict.Agg(runTask), Utils.getBspLoggedReporterPool(runParams.getOriginId, state.bspIdByModule, client), - logger = new MillBspLogger(client, runTask.hashCode(), evaluator.baseLogger) + logger = new MillBspLogger(client, runTask.hashCode(), ev.baseLogger) ) val response = runResult.results(runTask) match { case _: Result.Success[Any] => new RunResult(StatusCode.OK) @@ -510,7 +515,7 @@ private class MillBuildServer( .filter(millBuildTargetIds.contains) .foldLeft(StatusCode.OK) { (overallStatusCode, targetId) => state.bspModulesById(targetId) match { - case testModule: TestModule => + case (testModule: TestModule, ev) => val testTask = testModule.testLocal(argsMap(targetId.getUri): _*) // notifying the client that the testing of this build target started @@ -529,7 +534,7 @@ private class MillBuildServer( Seq.empty[String] ) - val results = evaluator.evaluate( + val results = ev.evaluate( Strict.Agg(testTask), Utils.getBspLoggedReporterPool( testParams.getOriginId, @@ -537,9 +542,9 @@ private class MillBuildServer( client ), testReporter, - new MillBspLogger(client, testTask.hashCode, evaluator.baseLogger) + new MillBspLogger(client, testTask.hashCode, ev.baseLogger) ) - val statusCode = Utils.getStatusCode(results) + val statusCode = Utils.getStatusCode(Seq(results)) // Notifying the client that the testing of this build target ended val taskFinishParams = @@ -582,16 +587,16 @@ private class MillBuildServer( true )) { case ((msg, cleaned), targetId) => - val module = state.bspModulesById(targetId) + val (module, ev) = state.bspModulesById(targetId) val mainModule = new MainModule { override implicit def millDiscover: Discover[_] = Discover[this.type] } val compileTargetName = (module.millModuleSegments ++ Label("compile")).render debug(s"about to clean: ${compileTargetName}") - val cleanTask = mainModule.clean(evaluator, Seq(compileTargetName): _*) - val cleanResult = evaluator.evaluate( + val cleanTask = mainModule.clean(ev, Seq(compileTargetName): _*) + val cleanResult = ev.evaluate( Strict.Agg(cleanTask), - logger = new MillBspLogger(client, cleanTask.hashCode, evaluator.baseLogger) + logger = new MillBspLogger(client, cleanTask.hashCode, ev.baseLogger) ) if (cleanResult.failing.keyCount > 0) ( msg + s" Target ${compileTargetName} could not be cleaned. See message from mill: \n" + @@ -602,7 +607,7 @@ private class MillBuildServer( false ) else { - val outPaths = evaluator.pathsResolver.resolveDest( + val outPaths = ev.pathsResolver.resolveDest( module.millModuleSegments ++ Label("compile") ) val outPathSeq = Seq(outPaths.dest, outPaths.meta, outPaths.log) @@ -626,14 +631,23 @@ private class MillBuildServer( hint: String, targetIds: State => Seq[BuildTargetIdentifier], tasks: BspModule => Task[W] - )(f: (State, BuildTargetIdentifier, BspModule, W) => T)(agg: java.util.List[T] => V) + )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: java.util.List[T] => V) : CompletableFuture[V] = completable(hint) { state: State => val ids = targetIds(state) - val tasksSeq = ids.map(m => tasks(state.bspModulesById(m))) - val evaluated = evaluator.evalOrThrow()(tasksSeq) - val res = evaluated.zip(ids).map { case (v, i) => f(state, i, state.bspModulesById(i), v) } - agg(res.asJava) + val tasksSeq = ids.map { id => + val (m, ev) = state.bspModulesById(id) + (tasks(m), (ev, id)) + } + + val evaluated = tasksSeq + .groupMap(_._2)(_._1) + .map { case ((ev, id), ts) => + ev.evalOrThrow()(ts) + .map { v => f(ev, state, id, state.bspModulesById(id)._1, v) } + } + + agg(evaluated.flatten.toSeq.asJava) } /** diff --git a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala index 455ba319f5b..c9873e6c1d5 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala @@ -29,8 +29,8 @@ private trait MillJavaBuildServer extends JavaBuildServer { this: MillBuildServe T.task { (classesPathTask(), m.javacOptions(), m.bspCompileClasspath()) } } ) { - case (state, id, m: JavaModule, (classesPath, javacOptions, bspCompileClasspath)) => - val pathResolver = evaluator.pathsResolver + case (ev, state, id, m: JavaModule, (classesPath, javacOptions, bspCompileClasspath)) => + val pathResolver = ev.pathsResolver val options = javacOptions val classpath = bspCompileClasspath.map(_.resolve(pathResolver)).map(sanitizeUri) diff --git a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index 5accb18cb51..a639aad0d14 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -60,6 +60,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer } ) { case ( + ev, state, id, m: JavaModule, diff --git a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala index c918ea73a94..acfcd45b37a 100644 --- a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala @@ -49,8 +49,14 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer T.task { (Nil, Nil, classesPathTask()) } } ) { - case (state, id, m: JavaModule, (allScalacOptions, bspCompileClsaspath, classesPathTask)) => - val pathResolver = evaluator.pathsResolver + case ( + ev, + state, + id, + m: JavaModule, + (allScalacOptions, bspCompileClsaspath, classesPathTask) + ) => + val pathResolver = ev.pathsResolver new ScalacOptionsItem( id, allScalacOptions.asJava, @@ -73,7 +79,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer T.task((m.zincWorker().worker(), m.compile(), m.forkArgs(), m.forkEnv())) } ) { - case (state, id, m: JavaModule, (worker, compile, forkArgs, forkEnv)) => + case (ev, state, id, m: JavaModule, (worker, compile, forkArgs, forkEnv)) => // We find all main classes, although we could also find only the configured one val mainClasses = worker.discoverMainClasses(compile) // val mainMain = m.mainClass().orElse(if(mainClasses.size == 1) mainClasses.headOption else None) @@ -84,7 +90,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer } new ScalaMainClassesItem(id, items.asJava) - case (state, id, _, _) => // no Java module, so no main classes + case (ev, state, id, _, _) => // no Java module, so no main classes new ScalaMainClassesItem(id, Seq.empty[ScalaMainClass].asJava) } { new ScalaMainClassesResult(_) @@ -102,7 +108,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer T.task(None) } ) { - case (state, id, m: TestModule, Some((classpath, testFramework, compResult))) => + case (ev, state, id, m: TestModule, Some((classpath, testFramework, compResult))) => val (frameworkName, classFingerprint): (String, Agg[(Class[_], Fingerprint)]) = Jvm.inprocess( classpath.map(_.path), @@ -121,7 +127,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer )(new mill.api.Ctx.Home { def home = os.home }) val classes = Seq.from(classFingerprint.map(classF => classF._1.getName.stripSuffix("$"))) new ScalaTestClassesItem(id, classes.asJava, frameworkName) - case (state, id, _, _) => + case (ev, state, id, _, _) => // Not a test module, so no test classes new ScalaTestClassesItem(id, Seq.empty[String].asJava) } { diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index 842c078cc38..cfe83dd737f 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -1,74 +1,35 @@ package mill.bsp.worker import ch.epfl.scala.bsp4j.BuildTargetIdentifier -import mill.runner.MillBuildBootstrap import mill.scalalib.bsp.BspModule -import mill.scalalib.internal.{JavaModuleUtils, ModuleUtils} +import mill.scalalib.internal.JavaModuleUtils import mill.define.Module -import mill.util.ColorLogger +import mill.eval.Evaluator -private class State( - projectRoot: os.Path, - baseLogger: ColorLogger, - debug: String => Unit, - disableCallgraphInvalidation: Boolean -) { - lazy val bspModulesById: Map[BuildTargetIdentifier, BspModule] = { - val modules: Seq[(Module, Seq[Module])] = rootModules - .map(rootModule => (rootModule, JavaModuleUtils.transitiveModules(rootModule))) +private class State(evaluators: Seq[Evaluator], debug: String => Unit) { + lazy val bspModulesById: Map[BuildTargetIdentifier, (BspModule, Evaluator)] = { + val modules: Seq[(Module, Seq[Module], Evaluator)] = evaluators + .map(ev => (ev.rootModule, JavaModuleUtils.transitiveModules(ev.rootModule), ev)) val map = modules - .flatMap { case (rootModule, otherModules) => + .flatMap { case (rootModule, otherModules, eval) => (Seq(rootModule) ++ otherModules).collect { case m: BspModule => val uri = Utils.sanitizeUri( rootModule.millSourcePath / m.millModuleSegments.parts ) - (new BuildTargetIdentifier(uri), m) + (new BuildTargetIdentifier(uri), (m, eval)) } } .toMap - debug(s"BspModules: ${map.mapValues(_.bspDisplayName)}") + debug(s"BspModules: ${map.mapValues(_._1.bspDisplayName).toMap}") map } - lazy val rootModules: Seq[mill.main.RootModule] = { - val evaluated = new mill.runner.MillBuildBootstrap( - projectRoot = projectRoot, - home = os.home, - keepGoing = false, - imports = Nil, - env = Map.empty, - threadCount = None, - targetsAndParams = Seq("resolve", "_"), - prevRunnerState = mill.runner.RunnerState.empty, - logger = baseLogger, - disableCallgraphInvalidation = disableCallgraphInvalidation, - needBuildSc = true - ).evaluate() + lazy val rootModules: Seq[mill.define.BaseModule] = evaluators.map(_.rootModule) - val rootModules0 = evaluated.result.frames - .flatMap(_.classLoaderOpt) - .zipWithIndex - .map { case (c, i) => - MillBuildBootstrap - .getRootModule(c, i, projectRoot) - .fold(sys.error(_), identity(_)) - } - - val bootstrapModule = evaluated.result.bootstrapModuleOpt.map(m => - MillBuildBootstrap - .getChildRootModule( - m, - evaluated.result.frames.length, - projectRoot - ) - .fold(sys.error(_), identity(_)) - ) - - rootModules0 ++ bootstrapModule - } - lazy val bspIdByModule: Map[BspModule, BuildTargetIdentifier] = bspModulesById.map(_.swap) + lazy val bspIdByModule: Map[BspModule, BuildTargetIdentifier] = + bspModulesById.mapValues(_._1).map(_.swap).toMap } diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 9edec117254..42a06af854c 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -38,14 +38,12 @@ private object Utils { } // Get the execution status code given the results from Evaluator.evaluate - def getStatusCode(results: Evaluator.Results): StatusCode = { - val statusCodes = results.results.keys.map(task => getStatusCodePerTask(results, task)).toSeq - if (statusCodes.contains(StatusCode.ERROR)) - StatusCode.ERROR - else if (statusCodes.contains(StatusCode.CANCELLED)) - StatusCode.CANCELLED - else - StatusCode.OK + def getStatusCode(resultsLists: Seq[Evaluator.Results]): StatusCode = { + val statusCodes = + resultsLists.flatMap(r => r.results.keys.map(task => getStatusCodePerTask(r, task)).toSeq) + if (statusCodes.contains(StatusCode.ERROR)) StatusCode.ERROR + else if (statusCodes.contains(StatusCode.CANCELLED)) StatusCode.CANCELLED + else StatusCode.OK } private[this] def getStatusCodePerTask( diff --git a/main/eval/src/mill/eval/Evaluator.scala b/main/eval/src/mill/eval/Evaluator.scala index 6f4618c74dd..f20156b3083 100644 --- a/main/eval/src/mill/eval/Evaluator.scala +++ b/main/eval/src/mill/eval/Evaluator.scala @@ -66,6 +66,8 @@ object Evaluator { // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule // in directly) we are forced to pass it in via a ThreadLocal val currentEvaluator = new DynamicVariable[mill.eval.Evaluator](null) + val allBootstrapEvaluators = new DynamicVariable[AllBootstrapEvaluators](null) + case class AllBootstrapEvaluators(value: Seq[Evaluator]) val defaultEnv: Map[String, String] = System.getenv().asScala.toMap diff --git a/main/src/mill/main/TokenReaders.scala b/main/src/mill/main/TokenReaders.scala index 0ad750d8c20..72915270827 100644 --- a/main/src/mill/main/TokenReaders.scala +++ b/main/src/mill/main/TokenReaders.scala @@ -26,6 +26,11 @@ object Tasks { private[mill] class EvaluatorTokenReader[T]() extends mainargs.TokensReader.Constant[Evaluator] { def read(): Either[String, Evaluator] = Right(Evaluator.currentEvaluator.value) } +private[mill] class AllEvaluatorsTokenReader[T]() + extends mainargs.TokensReader.Constant[Evaluator.AllBootstrapEvaluators] { + def read(): Either[String, Evaluator.AllBootstrapEvaluators] = + Right(Evaluator.allBootstrapEvaluators.value) +} private class LeftoverTaskTokenReader[T](tokensReaderOfT: TokensReader.Leftover[T, _]) extends mainargs.TokensReader.Leftover[Task[T], T] { @@ -38,6 +43,10 @@ object TokenReaders { implicit def millEvaluatorTokenReader[T]: mainargs.TokensReader[Evaluator] = new mill.main.EvaluatorTokenReader[T]() + implicit def millAllEvaluatorsTokenReader[T] + : mainargs.TokensReader[Evaluator.AllBootstrapEvaluators] = + new mill.main.AllEvaluatorsTokenReader[T]() + implicit def millTasksTokenReader[T]: mainargs.TokensReader[Tasks[T]] = new mill.main.Tasks.TokenReader[T]() diff --git a/runner/src/mill/runner/MillBuildBootstrap.scala b/runner/src/mill/runner/MillBuildBootstrap.scala index 24c770f042b..b32cc5a6df6 100644 --- a/runner/src/mill/runner/MillBuildBootstrap.scala +++ b/runner/src/mill/runner/MillBuildBootstrap.scala @@ -193,7 +193,8 @@ class MillBuildBootstrap( Map.empty, Map.empty, None, - Nil + Nil, + evaluator ) nestedState.add(frame = evalState, errorOpt = Some(error)) @@ -242,7 +243,8 @@ class MillBuildBootstrap( scriptImportGraph, methodCodeHashSignatures, Some(classLoader), - runClasspath + runClasspath, + evaluator ) nestedState.add(frame = evalState) @@ -260,8 +262,11 @@ class MillBuildBootstrap( evaluator: Evaluator ): RunnerState = { - val (evaled, evalWatched, moduleWatches) = + val (evaled, evalWatched, moduleWatches) = Evaluator.allBootstrapEvaluators.withValue( + Evaluator.AllBootstrapEvaluators(Seq(evaluator) ++ nestedState.frames.map(_.evaluator)) + ) { evaluateWithWatches(rootModule, evaluator, targetsAndParams) + } val evalState = RunnerState.Frame( evaluator.workerCache.toMap, @@ -270,7 +275,8 @@ class MillBuildBootstrap( Map.empty, Map.empty, None, - Nil + Nil, + evaluator ) nestedState.add(frame = evalState, errorOpt = evaled.left.toOption) diff --git a/runner/src/mill/runner/RunnerState.scala b/runner/src/mill/runner/RunnerState.scala index 1daff8a28de..8a91535a021 100644 --- a/runner/src/mill/runner/RunnerState.scala +++ b/runner/src/mill/runner/RunnerState.scala @@ -61,7 +61,8 @@ object RunnerState { scriptImportGraph: Map[os.Path, (Int, Seq[os.Path])], methodCodeHashSignatures: Map[String, Int], classLoaderOpt: Option[RunnerState.URLClassLoader], - runClasspath: Seq[PathRef] + runClasspath: Seq[PathRef], + evaluator: Evaluator ) { def loggedData = { @@ -101,7 +102,7 @@ object RunnerState { ) implicit val loggedRw: ReadWriter[Logged] = macroRW - def empty = Frame(Map.empty, Nil, Nil, Map.empty, Map.empty, None, Nil) + def empty = Frame(Map.empty, Nil, Nil, Map.empty, Map.empty, None, Nil, null) } }