diff options
author | Alexandra Dima <alexandra.dima@jetbrains.com> | 2019-07-10 17:12:12 +0200 |
---|---|---|
committer | Samvel Abrahamyan <samvel1024@gmail.com> | 2019-10-12 14:32:58 +0200 |
commit | 0d53a6e057ae24ecf0bfd5bf0929310723c31282 (patch) | |
tree | 1503d4f04ff8c4bfb54f3ae841293ae20076eb8b | |
parent | b71748b1b58da3b70ceb9290257ed688b71fbe21 (diff) | |
download | mill-0d53a6e057ae24ecf0bfd5bf0929310723c31282.tar.gz mill-0d53a6e057ae24ecf0bfd5bf0929310723c31282.tar.bz2 mill-0d53a6e057ae24ecf0bfd5bf0929310723c31282.zip |
Implemented support for publishing compilation diagnostics through the custom BspLoggedReporter reporter. Patched the mill.api.Ctx data structure as well as the evaluate() method on mill's Evaluator in order to accept a potential reporter from the outside, or use a default value if none is given.
-rw-r--r-- | contrib/bsp/src/mill/contrib/MainMillBuildServer.scala | 30 | ||||
-rw-r--r-- | contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala | 82 | ||||
-rw-r--r-- | contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala | 152 | ||||
-rw-r--r-- | contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala | 3 | ||||
-rw-r--r-- | main/api/src/mill/api/Ctx.scala | 5 | ||||
-rw-r--r-- | main/core/src/eval/Evaluator.scala | 27 | ||||
-rw-r--r-- | scalalib/api/src/ZincWorkerApi.scala | 8 | ||||
-rw-r--r-- | scalalib/src/JavaModule.scala | 9 | ||||
-rw-r--r-- | scalalib/src/ScalaModule.scala | 7 | ||||
-rw-r--r-- | scalalib/worker/src/ZincWorkerImpl.scala | 43 | ||||
-rw-r--r-- | scratch/build.sc | 4 |
11 files changed, 323 insertions, 47 deletions
diff --git a/contrib/bsp/src/mill/contrib/MainMillBuildServer.scala b/contrib/bsp/src/mill/contrib/MainMillBuildServer.scala index a8508ab6..7caaf5d3 100644 --- a/contrib/bsp/src/mill/contrib/MainMillBuildServer.scala +++ b/contrib/bsp/src/mill/contrib/MainMillBuildServer.scala @@ -7,10 +7,10 @@ import java.nio.file.FileAlreadyExistsException import java.util.concurrent.{CancellationException, CompletableFuture, ExecutorService, Executors, Future} import upickle.default._ -import ch.epfl.scala.bsp4j.{BspConnectionDetails, BuildClient, ScalaTestClassesParams} +import ch.epfl.scala.bsp4j.{BspConnectionDetails, BuildClient, DidChangeBuildTarget, LogMessageParams, PublishDiagnosticsParams, ScalaTestClassesParams, ShowMessageParams, TaskFinishParams, TaskProgressParams, TaskStartParams, WorkspaceBuildTargetsResult} import mill._ import mill.api.Strict -import mill.contrib.bsp.{MillBuildServer, ModuleUtils} +import mill.contrib.bsp.{BspLoggedReporter, MillBuildServer, ModuleUtils} import mill.define.{Command, Discover, ExternalModule, Target, Task} import mill.eval.Evaluator import mill.scalalib._ @@ -20,6 +20,7 @@ import requests.Compress.None import upickle.default import scala.collection.JavaConverters._ +import scala.io.Source object MainMillBuildServer extends ExternalModule { @@ -152,11 +153,28 @@ object MainMillBuildServer extends ExternalModule { def experiment(ev: Evaluator): Command[Unit] = T.command { val millServer = new mill.contrib.bsp.MillBuildServer(ev, bspVersion, version, languages) - val mods: Seq[JavaModule] = modules(ev)() - for (module <- mods) { - println(module.millModuleSegments.parts.mkString(".")) + val client = new BuildClient { + var diagnostics = List.empty[PublishDiagnosticsParams] + override def onBuildShowMessage(params: ShowMessageParams): Unit = ??? + override def onBuildLogMessage(params: LogMessageParams): Unit = ??? + override def onBuildTaskStart(params: TaskStartParams): Unit = ??? + override def onBuildTaskProgress(params: TaskProgressParams): Unit = ??? + override def onBuildTaskFinish(params: TaskFinishParams): Unit = ??? + override def onBuildPublishDiagnostics( + params: PublishDiagnosticsParams + ): Unit = { + diagnostics ++= List(params) } - + override def onBuildTargetDidChange(params: DidChangeBuildTarget): Unit = + ??? + } + for (module <- millServer.millModules) { + ev.evaluate(Strict.Agg(module.compile), Option(new BspLoggedReporter(client, + millServer.moduleToTargetId(module), + Option.empty[String], + 10, millServer.getCompilationLogger))) + //println("Diagnostics: " + client.diagnostics) + } } /** diff --git a/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala b/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala new file mode 100644 index 00000000..31900211 --- /dev/null +++ b/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala @@ -0,0 +1,82 @@ +package mill.contrib.bsp + +import java.io.File + +import ch.epfl.scala.{bsp4j => bsp} +import sbt.internal.inc.ManagedLoggedReporter +import sbt.internal.inc.schema.Position +import sbt.internal.util.ManagedLogger +import xsbti.{Problem, Severity} + +import scala.collection.JavaConverters._ +import scala.compat.java8.OptionConverters._ +import scala.io.Source + +class BspLoggedReporter(client: bsp.BuildClient, + targetId: bsp.BuildTargetIdentifier, + compilationOriginId: Option[String], + maxErrors: Int, + logger: ManagedLogger) extends ManagedLoggedReporter(maxErrors, logger) { + + override def logError(problem: Problem): Unit = { + client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId)) + println("Sent diagnostics to the client") + super.logError(problem) + println("Logged the error") + } + + override def logInfo(problem: Problem): Unit = { + client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId)) + super.logInfo(problem) + } + + override def logWarning(problem: Problem): Unit = { + client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId)) + super.logWarning(problem) + } + + def getDiagnostics(problem: Problem, targetId: bsp.BuildTargetIdentifier, originId: Option[String]): + bsp.PublishDiagnosticsParams = { + println("Problem: " + problem) + val sourceFile = problem.position().sourceFile().asScala + val start = new bsp.Position( + problem.position.startLine.asScala.getOrElse(0), + problem.position.startOffset.asScala.getOrElse(0)) + val end = new bsp.Position( + problem.position.endLine.asScala.getOrElse(0), + problem.position.endOffset.asScala.getOrElse(0)) + val diagnostic = new bsp.Diagnostic(new bsp.Range(start, end), problem.message) + diagnostic.setCode(problem.position.lineContent) + diagnostic.setSource("compiler from mill") + diagnostic.setSeverity( problem.severity match { + case Severity.Info => bsp.DiagnosticSeverity.INFORMATION + case Severity.Error => bsp.DiagnosticSeverity.ERROR + case Severity.Warn => bsp.DiagnosticSeverity.WARNING + } + ) + + val params = new bsp.PublishDiagnosticsParams( + new bsp.TextDocumentIdentifier(sourceFile.getOrElse(new File(targetId.getUri)).toPath.toAbsolutePath.toUri.toString), + targetId, List(diagnostic).asJava, true) + + if (originId.nonEmpty) { params.setOriginId(originId.get) } + println("Diagnostics: " + params) + params + } + + private[this] def getErrorCode(file: Option[File], start: bsp.Position, end: bsp.Position, position: xsbti.Position): String = { + file match { + case None => position.lineContent + case f: Option[File] => + val source = Source.fromFile(f.get) + source.close() + val lines = source.getLines.toSeq + val code = lines(start.getLine).substring(start.getCharacter) + + lines.take(start.getLine - 1).takeRight(lines.length - end.getLine - 1).mkString("\n") + + lines(end.getLine).substring(0, end.getCharacter + 1) + code + } + + } + +} diff --git a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala index 91d9c4fd..5d79ee76 100644 --- a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala +++ b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala @@ -1,25 +1,34 @@ package mill.contrib.bsp +import java.io.File + import sbt.testing._ import java.util.{Calendar, Collections} import java.util.concurrent.CompletableFuture +import scala.compat.java8.OptionConverters._ import mill.scalalib.Lib.discoverTests import ch.epfl.scala.bsp4j._ +import ch.epfl.scala.{bsp4j => bsp} import mill.{scalalib, _} import mill.api.{Loose, Result, Strict} import mill.contrib.bsp.ModuleUtils._ import mill.eval.Evaluator import mill.scalalib._ -import mill.scalalib.api.CompilationResult -import mill.scalalib.api.ZincWorkerApi +import mill.scalalib.api.{CompilationResult, ZincWorkerApi} +import sbt.internal.inc._ +import xsbti.{Position, Problem, Severity} +import xsbti.compile.{AnalysisContents, AnalysisStore, FileAnalysisStore} +import xsbti.compile.analysis.SourceInfo import scala.collection.mutable.Map -import mill.api.Result.{Failing, Success} +import mill.api.Result.{Failing, Failure, Success} import scala.collection.JavaConverters._ import mill.modules.Jvm import mill.util.{Ctx, PrintLogger} import mill.define.{Discover, ExternalModule, Target, Task} +import sbt.internal.util.{ConsoleOut, MainAppender, ManagedLogger} +import sbt.util.LogExchange import scala.io.Source @@ -31,7 +40,6 @@ class MillBuildServer(evaluator: Evaluator, implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]() lazy val millDiscover: Discover[MillBuildServer.this.type] = Discover[this.type] - val bspVersion: String = _bspVersion val supportedLanguages: List[String] = languages val millServerVersion: String = serverVersion @@ -44,7 +52,6 @@ class MillBuildServer(evaluator: Evaluator, var moduleToTarget: Predef.Map[JavaModule, BuildTarget] = ModuleUtils.millModulesToBspTargets(millModules, evaluator, List("scala", "java")) - var clientInitialized = false val ctx: Ctx.Log with Ctx.Home = new Ctx.Log with Ctx.Home { @@ -217,6 +224,131 @@ class MillBuildServer(evaluator: Evaluator, future } + private[this] def getErrorCode(file: File, start: bsp.Position, end: bsp.Position): String = { + + val source = Source.fromFile(file) + source.close() + val lines = source.getLines.toSeq + val code = lines(start.getLine).substring(start.getCharacter) + + lines.take(start.getLine - 1).takeRight(lines.length - end.getLine - 1).mkString("\n") + + lines(end.getLine).substring(0, end.getCharacter + 1) + code + } + + def getDiagnosticsFromFile(analysisFile: os.Path, targetId: BuildTargetIdentifier, originId: Option[String]): + Seq[PublishDiagnosticsParams] = { + val analysisStore: AnalysisStore = FileAnalysisStore.getDefault(analysisFile.toIO) + analysisStore.get.asScala match { + case contents: AnalysisContents => + val sourceInfoMap: Map[File, SourceInfo] = contents.getAnalysis.readSourceInfos.getAllSourceInfos.asScala + var diagnosticsParams = Seq.empty[PublishDiagnosticsParams] + for ( (file, sourceInfo) <- sourceInfoMap) { + var diagnostics = List.empty[Diagnostic] + for (problem <- sourceInfo.getReportedProblems) { + val start = new bsp.Position( + problem.position.startLine.asScala.getOrElse(0), + problem.position.startOffset.asScala.getOrElse(0)) + val end = new bsp.Position( + problem.position.endLine.asScala.getOrElse(0), + problem.position.endOffset.asScala.getOrElse(0)) + val diagnostic = new Diagnostic(new Range(start, end), problem.message) + diagnostic.setCode(getErrorCode(file, start, end)) + diagnostic.setSource("compiler from mill") + + diagnostic.setSeverity( problem.severity match { + case Severity.Info => DiagnosticSeverity.INFORMATION + case Severity.Error => DiagnosticSeverity.ERROR + case Severity.Warn => DiagnosticSeverity.WARNING + } + ) + diagnostics ++= List(diagnostic) + } + val params = new PublishDiagnosticsParams(new TextDocumentIdentifier(file.toURI.toString), + targetId, diagnostics.asJava, true) + if (originId.nonEmpty) { params.setOriginId(originId.get) } + diagnosticsParams ++= Seq(params) + } + diagnosticsParams + case None => Seq.empty[PublishDiagnosticsParams] + } + } + + def getSourceFileCompileErrors(problems: Seq[Problem]): Map[File, Array[Problem]] = { + val problemsMap = Map.empty[File, Array[Problem]] + + for (problem <- problems) { + try { + val sourceFile = problem.position.sourceFile.get + if (problemsMap.contains(sourceFile)) { + problemsMap(sourceFile) = problemsMap(sourceFile) ++ Array(problem) + } else { + problemsMap(sourceFile) = Array(problem) + } + + } catch { + case e: Exception => + } + } + problemsMap + } + + def getDiagnostics(problems: Array[Problem], targetId: BuildTargetIdentifier, originId: Option[String]): + Seq[PublishDiagnosticsParams] = { + var diagnosticsParams = Seq.empty[PublishDiagnosticsParams] + for (( sourceFile, problems ) <- getSourceFileCompileErrors(problems)) { + var diagnostics = Seq.empty[Diagnostic] + for (problem <- problems) { + val start = new bsp.Position( + problem.position.startLine.asScala.getOrElse(0), + problem.position.startOffset.asScala.getOrElse(0)) + val end = new bsp.Position( + problem.position.endLine.asScala.getOrElse(0), + problem.position.endOffset.asScala.getOrElse(0)) + val diagnostic = new Diagnostic(new Range(start, end), problem.message) + diagnostic.setCode(getErrorCode(sourceFile, start, end)) + diagnostic.setSource("compiler from mill") + diagnostic.setSeverity( problem.severity match { + case Severity.Info => DiagnosticSeverity.INFORMATION + case Severity.Error => DiagnosticSeverity.ERROR + case Severity.Warn => DiagnosticSeverity.WARNING + } + ) + diagnostics ++= List(diagnostic) + } + val params = new PublishDiagnosticsParams(new TextDocumentIdentifier(sourceFile.toPath.toAbsolutePath.toUri.toString), + targetId, diagnostics.asJava, true) + + if (originId.nonEmpty) { params.setOriginId(originId.get) } + diagnosticsParams ++= Seq(params) + } + diagnosticsParams + } + + def getOriginId(params: CompileParams): Option[String] = { + try { + Option(params.getOriginId) + } catch { + case e: Exception => Option.empty[String] + } + } + + def sendCompilationDiagnostics(problems: Array[Problem], targetId: BuildTargetIdentifier, compileParams: CompileParams) = { + for (publishDiagnosticsParams <- + getDiagnostics(problems, targetId, getOriginId(compileParams))) { + client.onBuildPublishDiagnostics(publishDiagnosticsParams) + } + } + + def getCompilationLogger: ManagedLogger = { + val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut( + mill.util.DummyLogger.outputStream + )) + val l = LogExchange.logger("Hello") + LogExchange.unbindLoggerAppenders("Hello") + LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Info) :: Nil) + l + } + //TODO: send task notifications - start, progress and finish //TODO: if the client wants to give compilation arguments and the module // already has some from the build file, what to do? @@ -229,9 +361,10 @@ class MillBuildServer(evaluator: Evaluator, var compileTime = 0 for (targetId <- compileParams.getTargets.asScala) { if (moduleToTarget(targetIdToModule(targetId)).getCapabilities.getCanCompile) { - var millModule = targetIdToModule(targetId) + val millModule = targetIdToModule(targetId) //millModule.javacOptions = compileParams.getArguments.asScala val compileTask = millModule.compile + // send notification to client that compilation of this target started val taskStartParams = new TaskStartParams(new TaskId(compileTask.hashCode().toString)) taskStartParams.setEventTime(System.currentTimeMillis()) @@ -240,8 +373,13 @@ class MillBuildServer(evaluator: Evaluator, taskStartParams.setData(new CompileTask(targetId)) client.onBuildTaskStart(taskStartParams) - val result = millEvaluator.evaluate(Strict.Agg(compileTask)) + val result = millEvaluator.evaluate(Strict.Agg(compileTask), + Option(new BspLoggedReporter(client, + targetId, + getOriginId(compileParams), + 10, getCompilationLogger))) val endTime = System.currentTimeMillis() + compileTime += result.timings.map(timingTuple => timingTuple._2).sum var statusCode = StatusCode.OK diff --git a/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala b/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala index 266d832a..a3202aab 100644 --- a/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala +++ b/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala @@ -51,6 +51,9 @@ object ModuleUtils { supportedLanguages.asJava, dependencies, capabilities) + if (module.isInstanceOf[ScalaModule]) { + buildTarget.setDataKind("scala") + } buildTarget.setData(dataBuildTarget) buildTarget.setDisplayName(module.millModuleSegments.last.value.toList.head.pathSegments.head) buildTarget.setBaseDirectory(module.millSourcePath.toNIO.toAbsolutePath.toUri.toString) diff --git a/main/api/src/mill/api/Ctx.scala b/main/api/src/mill/api/Ctx.scala index 69d01f7e..7d081d6a 100644 --- a/main/api/src/mill/api/Ctx.scala +++ b/main/api/src/mill/api/Ctx.scala @@ -2,8 +2,8 @@ package mill.api import scala.annotation.{StaticAnnotation, compileTimeOnly} import scala.language.implicitConversions - import os.Path +import sbt.internal.inc.ManagedLoggedReporter /** * Provides access to various resources in the context of a currently execution Target. @@ -60,7 +60,8 @@ class Ctx( dest0: () => os.Path, val log: Logger, val home: os.Path, - val env: Map[String, String] + val env: Map[String, String], + val reporter: Option[ManagedLoggedReporter] ) extends Ctx.Dest with Ctx.Log diff --git a/main/core/src/eval/Evaluator.scala b/main/core/src/eval/Evaluator.scala index f4ec8ff9..22132a8f 100644 --- a/main/core/src/eval/Evaluator.scala +++ b/main/core/src/eval/Evaluator.scala @@ -5,7 +5,6 @@ import java.net.URLClassLoader import scala.collection.JavaConverters._ import scala.collection.mutable import scala.util.control.NonFatal - import ammonite.runtime.SpecialClassLoader import mill.util.Router.EntryPoint import mill.define.{Ctx => _, _} @@ -13,11 +12,15 @@ import mill.api.Result.{Aborted, OuterStack, Success} import mill.util import mill.util._ import mill.api.Strict.Agg +import sbt.internal.inc.ManagedLoggedReporter +import sbt.internal.util.{ConsoleOut, MainAppender} +import sbt.util.LogExchange case class Labelled[T](task: NamedTask[T], segments: Segments){ def format = task match{ case t: Target[T] => Some(t.readWrite.asInstanceOf[upickle.default.ReadWriter[T]]) + case t: PersistentArgs[T] => Some(t.readWrite.asInstanceOf[upickle.default.ReadWriter[T]]) case _ => None } def writer = task match{ @@ -40,7 +43,7 @@ case class Evaluator(home: os.Path, val classLoaderSignHash = classLoaderSig.hashCode() - def evaluate(goals: Agg[Task[_]]): Evaluator.Results = { + def evaluate(goals: Agg[Task[_]], reporter: Option[ManagedLoggedReporter] = Option.empty[ManagedLoggedReporter]): Evaluator.Results = { os.makeDir.all(outPath) val (sortedGroups, transitive) = Evaluator.plan(rootModule, goals) @@ -66,7 +69,8 @@ case class Evaluator(home: os.Path, terminal, group, results, - counterMsg + counterMsg, + reporter ) someTaskFailed = someTaskFailed || newResults.exists(task => !task._2.isInstanceOf[Success[_]]) @@ -111,7 +115,8 @@ case class Evaluator(home: os.Path, def evaluateGroupCached(terminal: Either[Task[_], Labelled[_]], group: Agg[Task[_]], results: collection.Map[Task[_], Result[(Any, Int)]], - counterMsg: String + counterMsg: String, + reporter: Option[ManagedLoggedReporter] ): (collection.Map[Task[_], Result[(Any, Int)]], Seq[Task[_]], Boolean) = { val externalInputsHash = scala.util.hashing.MurmurHash3.orderedHash( @@ -133,7 +138,8 @@ case class Evaluator(home: os.Path, inputsHash, paths = None, maybeTargetLabel = None, - counterMsg = counterMsg + counterMsg = counterMsg, + reporter ) (newResults, newEvaluated, false) case Right(labelledNamedTask) => @@ -185,7 +191,8 @@ case class Evaluator(home: os.Path, inputsHash, paths = Some(paths), maybeTargetLabel = Some(msgParts.mkString), - counterMsg = counterMsg + counterMsg = counterMsg, + reporter ) newResults(labelledNamedTask.task) match{ @@ -259,7 +266,8 @@ case class Evaluator(home: os.Path, inputsHash: Int, paths: Option[Evaluator.Paths], maybeTargetLabel: Option[String], - counterMsg: String): (mutable.LinkedHashMap[Task[_], Result[(Any, Int)]], mutable.Buffer[Task[_]]) = { + counterMsg: String, + reporter: Option[ManagedLoggedReporter]): (mutable.LinkedHashMap[Task[_], Result[(Any, Int)]], mutable.Buffer[Task[_]]) = { val newEvaluated = mutable.Buffer.empty[Task[_]] @@ -319,9 +327,10 @@ case class Evaluator(home: os.Path, }, multiLogger, home, - env + env, + reporter //new ManagedLoggedReporter(10, logger) ) - + println("Reporter: " + reporter) val out = System.out val in = System.in val err = System.err diff --git a/scalalib/api/src/ZincWorkerApi.scala b/scalalib/api/src/ZincWorkerApi.scala index 53a98c24..e80895d6 100644 --- a/scalalib/api/src/ZincWorkerApi.scala +++ b/scalalib/api/src/ZincWorkerApi.scala @@ -3,6 +3,8 @@ package mill.scalalib.api import mill.api.Loose.Agg import mill.api.PathRef import mill.api.JsonFormatters._ +import sbt.internal.inc._ + object ZincWorkerApi{ type Ctx = mill.api.Ctx.Dest with mill.api.Ctx.Log with mill.api.Ctx.Home } @@ -11,7 +13,8 @@ trait ZincWorkerApi { def compileJava(upstreamCompileOutput: Seq[CompilationResult], sources: Agg[os.Path], compileClasspath: Agg[os.Path], - javacOptions: Seq[String]) + javacOptions: Seq[String], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[CompilationResult] /** Compile a mixed Scala/Java or Scala-only project */ @@ -23,7 +26,8 @@ trait ZincWorkerApi { scalaOrganization: String, scalacOptions: Seq[String], compilerClasspath: Agg[os.Path], - scalacPluginClasspath: Agg[os.Path]) + scalacPluginClasspath: Agg[os.Path], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[CompilationResult] def discoverMainClasses(compilationResult: CompilationResult) diff --git a/scalalib/src/JavaModule.scala b/scalalib/src/JavaModule.scala index b9987ca1..e6c47324 100644 --- a/scalalib/src/JavaModule.scala +++ b/scalalib/src/JavaModule.scala @@ -13,6 +13,9 @@ import mill.modules.Jvm.{createAssembly, createJar} import Lib._ import mill.scalalib.publish.{Artifact, Scope} import mill.api.Loose.Agg +import sbt.internal.inc.ManagedLoggedReporter +import sbt.internal.util.{ConsoleOut, MainAppender} +import sbt.util.LogExchange /** * Core configuration required to compile a single Scala compilation target @@ -209,15 +212,17 @@ trait JavaModule extends mill.Module with TaskModule with GenIdeaModule { outer } yield PathRef(path) } + /** * Compiles the current module to generate compiled classfiles/bytecode */ - def compile: T[mill.scalalib.api.CompilationResult] = T.persistent{ + def compile: T[mill.scalalib.api.CompilationResult] = T.persistent { zincWorker.worker().compileJava( upstreamCompileOutput(), allSourceFiles().map(_.path), compileClasspath().map(_.path), - javacOptions() + javacOptions(), + T.ctx().reporter ) } diff --git a/scalalib/src/ScalaModule.scala b/scalalib/src/ScalaModule.scala index 0ebd5700..5c7a4c97 100644 --- a/scalalib/src/ScalaModule.scala +++ b/scalalib/src/ScalaModule.scala @@ -10,6 +10,9 @@ import mill.scalalib.api.Util.isDotty import Lib._ import mill.api.Loose.Agg import mill.api.DummyInputStream +import sbt.internal.inc.ManagedLoggedReporter +import sbt.internal.util.{ConsoleOut, MainAppender} +import sbt.util.LogExchange /** * Core configuration required to compile a single Scala compilation target @@ -128,7 +131,8 @@ trait ScalaModule extends JavaModule { outer => resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() } - override def compile: T[mill.scalalib.api.CompilationResult] = T.persistent{ + override def compile: T[mill.scalalib.api.CompilationResult] = T.persistent { + zincWorker.worker().compileMixed( upstreamCompileOutput(), allSourceFiles().map(_.path), @@ -139,6 +143,7 @@ trait ScalaModule extends JavaModule { outer => scalacOptions(), scalaCompilerClasspath().map(_.path), scalacPluginClasspath().map(_.path), + T.ctx().reporter ) } diff --git a/scalalib/worker/src/ZincWorkerImpl.scala b/scalalib/worker/src/ZincWorkerImpl.scala index cf37812c..bd61b440 100644 --- a/scalalib/worker/src/ZincWorkerImpl.scala +++ b/scalalib/worker/src/ZincWorkerImpl.scala @@ -4,15 +4,15 @@ import java.io.File import java.util.Optional import scala.ref.WeakReference - import mill.api.Loose.Agg -import mill.api.{KeyedLockedCache, PathRef} +import mill.api.{CompilationAnalysis, KeyedLockedCache, PathRef} import xsbti.compile.{CompilerCache => _, FileAnalysisStore => _, ScalaInstance => _, _} import mill.scalalib.api.Util.{grepJar, isDotty, scalaBinaryVersion} import sbt.internal.inc._ import sbt.internal.util.{ConsoleOut, MainAppender} import sbt.util.LogExchange import mill.scalalib.api.{CompilationResult, ZincWorkerApi} +import upickle.core.Visitor case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { override def analysis(classpathEntry: File): Optional[CompileAnalysis] = am(classpathEntry) @@ -61,7 +61,7 @@ class ZincWorkerImpl(compilerBridge: Either[ scalaVersion, scalaOrganization, compilerClasspath, - scalacPluginClasspath, + scalacPluginClasspath ) { compilers: Compilers => val scaladocClass = compilers.scalac().scalaInstance().loader().loadClass("scala.tools.nsc.ScalaDoc") val scaladocMethod = scaladocClass.getMethod("process", classOf[Array[String]]) @@ -155,20 +155,23 @@ class ZincWorkerImpl(compilerBridge: Either[ def compileJava(upstreamCompileOutput: Seq[CompilationResult], sources: Agg[os.Path], compileClasspath: Agg[os.Path], - javacOptions: Seq[String]) + javacOptions: Seq[String], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[CompilationResult] = { for(res <- compileJava0( upstreamCompileOutput.map(c => (c.analysisFile, c.classes.path)), sources, compileClasspath, - javacOptions + javacOptions, + reporter )) yield CompilationResult(res._1, PathRef(res._2)) } def compileJava0(upstreamCompileOutput: Seq[(os.Path, os.Path)], sources: Agg[os.Path], compileClasspath: Agg[os.Path], - javacOptions: Seq[String]) + javacOptions: Seq[String], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[(os.Path, os.Path)] = { compileInternal( upstreamCompileOutput, @@ -176,7 +179,8 @@ class ZincWorkerImpl(compilerBridge: Either[ compileClasspath, javacOptions, scalacOptions = Nil, - javaOnlyCompilers + javaOnlyCompilers, + reporter ) } @@ -188,7 +192,8 @@ class ZincWorkerImpl(compilerBridge: Either[ scalaOrganization: String, scalacOptions: Seq[String], compilerClasspath: Agg[os.Path], - scalacPluginClasspath: Agg[os.Path]) + scalacPluginClasspath: Agg[os.Path], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[CompilationResult] = { for (res <- compileMixed0( @@ -200,7 +205,8 @@ class ZincWorkerImpl(compilerBridge: Either[ scalaOrganization, scalacOptions, compilerClasspath, - scalacPluginClasspath + scalacPluginClasspath, + reporter )) yield CompilationResult(res._1, PathRef(res._2)) } @@ -212,13 +218,14 @@ class ZincWorkerImpl(compilerBridge: Either[ scalaOrganization: String, scalacOptions: Seq[String], compilerClasspath: Agg[os.Path], - scalacPluginClasspath: Agg[os.Path]) + scalacPluginClasspath: Agg[os.Path], + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[(os.Path, os.Path)] = { withCompilers( scalaVersion, scalaOrganization, compilerClasspath, - scalacPluginClasspath, + scalacPluginClasspath ) {compilers: Compilers => compileInternal( upstreamCompileOutput, @@ -226,7 +233,8 @@ class ZincWorkerImpl(compilerBridge: Either[ compileClasspath, javacOptions, scalacOptions = scalacPluginClasspath.map(jar => s"-Xplugin:$jar").toSeq ++ scalacOptions, - compilers + compilers, + reporter ) } } @@ -298,7 +306,8 @@ class ZincWorkerImpl(compilerBridge: Either[ compileClasspath: Agg[os.Path], javacOptions: Seq[String], scalacOptions: Seq[String], - compilers: Compilers) + compilers: Compilers, + reporter: Option[ManagedLoggedReporter]) (implicit ctx: ZincWorkerApi.Ctx): mill.api.Result[(os.Path, os.Path)] = { os.makeDir.all(ctx.dest) @@ -312,7 +321,10 @@ class ZincWorkerImpl(compilerBridge: Either[ LogExchange.bindLoggerAppenders(id, (consoleAppender -> sbt.util.Level.Info) :: Nil) l } - + val newReporter = reporter match { + case None => new ManagedLoggedReporter(10, logger) + case r: Option[ManagedLoggedReporter] => r.get + } val analysisMap0 = upstreamCompileOutput.map(_.swap).toMap def analysisMap(f: File): Optional[CompileAnalysis] = { @@ -350,7 +362,7 @@ class ZincWorkerImpl(compilerBridge: Either[ zincIOFile, new FreshCompilerCache, IncOptions.of(), - new ManagedLoggedReporter(10, logger), + newReporter,//new ManagedLoggedReporter(10, logger), None, Array() ), @@ -372,7 +384,6 @@ class ZincWorkerImpl(compilerBridge: Either[ newResult.setup() ) ) - mill.api.Result.Success((zincFile, classesDir)) }catch{case e: CompileFailed => mill.api.Result.Failure(e.toString)} } diff --git a/scratch/build.sc b/scratch/build.sc index 817f68e4..c36b554f 100644 --- a/scratch/build.sc +++ b/scratch/build.sc @@ -1,9 +1,9 @@ import mill._, scalalib._ -import $ivy.`com.lihaoyi::mill-contrib-bsp:0.4.1-7-be21ae-DIRTY1fe41d7a` +//import $ivy.`com.lihaoyi::mill-contrib-bsp:0.4.1-7-be21ae-DIRTY1fe41d7a` object mill_exercise extends ScalaModule { def scalaVersion = "2.12.8" - + def mainClass = Some("mill_exercise.Compiler") def ivyDeps = Agg( ivy"org.scalameta::metals:0.5.2", ivy"org.scalameta::scalameta:4.1.9", |