summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamvel Abrahamyan <samvel1024@gmail.com>2019-10-08 12:00:28 +0200
committerSamvel Abrahamyan <samvel1024@gmail.com>2019-10-12 14:33:17 +0200
commit2269dbfca8b1118ec7f89abeb52e70a88376432c (patch)
tree024ecc61705c53c28d0fcc306b7e14c4ab80ef87
parentfc9b6e8b573fb2ad61801d0f335a05f07e3a2d83 (diff)
downloadmill-2269dbfca8b1118ec7f89abeb52e70a88376432c.tar.gz
mill-2269dbfca8b1118ec7f89abeb52e70a88376432c.tar.bz2
mill-2269dbfca8b1118ec7f89abeb52e70a88376432c.zip
Reformat code
-rw-r--r--contrib/bsp/src/mill/contrib/BSP.scala78
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala104
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala47
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/MillBspLogger.scala1
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala487
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala186
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/TaskParameters.scala20
-rw-r--r--main/api/src/mill/api/Ctx.scala14
8 files changed, 493 insertions, 444 deletions
diff --git a/contrib/bsp/src/mill/contrib/BSP.scala b/contrib/bsp/src/mill/contrib/BSP.scala
index d31eb7f4..ab432743 100644
--- a/contrib/bsp/src/mill/contrib/BSP.scala
+++ b/contrib/bsp/src/mill/contrib/BSP.scala
@@ -1,17 +1,16 @@
package mill.contrib
-import java.io.{File, PrintWriter}
-
-import play.api.libs.json._
+import java.io.PrintWriter
import java.nio.file.FileAlreadyExistsException
import java.util.concurrent.Executors
-import upickle.default._
import ch.epfl.scala.bsp4j._
import mill._
import mill.define.{Command, Discover, ExternalModule}
import mill.eval.Evaluator
import org.eclipse.lsp4j.jsonrpc.Launcher
+import play.api.libs.json._
+import upickle.default._
import scala.collection.JavaConverters._
import scala.concurrent.CancellationException
@@ -26,35 +25,6 @@ object BSP extends ExternalModule {
val bspVersion = "2.0.0"
val languages = List("scala", "java")
- // computes the path to the java executable
- def whichJava: String = {
- if (scala.sys.props.contains("JAVA_HOME")) scala.sys.props("JAVA_HOME") else "java"
- }
-
- // creates a Json with the BSP connection details
- def createBspConnectionJson(): JsValue = {
-
- implicit val connectionWrites = new Writes[BspConnectionDetails] {
- def writes(connection: BspConnectionDetails) = Json.obj(
- "name" -> connection.getName,
- "argv" -> new JsArray(connection.getArgv.asScala.map(string => JsString(string)).toIndexedSeq),
- "version" -> connection.getVersion,
- "bspVersion" -> connection.getBspVersion,
- "languages" -> new JsArray(connection.getLanguages.asScala.map(string => JsString(string)).toIndexedSeq)
- )
- }
- val millPath = scala.sys.props("MILL_CLASSPATH")
- Json.toJson(new BspConnectionDetails("mill-bsp",
- List(whichJava,"-DMILL_CLASSPATH=" + millPath,
- s"-DMILL_VERSION=${scala.sys.props("MILL_VERSION")}",
- "-Djna.nosys=true", "-cp",
- millPath,
- "mill.MillMain", "mill.contrib.BSP/start").asJava,
- version,
- bspVersion,
- languages.asJava))
- }
-
/**
* Installs the mill-bsp server. It creates a json file
* with connection details in the ./.bsp directory for
@@ -70,9 +40,9 @@ object BSP extends ExternalModule {
* printed to stdout.
*
*/
- def install(ev: Evaluator): Command[Unit] = T.command{
+ def install(ev: Evaluator): Command[Unit] = T.command {
val bspDirectory = os.pwd / ".bsp"
- if (! os.exists(bspDirectory)) os.makeDir.all(bspDirectory)
+ if (!os.exists(bspDirectory)) os.makeDir.all(bspDirectory)
try {
os.write(bspDirectory / "mill.json", Json.stringify(createBspConnectionJson()))
} catch {
@@ -81,23 +51,53 @@ object BSP extends ExternalModule {
os.remove(bspDirectory / "mill.json")
os.write(bspDirectory / "mill.json", Json.stringify(createBspConnectionJson()))
case e: Exception => println("An exception occurred while installing mill-bsp: " + e.getMessage +
- " " + e.getStackTrace.toString)
+ " " + e.getStackTrace.toString)
}
}
+ // creates a Json with the BSP connection details
+ def createBspConnectionJson(): JsValue = {
+
+ implicit val connectionWrites = new Writes[BspConnectionDetails] {
+ def writes(connection: BspConnectionDetails) = Json.obj(
+ "name" -> connection.getName,
+ "argv" -> new JsArray(connection.getArgv.asScala.map(string => JsString(string)).toIndexedSeq),
+ "version" -> connection.getVersion,
+ "bspVersion" -> connection.getBspVersion,
+ "languages" -> new JsArray(connection.getLanguages.asScala.map(string => JsString(string)).toIndexedSeq)
+ )
+ }
+ val millPath = scala.sys.props("MILL_CLASSPATH")
+ Json.toJson(new BspConnectionDetails("mill-bsp",
+ List(whichJava, "-DMILL_CLASSPATH=" + millPath,
+ s"-DMILL_VERSION=${scala.sys.props("MILL_VERSION")}",
+ "-Djna.nosys=true", "-cp",
+ millPath,
+ "mill.MillMain", "mill.contrib.BSP/start").asJava,
+ version,
+ bspVersion,
+ languages.asJava))
+ }
+
+ // computes the path to the java executable
+ def whichJava: String = {
+ if (scala.sys.props.contains("JAVA_HOME")) scala.sys.props("JAVA_HOME") else "java"
+ }
+
/**
* Computes a mill command which starts the mill-bsp
* server and establishes connection to client. Waits
* until a client connects and ends the connection
* after the client sent an "exit" notification
+ *
* @param ev Environment, used by mill to evaluate commands
* @return: mill.Command which executes the starting of the
- * server
+ * server
*/
def start(ev: Evaluator): Command[Unit] = T.command {
val eval = new Evaluator(ev.home, ev.outPath, ev.externalOutPath, ev.rootModule, ev.log, ev.classLoaderSig,
- ev.workerCache, ev.env, false)
+ ev.workerCache, ev.env, false)
val millServer = new mill.contrib.bsp.MillBuildServer(eval, bspVersion, version, languages)
val executor = Executors.newCachedThreadPool()
@@ -109,7 +109,7 @@ object BSP extends ExternalModule {
.setInput(stdin)
.setLocalService(millServer)
.setRemoteInterface(classOf[BuildClient]).
- traceMessages(new PrintWriter((os.pwd/ "bsp.log" ).toIO))
+ traceMessages(new PrintWriter((os.pwd / "bsp.log").toIO))
.setExecutorService(executor)
.create()
millServer.onConnectWithClient(launcher.getRemoteProxy)
diff --git a/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala b/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala
index b4f0260d..3e65b648 100644
--- a/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala
@@ -6,7 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger
import ch.epfl.scala.bsp4j._
import ch.epfl.scala.{bsp4j => bsp}
-import mill.api.{Info, Problem, Warn, BuildProblemReporter}
+import mill.api.{BuildProblemReporter, Problem}
import scala.collection.JavaConverters._
import scala.collection.concurrent
@@ -17,11 +17,11 @@ import scala.language.implicitConversions
* for each problem it logs, either as information, warning or
* error as well as task finish notifications of type `compile-report`.
*
- * @param client the client to send diagnostics to
- * @param targetId the target id of the target whose compilation
- * the diagnostics are related to
- * @param taskId a unique id of the compilation task of the target
- * specified by `targetId`
+ * @param client the client to send diagnostics to
+ * @param targetId the target id of the target whose compilation
+ * the diagnostics are related to
+ * @param taskId a unique id of the compilation task of the target
+ * specified by `targetId`
* @param compilationOriginId optional origin id the client assigned to
* the compilation request. Needs to be sent
* back as part of the published diagnostics
@@ -48,25 +48,6 @@ class BspLoggedReporter(client: bsp.BuildClient,
infos.incrementAndGet()
}
- override def logWarning(problem: Problem): Unit = {
- client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId))
- warnings.incrementAndGet()
- }
-
- override def printSummary(): Unit = {
- val taskFinishParams = new TaskFinishParams(taskId, getStatusCode)
- taskFinishParams.setEventTime(System.currentTimeMillis())
- taskFinishParams.setMessage("Finished compiling target: " + targetId.getUri)
- taskFinishParams.setDataKind("compile-report")
- val compileReport = new CompileReport(targetId, errors.get, warnings.get)
- compilationOriginId match {
- case Some(id) => compileReport.setOriginId(id)
- case None =>
- }
- taskFinishParams.setData(compileReport)
- client.onBuildTaskFinish(taskFinishParams)
- }
-
// Obtains the parameters for sending diagnostics about the given Problem ( as well as
// about all previous problems generated for the same text file ) related to the specified
// targetId, incorporating the given optional originId ( generated by the client for the
@@ -74,27 +55,24 @@ class BspLoggedReporter(client: bsp.BuildClient,
//TODO: document that if the problem is a general information without a text document
// associated to it, then the document field of the diagnostic is set to the uri of the target
private[this] def getDiagnostics(problem: Problem, targetId: bsp.BuildTargetIdentifier, originId: Option[String]):
- bsp.PublishDiagnosticsParams = {
- val diagnostic = getSingleDiagnostic(problem)
- val sourceFile = problem.position.sourceFile
- val textDocument = new TextDocumentIdentifier(
- sourceFile.getOrElse(None) match {
+ bsp.PublishDiagnosticsParams = {
+ val diagnostic = getSingleDiagnostic(problem)
+ val sourceFile = problem.position.sourceFile
+ val textDocument = new TextDocumentIdentifier(
+ sourceFile.getOrElse(None) match {
case None => targetId.getUri
case f: File => f.toURI.toString
})
- val params = new bsp.PublishDiagnosticsParams(textDocument,
- targetId,
- appendDiagnostics(textDocument, diagnostic).asJava,
- true)
+ val params = new bsp.PublishDiagnosticsParams(textDocument,
+ targetId,
+ appendDiagnostics(textDocument, diagnostic).asJava,
+ true)
- if (originId.nonEmpty) { params.setOriginId(originId.get) }
- diagnosticMap.put(textDocument, params)
- params
+ if (originId.nonEmpty) {
+ params.setOriginId(originId.get)
}
-
- // Compute the compilation status code
- private[this] def getStatusCode: StatusCode = {
- if (errors.get > 0) StatusCode.ERROR else StatusCode.OK
+ diagnosticMap.put(textDocument, params)
+ params
}
// Update the published diagnostics for the fiven text file by
@@ -103,14 +81,14 @@ class BspLoggedReporter(client: bsp.BuildClient,
private[this] def appendDiagnostics(textDocument: TextDocumentIdentifier,
currentDiagnostic: Diagnostic): List[Diagnostic] = {
diagnosticMap.putIfAbsent(textDocument, new bsp.PublishDiagnosticsParams(
- textDocument,
- targetId,
- List.empty[Diagnostic].asJava, true))
+ textDocument,
+ targetId,
+ List.empty[Diagnostic].asJava, true))
diagnosticMap(textDocument).getDiagnostics.asScala.toList ++ List(currentDiagnostic)
}
// Computes the diagnostic related to the given Problem
- private[this] def getSingleDiagnostic(problem: Problem): Diagnostic ={
+ private[this] def getSingleDiagnostic(problem: Problem): Diagnostic = {
val pos = problem.position
val i: Integer = pos.startLine.orElse(pos.line).getOrElse[Int](0)
println(i)
@@ -123,12 +101,36 @@ class BspLoggedReporter(client: bsp.BuildClient,
val diagnostic = new bsp.Diagnostic(new bsp.Range(start, end), problem.message)
diagnostic.setCode(pos.lineContent)
diagnostic.setSource("compiler from mill")
- diagnostic.setSeverity( problem.severity match {
- case mill.api.Info => bsp.DiagnosticSeverity.INFORMATION
- case mill.api.Error => bsp.DiagnosticSeverity.ERROR
- case mill.api.Warn => bsp.DiagnosticSeverity.WARNING
- }
- )
+ diagnostic.setSeverity(problem.severity match {
+ case mill.api.Info => bsp.DiagnosticSeverity.INFORMATION
+ case mill.api.Error => bsp.DiagnosticSeverity.ERROR
+ case mill.api.Warn => bsp.DiagnosticSeverity.WARNING
+ }
+ )
diagnostic
}
+
+ override def logWarning(problem: Problem): Unit = {
+ client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId))
+ warnings.incrementAndGet()
+ }
+
+ override def printSummary(): Unit = {
+ val taskFinishParams = new TaskFinishParams(taskId, getStatusCode)
+ taskFinishParams.setEventTime(System.currentTimeMillis())
+ taskFinishParams.setMessage("Finished compiling target: " + targetId.getUri)
+ taskFinishParams.setDataKind("compile-report")
+ val compileReport = new CompileReport(targetId, errors.get, warnings.get)
+ compilationOriginId match {
+ case Some(id) => compileReport.setOriginId(id)
+ case None =>
+ }
+ taskFinishParams.setData(compileReport)
+ client.onBuildTaskFinish(taskFinishParams)
+ }
+
+ // Compute the compilation status code
+ private[this] def getStatusCode: StatusCode = {
+ if (errors.get > 0) StatusCode.ERROR else StatusCode.OK
+ }
}
diff --git a/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala b/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
index 9681313a..922e26eb 100644
--- a/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
@@ -10,12 +10,13 @@ import sbt.testing._
/**
* Context class for BSP, specialized for sending `task-start` and
* `task-finish` notifications for every test being ran.
- * @param client The client to send notifications to
- * @param targetId The targetId of the BSP target for which
- * the test request is being processed
- * @param taskId The unique taskId associated with the
- * test task that will trigger this reporter
- * to log testing events.
+ *
+ * @param client The client to send notifications to
+ * @param targetId The targetId of the BSP target for which
+ * the test request is being processed
+ * @param taskId The unique taskId associated with the
+ * test task that will trigger this reporter
+ * to log testing events.
* @param arguments compilation arguments as part of the BSP context,
* in case special arguments need to be passed to
* the compiler before running the test task.
@@ -42,14 +43,26 @@ class BspTestReporter(
client.onBuildTaskStart(taskStartParams)
}
+ // Compute the display name of the test / test suite
+ // to which the given event relates
+ private[this] def getDisplayName(e: Event): String = {
+ e.selector() match {
+ case s: NestedSuiteSelector => s.suiteId()
+ case s: NestedTestSelector => s.suiteId() + "." + s.testName()
+ case s: SuiteSelector => s.toString
+ case s: TestSelector => s.testName()
+ case s: TestWildcardSelector => s.testWildcard()
+ }
+ }
+
override def logFinish(event: Event): Unit = {
totalTime += event.duration()
val taskFinishParams = new TaskFinishParams(taskId,
- event.status() match {
- case sbt.testing.Status.Canceled => StatusCode.CANCELLED
- case sbt.testing.Status.Error => StatusCode.ERROR
- case default => StatusCode.OK
- })
+ event.status() match {
+ case sbt.testing.Status.Canceled => StatusCode.CANCELLED
+ case sbt.testing.Status.Error => StatusCode.ERROR
+ case default => StatusCode.OK
+ })
val status = event.status match {
case sbt.testing.Status.Success =>
passed += 1
@@ -92,18 +105,6 @@ class BspTestReporter(
sw.toString
}
- // Compute the display name of the test / test suite
- // to which the given event relates
- private[this] def getDisplayName(e: Event): String = {
- e.selector() match{
- case s: NestedSuiteSelector => s.suiteId()
- case s: NestedTestSelector => s.suiteId() + "." + s.testName()
- case s: SuiteSelector => s.toString
- case s: TestSelector => s.testName()
- case s: TestWildcardSelector => s.testWildcard()
- }
- }
-
// Compute the test report data structure that will go into
// the task finish notification after all tests are ran.
def getTestReport: TestReport = {
diff --git a/contrib/bsp/src/mill/contrib/bsp/MillBspLogger.scala b/contrib/bsp/src/mill/contrib/bsp/MillBspLogger.scala
index a17c4a40..12638bed 100644
--- a/contrib/bsp/src/mill/contrib/bsp/MillBspLogger.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/MillBspLogger.scala
@@ -10,6 +10,7 @@ import mill.util.ProxyLogger
* notifications ( upon the invocation of the `ticker` method ) and
* `show-message` notifications ( for each error or information
* being logged ).
+ *
* @param client the client to send notifications to, also the
* client that initiated a request which triggered
* a mill task evaluation
diff --git a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala
index 40e98ef7..95eb43cd 100644
--- a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala
@@ -5,7 +5,7 @@ import java.util.concurrent.CompletableFuture
import ch.epfl.scala.bsp4j._
import com.google.gson.JsonObject
import mill.api.Result.{Skipped, Success}
-import mill.api.{DummyTestReporter, Result, Strict, BuildProblemReporter}
+import mill.api.{BuildProblemReporter, DummyTestReporter, Result, Strict}
import mill.contrib.bsp.ModuleUtils._
import mill.define.Segment.Label
import mill.define.{Discover, ExternalModule}
@@ -26,37 +26,36 @@ import scala.collection.JavaConverters._
class MillBuildServer(evaluator: Evaluator,
_bspVersion: String,
- serverVersion:String,
- languages: List[String]) extends ExternalModule with BuildServer with ScalaBuildServer {
+ serverVersion: String,
+ languages: List[String]) extends ExternalModule with BuildServer with ScalaBuildServer {
implicit def millScoptEvaluatorReads[T]: EvaluatorScopt[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
- var cancelator: () => Unit = () => ()
val millEvaluator: Evaluator = evaluator
+ val ctx: Ctx.Log with Ctx.Home = new Ctx.Log with Ctx.Home {
+ val log: DummyLogger.type = mill.util.DummyLogger
+ val home: Path = os.pwd
+ }
+ var cancelator: () => Unit = () => ()
var rootModule: JavaModule = ModuleUtils.getRootJavaModule(evaluator.rootModule)
var millModules: Seq[JavaModule] = getMillModules(millEvaluator)
var client: BuildClient = _
var moduleToTargetId: Predef.Map[JavaModule, BuildTargetIdentifier] = ModuleUtils.getModuleTargetIdMap(
- millModules,
- evaluator
- )
+ millModules,
+ evaluator
+ )
var targetIdToModule: Predef.Map[BuildTargetIdentifier, JavaModule] = targetToModule(moduleToTargetId)
var moduleToTarget: Predef.Map[JavaModule, BuildTarget] =
- ModuleUtils.millModulesToBspTargets(millModules, rootModule, evaluator, List("scala", "java"))
+ ModuleUtils.millModulesToBspTargets(millModules, rootModule, evaluator, List("scala", "java"))
var moduleCodeToTargetId: Predef.Map[Int, BuildTargetIdentifier] =
- for ( (targetId, module) <- targetIdToModule ) yield (module.hashCode(), targetId)
-
+ for ((targetId, module) <- targetIdToModule) yield (module.hashCode(), targetId)
var initialized = false
var clientInitialized = false
- val ctx: Ctx.Log with Ctx.Home = new Ctx.Log with Ctx.Home {
- val log: DummyLogger.type = mill.util.DummyLogger
- val home: Path = os.pwd
- }
-
override def onConnectWithClient(server: BuildClient): Unit =
client = server
@@ -89,14 +88,15 @@ class MillBuildServer(evaluator: Evaluator,
}
override def workspaceBuildTargets(): CompletableFuture[WorkspaceBuildTargetsResult] = {
- recomputeTargets()
- handleExceptions[String, WorkspaceBuildTargetsResult](
- _ => new WorkspaceBuildTargetsResult(moduleToTarget.values.toList.asJava),
- "")
+ recomputeTargets()
+ handleExceptions[String, WorkspaceBuildTargetsResult](
+ _ => new WorkspaceBuildTargetsResult(moduleToTarget.values.toList.asJava),
+ "")
}
override def buildTargetSources(sourcesParams: SourcesParams): CompletableFuture[SourcesResult] = {
recomputeTargets()
+
def computeSourcesResult: SourcesResult = {
var items = List[SourcesItem]()
@@ -104,11 +104,11 @@ class MillBuildServer(evaluator: Evaluator,
var itemSources = List[SourceItem]()
val sources = evaluateInformativeTask(evaluator, targetIdToModule(targetId).sources, Agg.empty[PathRef]).
- map(pathRef => pathRef.path).toSeq
+ map(pathRef => pathRef.path).toSeq
val generatedSources = evaluateInformativeTask(evaluator,
- targetIdToModule(targetId).generatedSources,
- Agg.empty[PathRef]).
- map(pathRef => pathRef.path).toSeq
+ targetIdToModule(targetId).generatedSources,
+ Agg.empty[PathRef]).
+ map(pathRef => pathRef.path).toSeq
for (source <- sources) {
itemSources ++= List(
@@ -125,28 +125,31 @@ class MillBuildServer(evaluator: Evaluator,
new SourcesResult(items.asJava)
}
+
handleExceptions[String, SourcesResult](_ => computeSourcesResult, "")
}
override def buildTargetInverseSources(inverseSourcesParams: InverseSourcesParams):
- CompletableFuture[InverseSourcesResult] = {
+ CompletableFuture[InverseSourcesResult] = {
recomputeTargets()
def getInverseSourcesResult: InverseSourcesResult = {
val textDocument = inverseSourcesParams.getTextDocument
val targets = millModules.filter(m => ModuleUtils.evaluateInformativeTask(
- millEvaluator, m.allSourceFiles, Seq.empty[PathRef]).
- map(pathRef => pathRef.path.toIO.toURI.toString).
- contains(textDocument.getUri)).
- map(m => moduleToTargetId(m))
+ millEvaluator, m.allSourceFiles, Seq.empty[PathRef]).
+ map(pathRef => pathRef.path.toIO.toURI.toString).
+ contains(textDocument.getUri)).
+ map(m => moduleToTargetId(m))
new InverseSourcesResult(targets.asJava)
}
+
handleExceptions[String, InverseSourcesResult](_ => getInverseSourcesResult, "")
}
override def buildTargetDependencySources(dependencySourcesParams: DependencySourcesParams):
- CompletableFuture[DependencySourcesResult] = {
+ CompletableFuture[DependencySourcesResult] = {
recomputeTargets()
+
def getDependencySources: DependencySourcesResult = {
var items = List[DependencySourcesItem]()
@@ -155,117 +158,136 @@ class MillBuildServer(evaluator: Evaluator,
var sources = evaluateInformativeTask(evaluator,
millModule.resolveDeps(millModule.transitiveIvyDeps),
Agg.empty[PathRef]) ++
- evaluateInformativeTask(evaluator,
- millModule.resolveDeps(millModule.compileIvyDeps),
- Agg.empty[PathRef]) ++
- evaluateInformativeTask(evaluator,
- millModule.unmanagedClasspath,
- Agg.empty[PathRef])
+ evaluateInformativeTask(evaluator,
+ millModule.resolveDeps(millModule.compileIvyDeps),
+ Agg.empty[PathRef]) ++
+ evaluateInformativeTask(evaluator,
+ millModule.unmanagedClasspath,
+ Agg.empty[PathRef])
millModule match {
case _: ScalaModule => sources ++= evaluateInformativeTask(evaluator,
- millModule.resolveDeps(millModule.asInstanceOf[ScalaModule].scalaLibraryIvyDeps),
- Agg.empty[PathRef])
+ millModule.resolveDeps(millModule.asInstanceOf[ScalaModule].scalaLibraryIvyDeps),
+ Agg.empty[PathRef])
case _: JavaModule => sources ++= List()
}
items ++= List(new DependencySourcesItem(targetId, sources.
- map(pathRef => pathRef.path.toIO.toURI.toString).
- toList.asJava))
+ map(pathRef => pathRef.path.toIO.toURI.toString).
+ toList.asJava))
}
new DependencySourcesResult(items.asJava)
}
+
handleExceptions[String, DependencySourcesResult](_ => getDependencySources, "")
}
+ // Recompute the modules in the project in case any changes to the build took place
+ // and update all the mappings that depend on this info
+ private[this] def recomputeTargets(): Unit = {
+ rootModule = ModuleUtils.getRootJavaModule(millEvaluator.rootModule)
+ millModules = getMillModules(millEvaluator)
+ moduleToTargetId = ModuleUtils.getModuleTargetIdMap(millModules, millEvaluator)
+ targetIdToModule = targetToModule(moduleToTargetId)
+ moduleToTarget = ModuleUtils.millModulesToBspTargets(millModules, rootModule, evaluator, List("scala", "java"))
+ }
+
+ // Given the mapping from modules to targetIds, construct the mapping from targetIds to modules
+ private[this] def targetToModule(moduleToTargetId: Predef.Map[JavaModule, BuildTargetIdentifier]):
+ Predef.Map[BuildTargetIdentifier, JavaModule] = {
+ moduleToTargetId.keys.map(mod => (moduleToTargetId(mod), mod)).toMap
+
+ }
+
+ // Resolve all the mill modules contained in the project
+ private[this] def getMillModules(ev: Evaluator): Seq[JavaModule] = {
+ ev.rootModule.millInternal.segmentsToModules.values.
+ collect {
+ case m: scalalib.JavaModule => m
+ }.toSeq ++ Seq(rootModule)
+ }
+
+ // Given a function that take input of type T and return output of type V,
+ // apply the function on the given inputs and return a completable future of
+ // the result. If the execution of the function raises an Exception, complete
+ // the future exceptionally. Also complete exceptionally if the server was not
+ // yet initialized.
+ private[this] def handleExceptions[T, V](serverMethod: T => V, input: T): CompletableFuture[V] = {
+ val future = new CompletableFuture[V]()
+ if (initialized) {
+ try {
+ future.complete(serverMethod(input))
+ } catch {
+ case e: Exception => future.completeExceptionally(e)
+ }
+ } else {
+ future.completeExceptionally(
+ new Exception("Can not respond to any request before receiving the `initialize` request.")
+ )
+ }
+ future
+ }
+
override def buildTargetResources(resourcesParams: ResourcesParams): CompletableFuture[ResourcesResult] = {
recomputeTargets()
+
def getResources: ResourcesResult = {
var items = List[ResourcesItem]()
for (targetId <- resourcesParams.getTargets.asScala) {
val millModule = targetIdToModule(targetId)
val resources = evaluateInformativeTask(evaluator, millModule.resources, Agg.empty[PathRef]).
- filter(pathRef => os.exists(pathRef.path)).
- flatMap(pathRef => os.walk(pathRef.path)).
- map(path => path.toIO.toURI.toString).
- toList.asJava
+ filter(pathRef => os.exists(pathRef.path)).
+ flatMap(pathRef => os.walk(pathRef.path)).
+ map(path => path.toIO.toURI.toString).
+ toList.asJava
items ++= List(new ResourcesItem(targetId, resources))
}
new ResourcesResult(items.asJava)
}
- handleExceptions[String, ResourcesResult](_ => getResources, "")
- }
- // construct the ManagedLogger that will go into the compilation problems reporter
- private[this] def getCompilationLogger: ManagedLogger = {
- val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut(
- millEvaluator.log.outputStream
- ))
- val l = LogExchange.logger("Hello")
- LogExchange.unbindLoggerAppenders("Hello")
- LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Info) :: Nil)
- l
- }
-
- // define the function that spawns compilation reporter for each module based on the
- // module's hash code TODO: find something more reliable than the hash code
- private[this] def getBspLoggedReporterPool(params: Parameters, taskStartMessage: String => String,
- taskStartDataKind: String, taskStartData: BuildTargetIdentifier => Object):
- Int => Option[BuildProblemReporter] = {
- int: Int =>
- if (moduleCodeToTargetId.contains(int)) {
- val targetId = moduleCodeToTargetId(int)
- val taskId = new TaskId(targetIdToModule(targetId).compile.hashCode.toString)
- val taskStartParams = new TaskStartParams(taskId)
- taskStartParams.setEventTime(System.currentTimeMillis())
- taskStartParams.setData(taskStartData(targetId))
- taskStartParams.setDataKind(taskStartDataKind)
- taskStartParams.setMessage(taskStartMessage(moduleToTarget(targetIdToModule(targetId)).getDisplayName))
- client.onBuildTaskStart(taskStartParams)
- Option(new BspLoggedReporter(client,
- targetId,
- taskId,
- params.getOriginId))}
- else None
+ handleExceptions[String, ResourcesResult](_ => getResources, "")
}
//TODO: if the client wants to give compilation arguments and the module
// already has some from the build file, what to do?
override def buildTargetCompile(compileParams: CompileParams): CompletableFuture[CompileResult] = {
recomputeTargets()
+
def getCompileResult: CompileResult = {
val params = TaskParameters.fromCompileParams(compileParams)
val taskId = params.hashCode()
val compileTasks = Strict.Agg(params.getTargets.
- filter(targetId => targetId != moduleToTarget(rootModule).getId).
- map(targetId => targetIdToModule(targetId).compile):_*)
+ filter(targetId => targetId != moduleToTarget(rootModule).getId).
+ map(targetId => targetIdToModule(targetId).compile): _*)
val result = millEvaluator.evaluate(compileTasks,
- getBspLoggedReporterPool(params, t => s"Started compiling target: $t",
- TaskDataKind.COMPILE_TASK, (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
- DummyTestReporter,
- new MillBspLogger(client, taskId, millEvaluator.log)
- )
+ getBspLoggedReporterPool(params, t => s"Started compiling target: $t",
+ TaskDataKind.COMPILE_TASK, (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
+ DummyTestReporter,
+ new MillBspLogger(client, taskId, millEvaluator.log)
+ )
val compileResult = new CompileResult(getStatusCode(result))
compileResult.setOriginId(compileParams.getOriginId)
compileResult //TODO: See in what form IntelliJ expects data about products of compilation in order to set data field
}
+
handleExceptions[String, CompileResult](_ => getCompileResult, "")
}
override def buildTargetRun(runParams: RunParams): CompletableFuture[RunResult] = {
recomputeTargets()
+
def getRunResult: RunResult = {
val params = TaskParameters.fromRunParams(runParams)
val module = targetIdToModule(params.getTargets.head)
val args = params.getArguments.getOrElse(Seq.empty[String])
- val runTask = module.run(args:_*)
+ val runTask = module.run(args: _*)
val runResult = millEvaluator.evaluate(Strict.Agg(runTask),
- getBspLoggedReporterPool(
- params,
- t => s"Started compiling target: $t",
- TaskDataKind.COMPILE_TASK,
- (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
- logger = new MillBspLogger(client, runTask.hashCode(), millEvaluator.log))
+ getBspLoggedReporterPool(
+ params,
+ t => s"Started compiling target: $t",
+ TaskDataKind.COMPILE_TASK,
+ (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
+ logger = new MillBspLogger(client, runTask.hashCode(), millEvaluator.log))
val response = runResult.results(runTask) match {
case _: Result.Success[Any] => new RunResult(StatusCode.OK)
case _ => new RunResult(StatusCode.ERROR)
@@ -276,52 +298,34 @@ class MillBuildServer(evaluator: Evaluator,
}
response
}
- handleExceptions[String, RunResult](_ => getRunResult, "")
- }
-
- private[this] def getStatusCodePerTask(results: Evaluator.Results, task: mill.define.Task[_]): StatusCode = {
- results.results(task) match {
- case _: Success[_] => StatusCode.OK
- case Skipped => StatusCode.CANCELLED
- case _ => StatusCode.ERROR
- }
- }
-
- // Get the execution status code given the results from Evaluator.evaluate
- private[this] 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
+ handleExceptions[String, RunResult](_ => getRunResult, "")
}
override def buildTargetTest(testParams: TestParams): CompletableFuture[TestResult] = {
recomputeTargets()
+
def getTestResult: TestResult = {
val params = TaskParameters.fromTestParams(testParams)
val argsMap = try {
- val scalaTestParams = testParams.getData.asInstanceOf[JsonObject]
- (for (testItem <- scalaTestParams.get("testClasses").getAsJsonArray.asScala)
- yield (
- testItem.getAsJsonObject.get("target").getAsJsonObject.get("uri").getAsString,
- testItem.getAsJsonObject.get("classes").getAsJsonArray
- .asScala.map(elem => elem.getAsString).toSeq)).toMap
- } catch {
- case _: Exception => (for (targetId <- testParams.getTargets.asScala) yield
- (targetId.getUri, Seq.empty[String])).toMap
-
- }
+ val scalaTestParams = testParams.getData.asInstanceOf[JsonObject]
+ (for (testItem <- scalaTestParams.get("testClasses").getAsJsonArray.asScala)
+ yield (
+ testItem.getAsJsonObject.get("target").getAsJsonObject.get("uri").getAsString,
+ testItem.getAsJsonObject.get("classes").getAsJsonArray
+ .asScala.map(elem => elem.getAsString).toSeq)).toMap
+ } catch {
+ case _: Exception => (for (targetId <- testParams.getTargets.asScala) yield
+ (targetId.getUri, Seq.empty[String])).toMap
+
+ }
var overallStatusCode = StatusCode.OK
for (targetId <- testParams.getTargets.asScala) {
val module = targetIdToModule(targetId)
module match {
case m: TestModule => val testModule = m.asInstanceOf[TestModule]
- val testTask = testModule.testLocal(argsMap(targetId.getUri):_*)
+ val testTask = testModule.testLocal(argsMap(targetId.getUri): _*)
// notifying the client that the testing of this build target started
val taskStartParams = new TaskStartParams(new TaskId(testTask.hashCode().toString))
@@ -339,7 +343,7 @@ class MillBuildServer(evaluator: Evaluator,
val results = millEvaluator.evaluate(
Strict.Agg(testTask),
getBspLoggedReporterPool(params, t => s"Started compiling target: $t",
- TaskDataKind.COMPILE_TASK, (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
+ TaskDataKind.COMPILE_TASK, (targetId: BuildTargetIdentifier) => new CompileTask(targetId)),
testReporter,
new MillBspLogger(client, testTask.hashCode, millEvaluator.log))
val endTime = System.currentTimeMillis()
@@ -354,10 +358,10 @@ class MillBuildServer(evaluator: Evaluator,
val taskFinishParams = new TaskFinishParams(
new TaskId(testTask.hashCode().toString),
statusCode
- )
+ )
taskFinishParams.setEventTime(endTime)
taskFinishParams.setMessage("Finished testing target: " +
- moduleToTarget(targetIdToModule(targetId)).getDisplayName)
+ moduleToTarget(targetIdToModule(targetId)).getDisplayName)
taskFinishParams.setDataKind(TaskDataKind.TEST_REPORT)
taskFinishParams.setData(testReporter.getTestReport)
client.onBuildTaskFinish(taskFinishParams)
@@ -369,56 +373,105 @@ class MillBuildServer(evaluator: Evaluator,
params.getOriginId match {
case None => testResult
case Some(id) =>
- //TODO: Add the messages from mill to the data field?
+ //TODO: Add the messages from mill to the data field?
testResult.setOriginId(id)
testResult
}
}
+
handleExceptions[String, TestResult](_ => getTestResult, "")
}
+ // define the function that spawns compilation reporter for each module based on the
+ // module's hash code TODO: find something more reliable than the hash code
+ private[this] def getBspLoggedReporterPool(params: Parameters,
+ taskStartMessage: String => String,
+ taskStartDataKind: String,
+ taskStartData: BuildTargetIdentifier => Object):
+ Int => Option[BuildProblemReporter] = {
+ int: Int =>
+ if (moduleCodeToTargetId.contains(int)) {
+ val targetId = moduleCodeToTargetId(int)
+ val taskId = new TaskId(targetIdToModule(targetId).compile.hashCode.toString)
+ val taskStartParams = new TaskStartParams(taskId)
+ taskStartParams.setEventTime(System.currentTimeMillis())
+ taskStartParams.setData(taskStartData(targetId))
+ taskStartParams.setDataKind(taskStartDataKind)
+ taskStartParams.setMessage(taskStartMessage(moduleToTarget(targetIdToModule(targetId)).getDisplayName))
+ client.onBuildTaskStart(taskStartParams)
+ Option(new BspLoggedReporter(client,
+ targetId,
+ taskId,
+ params.getOriginId))
+ }
+ else None
+ }
+
+ // Get the execution status code given the results from Evaluator.evaluate
+ private[this] 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
+ }
+
+ private[this] def getStatusCodePerTask(results: Evaluator.Results, task: mill.define.Task[_]): StatusCode = {
+ results.results(task) match {
+ case _: Success[_] => StatusCode.OK
+ case Skipped => StatusCode.CANCELLED
+ case _ => StatusCode.ERROR
+ }
+ }
+
override def buildTargetCleanCache(cleanCacheParams: CleanCacheParams): CompletableFuture[CleanCacheResult] = {
- recomputeTargets()
- def getCleanCacheResult: CleanCacheResult = {
- var msg = ""
- var cleaned = true
- for (targetId <- cleanCacheParams.getTargets.asScala) {
- val module = targetIdToModule(targetId)
- val mainModule = new MainModule {
- override implicit def millDiscover: Discover[_] = {
- Discover[this.type]
- }
+ recomputeTargets()
+
+ def getCleanCacheResult: CleanCacheResult = {
+ var msg = ""
+ var cleaned = true
+ for (targetId <- cleanCacheParams.getTargets.asScala) {
+ val module = targetIdToModule(targetId)
+ val mainModule = new MainModule {
+ override implicit def millDiscover: Discover[_] = {
+ Discover[this.type]
}
- val cleanTask = mainModule.clean(millEvaluator, List(s"${module.millModuleSegments.render}.compile"):_*)
- val cleanResult = millEvaluator.evaluate(
- Strict.Agg(cleanTask),
- logger = new MillBspLogger(client, cleanTask.hashCode, millEvaluator.log)
+ }
+ val cleanTask = mainModule.clean(millEvaluator, List(s"${module.millModuleSegments.render}.compile"): _*)
+ val cleanResult = millEvaluator.evaluate(
+ Strict.Agg(cleanTask),
+ logger = new MillBspLogger(client, cleanTask.hashCode, millEvaluator.log)
)
- if (cleanResult.failing.keyCount > 0) {
- cleaned = false
- msg += s" Target ${module.millModuleSegments.render} could not be cleaned. See message from mill: \n"
- cleanResult.results(cleanTask) match {
- case fail: Result.Failure[Any] => msg += fail.msg + "\n"
- case _ => msg += "could not retrieve message"
- }
- } else {
- msg += s"${module.millModuleSegments.render} cleaned \n"
+ if (cleanResult.failing.keyCount > 0) {
+ cleaned = false
+ msg += s" Target ${module.millModuleSegments.render} could not be cleaned. See message from mill: \n"
+ cleanResult.results(cleanTask) match {
+ case fail: Result.Failure[Any] => msg += fail.msg + "\n"
+ case _ => msg += "could not retrieve message"
+ }
+ } else {
+ msg += s"${module.millModuleSegments.render} cleaned \n"
- val outDir = Evaluator.resolveDestPaths(os.pwd / "out", module.millModuleSegments ++
- Seq(Label("compile"))).out
- while (os.exists(outDir)) {
- Thread.sleep(10)
- }
+ val outDir = Evaluator.resolveDestPaths(os.pwd / "out", module.millModuleSegments ++
+ Seq(Label("compile"))).out
+ while (os.exists(outDir)) {
+ Thread.sleep(10)
}
}
- new CleanCacheResult(msg, cleaned)
}
- handleExceptions[String, CleanCacheResult](_ => getCleanCacheResult, "")
+ new CleanCacheResult(msg, cleaned)
}
+ handleExceptions[String, CleanCacheResult](_ => getCleanCacheResult, "")
+ }
+
override def buildTargetScalacOptions(scalacOptionsParams: ScalacOptionsParams):
- CompletableFuture[ScalacOptionsResult] = {
+ CompletableFuture[ScalacOptionsResult] = {
recomputeTargets()
+
def getScalacOptionsResult: ScalacOptionsResult = {
var targetScalacOptions = List.empty[ScalacOptionsItem]
for (targetId <- scalacOptionsParams.getTargets.asScala) {
@@ -429,8 +482,8 @@ class MillBuildServer(evaluator: Evaluator,
val classpath = evaluateInformativeTask(evaluator, m.runClasspath, Agg.empty[PathRef]).
map(pathRef => pathRef.path.toIO.toURI.toString).toList
val classDirectory = (Evaluator.resolveDestPaths(
- os.pwd / "out" ,
- m.millModuleSegments ++ Seq(Label("compile"))).dest / "classes"
+ os.pwd / "out",
+ m.millModuleSegments ++ Seq(Label("compile"))).dest / "classes"
).toIO.toURI.toString
targetScalacOptions ++= List(new ScalacOptionsItem(targetId, options.asJava, classpath.asJava, classDirectory))
@@ -439,6 +492,7 @@ class MillBuildServer(evaluator: Evaluator,
}
new ScalacOptionsResult(targetScalacOptions.asJava)
}
+
handleExceptions[String, ScalacOptionsResult](_ => getScalacOptionsResult, "")
}
@@ -446,8 +500,9 @@ class MillBuildServer(evaluator: Evaluator,
// defined for the same module, do something so that those can still be detected
// such that IntelliJ can run any of them
override def buildTargetScalaMainClasses(scalaMainClassesParams: ScalaMainClassesParams):
- CompletableFuture[ScalaMainClassesResult] = {
+ CompletableFuture[ScalaMainClassesResult] = {
recomputeTargets()
+
def getScalaMainClasses: ScalaMainClassesResult = {
var items = List.empty[ScalaMainClassesItem]
for (targetId <- scalaMainClassesParams.getTargets.asScala) {
@@ -456,10 +511,10 @@ class MillBuildServer(evaluator: Evaluator,
case result: Result.Success[Any] => result.asSuccess.get.value match {
case mainClass: Right[String, String] =>
List(new ScalaMainClass(
- mainClass.value,
- List.empty[String].asJava,
- evaluateInformativeTask(evaluator, module.forkArgs, Seq.empty[String]).
- toList.asJava))
+ mainClass.value,
+ List.empty[String].asJava,
+ evaluateInformativeTask(evaluator, module.forkArgs, Seq.empty[String]).
+ toList.asJava))
case msg: Left[String, String] =>
val messageParams = new ShowMessageParams(MessageType.WARNING, msg.value)
messageParams.setOriginId(scalaMainClassesParams.getOriginId)
@@ -468,96 +523,64 @@ class MillBuildServer(evaluator: Evaluator,
}
case _ => List.empty[ScalaMainClass]
}
- val item = new ScalaMainClassesItem (targetId , scalaMainClasses.asJava)
+ val item = new ScalaMainClassesItem(targetId, scalaMainClasses.asJava)
items ++= List(item)
- }
+ }
new ScalaMainClassesResult(items.asJava)
}
- handleExceptions[String, ScalaMainClassesResult](_ => getScalaMainClasses, "")
- }
- // Detect and return the test classes contained in the given TestModule
- private[this] def getTestClasses(module: TestModule) (implicit ctx: Ctx.Home): Seq[String] = {
- val runClasspath = getTaskResult(millEvaluator, module.runClasspath)
- val frameworks = getTaskResult(millEvaluator, module.testFrameworks)
- val compilationResult = getTaskResult(millEvaluator, module.compile)
-
- (runClasspath, frameworks, compilationResult) match {
- case (Result.Success(classpath), Result.Success(testFrameworks), Result.Success(compResult)) =>
- val classFingerprint = Jvm.inprocess(classpath.asInstanceOf[Seq[PathRef]].map(_.path),
- classLoaderOverrideSbtTesting = true,
- isolated = true,
- closeContextClassLoaderWhenDone = false, cl => {
- val fs = TestRunner.frameworks(testFrameworks.asInstanceOf[Seq[String]])(cl)
- fs.flatMap(framework =>
- discoverTests(cl, framework, Agg(compResult.asInstanceOf[CompilationResult].
- classes.path)))
- })
- classFingerprint.map(classF => classF._1.getName.stripSuffix("$"))
- case _ => Seq.empty[String] //TODO: or send notification that something went wrong
- }
+ handleExceptions[String, ScalaMainClassesResult](_ => getScalaMainClasses, "")
}
override def buildTargetScalaTestClasses(scalaTestClassesParams: ScalaTestClassesParams):
- CompletableFuture[ScalaTestClassesResult] = {
+ CompletableFuture[ScalaTestClassesResult] = {
recomputeTargets()
- def getScalaTestClasses (implicit ctx: Ctx.Home): ScalaTestClassesResult = {
+
+ def getScalaTestClasses(implicit ctx: Ctx.Home): ScalaTestClassesResult = {
var items = List.empty[ScalaTestClassesItem]
for (targetId <- scalaTestClassesParams.getTargets.asScala) {
targetIdToModule(targetId) match {
case module: TestModule =>
- items ++= List(new ScalaTestClassesItem(targetId, getTestClasses(module).toList.asJava))
+ items ++= List(new ScalaTestClassesItem(targetId, getTestClasses(module).toList.asJava))
case _: JavaModule => //TODO: maybe send a notification that this target has no test classes
}
}
new ScalaTestClassesResult(items.asJava)
}
- handleExceptions[Ctx.Home, ScalaTestClassesResult](c => getScalaTestClasses(c), ctx)
- }
-
- // Given the mapping from modules to targetIds, construct the mapping from targetIds to modules
- private[this] def targetToModule(moduleToTargetId: Predef.Map[JavaModule, BuildTargetIdentifier]):
- Predef.Map[BuildTargetIdentifier, JavaModule] = {
- moduleToTargetId.keys.map(mod => (moduleToTargetId(mod), mod)).toMap
+ handleExceptions[Ctx.Home, ScalaTestClassesResult](c => getScalaTestClasses(c), ctx)
}
- // Resolve all the mill modules contained in the project
- private[this] def getMillModules(ev: Evaluator): Seq[JavaModule] = {
- ev.rootModule.millInternal.segmentsToModules.values.
- collect {
- case m: scalalib.JavaModule => m
- }.toSeq ++ Seq(rootModule)
- }
+ // Detect and return the test classes contained in the given TestModule
+ private[this] def getTestClasses(module: TestModule)(implicit ctx: Ctx.Home): Seq[String] = {
+ val runClasspath = getTaskResult(millEvaluator, module.runClasspath)
+ val frameworks = getTaskResult(millEvaluator, module.testFrameworks)
+ val compilationResult = getTaskResult(millEvaluator, module.compile)
- // Recompute the modules in the project in case any changes to the build took place
- // and update all the mappings that depend on this info
- private[this] def recomputeTargets(): Unit = {
- rootModule = ModuleUtils.getRootJavaModule(millEvaluator.rootModule)
- millModules = getMillModules(millEvaluator)
- moduleToTargetId = ModuleUtils.getModuleTargetIdMap(millModules, millEvaluator)
- targetIdToModule = targetToModule(moduleToTargetId)
- moduleToTarget = ModuleUtils.millModulesToBspTargets(millModules, rootModule, evaluator, List("scala", "java"))
+ (runClasspath, frameworks, compilationResult) match {
+ case (Result.Success(classpath), Result.Success(testFrameworks), Result.Success(compResult)) =>
+ val classFingerprint = Jvm.inprocess(classpath.asInstanceOf[Seq[PathRef]].map(_.path),
+ classLoaderOverrideSbtTesting = true,
+ isolated = true,
+ closeContextClassLoaderWhenDone = false, cl => {
+ val fs = TestRunner.frameworks(testFrameworks.asInstanceOf[Seq[String]])(cl)
+ fs.flatMap(framework =>
+ discoverTests(cl, framework, Agg(compResult.asInstanceOf[CompilationResult].
+ classes.path)))
+ })
+ classFingerprint.map(classF => classF._1.getName.stripSuffix("$"))
+ case _ => Seq.empty[String] //TODO: or send notification that something went wrong
+ }
}
- // Given a function that take input of type T and return output of type V,
- // apply the function on the given inputs and return a completable future of
- // the result. If the execution of the function raises an Exception, complete
- // the future exceptionally. Also complete exceptionally if the server was not
- // yet initialized.
- private[this] def handleExceptions[T, V](serverMethod: T => V, input: T): CompletableFuture[V] = {
- val future = new CompletableFuture[V]()
- if (initialized) {
- try {
- future.complete(serverMethod(input))
- } catch {
- case e: Exception => future.completeExceptionally(e)
- }
- } else {
- future.completeExceptionally(
- new Exception("Can not respond to any request before receiving the `initialize` request.")
- )
- }
- future
+ // construct the ManagedLogger that will go into the compilation problems reporter
+ private[this] def getCompilationLogger: ManagedLogger = {
+ val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut(
+ millEvaluator.log.outputStream
+ ))
+ val l = LogExchange.logger("Hello")
+ LogExchange.unbindLoggerAppenders("Hello")
+ LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Info) :: Nil)
+ l
}
}
diff --git a/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala b/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala
index 8cccf7b3..1fd0f019 100644
--- a/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/ModuleUtils.scala
@@ -1,19 +1,19 @@
package mill.contrib.bsp
-import scala.collection.JavaConverters._
import ch.epfl.scala.bsp4j._
import mill.T
import mill.api.Result.Success
import mill.api.{Loose, Strict}
-import mill.define.{BaseModule, Ctx, Segment, Segments, Target, Task}
-import mill.eval._
-import mill.eval.Evaluator
+import mill.define._
+import mill.eval.{Evaluator, _}
import mill.scalajslib.ScalaJSModule
import mill.scalalib.api.Util
-import mill.scalanativelib._
import mill.scalalib.{JavaModule, ScalaModule, TestModule}
+import mill.scalanativelib._
import os.Path
+import scala.collection.JavaConverters._
+
/**
* Utilities for translating the mill build into
* BSP information like BuildTargets and BuildTargetIdentifiers
@@ -25,24 +25,25 @@ object ModuleUtils {
* working directory ( has to be a mill-based project ) and
* BSP BuildTargets ( mill modules correspond one-to-one to
* bsp build targets ).
- * @param modules All JavaModules contained in the working
- * directory of the mill project
- * @param rootModule The root module ( corresponding to the root
- * of the mill project )
- * @param evaluator The mill evaluator that can resolve information
- * about the mill project
+ *
+ * @param modules All JavaModules contained in the working
+ * directory of the mill project
+ * @param rootModule The root module ( corresponding to the root
+ * of the mill project )
+ * @param evaluator The mill evaluator that can resolve information
+ * about the mill project
* @param supportedLanguages the languages supported by the modules
* of the mill project
* @return JavaModule -> BuildTarget mapping
*/
def millModulesToBspTargets(modules: Seq[JavaModule],
- rootModule: JavaModule,
- evaluator: Evaluator,
- supportedLanguages: List[String]): Predef.Map[JavaModule, BuildTarget] = {
+ rootModule: JavaModule,
+ evaluator: Evaluator,
+ supportedLanguages: List[String]): Predef.Map[JavaModule, BuildTarget] = {
val moduleIdMap = getModuleTargetIdMap(modules, evaluator)
- (for ( module <- modules )
+ (for (module <- modules)
yield (module, getTarget(rootModule, module, evaluator, moduleIdMap))).toMap
}
@@ -62,10 +63,10 @@ object ModuleUtils {
* with it.
* @return build target for `module`
*/
- def getTarget( rootModule: JavaModule,
- module: JavaModule,
- evaluator: Evaluator,
- moduleIdMap: Map[JavaModule, BuildTargetIdentifier]
+ def getTarget(rootModule: JavaModule,
+ module: JavaModule,
+ evaluator: Evaluator,
+ moduleIdMap: Map[JavaModule, BuildTargetIdentifier]
): BuildTarget = {
if (module == rootModule)
getRootTarget(module, evaluator, moduleIdMap)
@@ -79,6 +80,7 @@ object ModuleUtils {
* has the same millSourcePath. Set generated sources
* according to the location of the compilation
* products
+ *
* @param rootBaseModule module for the root
* @return root JavaModule
*/
@@ -87,22 +89,33 @@ object ModuleUtils {
new JavaModule {
override def millSourcePath: Path = rootBaseModule.millSourcePath
- override def sources = T.sources{millSourcePath / "src"}
- def out = T.sources{millSourcePath / "out"}
- def target = T.sources{millSourcePath / "target"}
- override def generatedSources: Target[Seq[PathRef]] = T.sources{
- out() ++ target()}
+ override def sources = T.sources {
+ millSourcePath / "src"
+ }
+
+ def out = T.sources {
+ millSourcePath / "out"
+ }
+
+ def target = T.sources {
+ millSourcePath / "target"
+ }
+
+ override def generatedSources: Target[Seq[PathRef]] = T.sources {
+ out() ++ target()
+ }
}
}
/**
* Compute the BuildTarget associated with the root
* directory of the mill project being built
- * @param rootModule the root JavaModule extracted from
- * the build file by a mill evalautor
- * @param evaluator mill evaluator that can resolve
- * build information
+ *
+ * @param rootModule the root JavaModule extracted from
+ * the build file by a mill evalautor
+ * @param evaluator mill evaluator that can resolve
+ * build information
* @param moduleIdMap mapping from each mill JavaModule
* contained in the working directory and
* a BuildTargetIdentifier associated
@@ -145,9 +158,9 @@ object ModuleUtils {
* @return inner BuildTarget
*/
def getRegularTarget(
- module: JavaModule,
- evaluator: Evaluator,
- moduleIdMap: Map[JavaModule, BuildTargetIdentifier]): BuildTarget = {
+ module: JavaModule,
+ evaluator: Evaluator,
+ moduleIdMap: Map[JavaModule, BuildTargetIdentifier]): BuildTarget = {
val dataBuildTarget = computeBuildTargetData(module, evaluator)
val capabilities = getModuleCapabilities(module, evaluator)
val buildTargetTag: List[String] = module match {
@@ -160,10 +173,10 @@ object ModuleUtils {
}
val buildTarget = new BuildTarget(moduleIdMap(module),
- buildTargetTag.asJava,
- List("scala", "java").asJava,
- dependencies,
- capabilities)
+ buildTargetTag.asJava,
+ List("scala", "java").asJava,
+ dependencies,
+ capabilities)
if (module.isInstanceOf[ScalaModule]) {
buildTarget.setDataKind(BuildTargetDataKind.SCALA)
}
@@ -173,6 +186,59 @@ object ModuleUtils {
buildTarget
}
+ /**
+ * Evaluate the given task using the given mill evaluator and return
+ * its result of type Result
+ *
+ * @param evaluator mill evalautor
+ * @param task task to evaluate
+ * @tparam T
+ */
+ def getTaskResult[T](evaluator: Evaluator, task: Task[T]): Result[Any] = {
+ evaluator.evaluate(Strict.Agg(task)).results(task)
+ }
+
+ /**
+ * Evaluate the given task using the given mill evaluator and return
+ * its result of type T, or the default value of the evaluation failed.
+ *
+ * @param evaluator mill evalautor
+ * @param task task to evaluate
+ * @param defaultValue default value to return in case of failure
+ * @tparam T
+ */
+ def evaluateInformativeTask[T](evaluator: Evaluator, task: Task[T], defaultValue: T): T = {
+ val evaluated = evaluator.evaluate(Strict.Agg(task)).results(task)
+ evaluated match {
+ case Success(value) => evaluated.asSuccess.get.value.asInstanceOf[T]
+ case default => defaultValue
+ }
+ }
+
+ /**
+ * Compute mapping between a mill JavaModule and the BuildTargetIdentifier
+ * associated with its corresponding bsp BuildTarget.
+ *
+ * @param modules mill modules inside the project ( including root )
+ * @param evaluator mill evalautor to resolve build information
+ * @return JavaModule -> BuildTargetIdentifier mapping
+ */
+ def getModuleTargetIdMap(modules: Seq[JavaModule], evaluator: Evaluator): Predef.Map[JavaModule, BuildTargetIdentifier] = {
+
+ (for (module <- modules)
+ yield (module, new BuildTargetIdentifier(
+ (module.millOuterCtx.millSourcePath / os.RelPath(moduleName(module.millModuleSegments))).
+ toIO.toURI.toString))).toMap
+ }
+
+ // this is taken from mill.scalalib GenIdeaImpl
+ def moduleName(p: Segments) = p.value.foldLeft(StringBuilder.newBuilder) {
+ case (sb, Segment.Label(s)) if sb.isEmpty => sb.append(s)
+ case (sb, Segment.Cross(s)) if sb.isEmpty => sb.append(s.mkString("-"))
+ case (sb, Segment.Label(s)) => sb.append(".").append(s)
+ case (sb, Segment.Cross(s)) => sb.append("-").append(s.mkString("-"))
+ }.mkString.toLowerCase()
+
// obtain the capabilities of the given module ( ex: canCompile, canRun, canTest )
private[this] def getModuleCapabilities(module: JavaModule, evaluator: Evaluator): BuildTargetCapabilities = {
val canTest = module match {
@@ -209,33 +275,6 @@ object ModuleUtils {
}
}
- /**
- * Evaluate the given task using the given mill evaluator and return
- * its result of type Result
- * @param evaluator mill evalautor
- * @param task task to evaluate
- * @tparam T
- */
- def getTaskResult[T](evaluator: Evaluator, task: Task[T]): Result[Any] = {
- evaluator.evaluate(Strict.Agg(task)).results(task)
- }
-
- /**
- * Evaluate the given task using the given mill evaluator and return
- * its result of type T, or the default value of the evaluation failed.
- * @param evaluator mill evalautor
- * @param task task to evaluate
- * @param defaultValue default value to return in case of failure
- * @tparam T
- */
- def evaluateInformativeTask[T](evaluator: Evaluator, task: Task[T], defaultValue: T): T = {
- val evaluated = evaluator.evaluate(Strict.Agg(task)).results(task)
- evaluated match {
- case Success(value) => evaluated.asSuccess.get.value.asInstanceOf[T]
- case default => defaultValue
- }
- }
-
// Compute all relevant scala dependencies of `module`, like scala-library, scala-compiler,
// and scala-reflect
private[this] def computeScalaLangDependencies(module: ScalaModule, evaluator: Evaluator): Loose.Agg[PathRef] = {
@@ -255,27 +294,4 @@ object ModuleUtils {
case m: ScalaModule => ScalaPlatform.JVM
}
}
-
- /**
- * Compute mapping between a mill JavaModule and the BuildTargetIdentifier
- * associated with its corresponding bsp BuildTarget.
- * @param modules mill modules inside the project ( including root )
- * @param evaluator mill evalautor to resolve build information
- * @return JavaModule -> BuildTargetIdentifier mapping
- */
- def getModuleTargetIdMap(modules: Seq[JavaModule], evaluator:Evaluator): Predef.Map[JavaModule, BuildTargetIdentifier] = {
-
- (for ( module <- modules )
- yield (module, new BuildTargetIdentifier(
- (module.millOuterCtx.millSourcePath / os.RelPath(moduleName(module.millModuleSegments))).
- toIO.toURI.toString))).toMap
- }
-
- // this is taken from mill.scalalib GenIdeaImpl
- def moduleName(p: Segments) = p.value.foldLeft(StringBuilder.newBuilder) {
- case (sb, Segment.Label(s)) if sb.isEmpty => sb.append(s)
- case (sb, Segment.Cross(s)) if sb.isEmpty => sb.append(s.mkString("-"))
- case (sb, Segment.Label(s)) => sb.append(".").append(s)
- case (sb, Segment.Cross(s)) => sb.append("-").append(s.mkString("-"))
- }.mkString.toLowerCase()
}
diff --git a/contrib/bsp/src/mill/contrib/bsp/TaskParameters.scala b/contrib/bsp/src/mill/contrib/bsp/TaskParameters.scala
index 29a07f17..a235c922 100644
--- a/contrib/bsp/src/mill/contrib/bsp/TaskParameters.scala
+++ b/contrib/bsp/src/mill/contrib/bsp/TaskParameters.scala
@@ -1,8 +1,9 @@
package mill.contrib.bsp
-import scala.collection.JavaConverters._
import ch.epfl.scala.bsp4j.{BuildTargetIdentifier, CompileParams, RunParams, TestParams}
+import scala.collection.JavaConverters._
+
/**
* Common trait to represent BSP request parameters that
@@ -27,7 +28,7 @@ case class CParams(compileParams: CompileParams) extends Parameters {
override def getArguments: Option[Seq[String]] = {
try {
Option(compileParams.getArguments.asScala)
- }catch {
+ } catch {
case e: Exception => Option.empty[Seq[String]]
}
}
@@ -35,12 +36,13 @@ case class CParams(compileParams: CompileParams) extends Parameters {
override def getOriginId: Option[String] = {
try {
Option(compileParams.getOriginId)
- }catch {
+ } catch {
case e: Exception => Option.empty[String]
}
}
}
+
case class RParams(runParams: RunParams) extends Parameters {
override def getTargets: List[BuildTargetIdentifier] = {
@@ -50,7 +52,7 @@ case class RParams(runParams: RunParams) extends Parameters {
override def getArguments: Option[Seq[String]] = {
try {
Option(runParams.getArguments.asScala)
- }catch {
+ } catch {
case e: Exception => Option.empty[Seq[String]]
}
}
@@ -58,12 +60,13 @@ case class RParams(runParams: RunParams) extends Parameters {
override def getOriginId: Option[String] = {
try {
Option(runParams.getOriginId)
- }catch {
+ } catch {
case e: Exception => Option.empty[String]
}
}
}
+
case class TParams(testParams: TestParams) extends Parameters {
override def getTargets: List[BuildTargetIdentifier] = {
@@ -73,7 +76,7 @@ case class TParams(testParams: TestParams) extends Parameters {
override def getArguments: Option[Seq[String]] = {
try {
Option(testParams.getArguments.asScala)
- }catch {
+ } catch {
case e: Exception => Option.empty[Seq[String]]
}
}
@@ -81,7 +84,7 @@ case class TParams(testParams: TestParams) extends Parameters {
override def getOriginId: Option[String] = {
try {
Option(testParams.getOriginId)
- }catch {
+ } catch {
case e: Exception => Option.empty[String]
}
}
@@ -92,6 +95,7 @@ object TaskParameters {
/**
* Convert parameters specific to the compile request
* to the common trait Parameters.
+ *
* @param compileParams compile request parameters
* @return general task parameters containing compilation info
*/
@@ -102,6 +106,7 @@ object TaskParameters {
/**
* Convert parameters specific to the run request
* to the common trait Parameters.
+ *
* @param runParams run request parameters
* @return general task parameters containing running info
*/
@@ -112,6 +117,7 @@ object TaskParameters {
/**
* Convert parameters specific to the test request
* to the common trait Parameters.
+ *
* @param testParams compile request parameters
* @return general task parameters containing testing info
*/
diff --git a/main/api/src/mill/api/Ctx.scala b/main/api/src/mill/api/Ctx.scala
index 96da84eb..e86ad7f9 100644
--- a/main/api/src/mill/api/Ctx.scala
+++ b/main/api/src/mill/api/Ctx.scala
@@ -55,13 +55,13 @@ object Ctx {
class Ctx(
- val args: IndexedSeq[_],
- dest0: () => os.Path,
- val log: Logger,
- val home: os.Path,
- val env: Map[String, String],
- val reporter: Int => Option[BuildProblemReporter],
- val testReporter: TestReporter
+ val args: IndexedSeq[_],
+ dest0: () => os.Path,
+ val log: Logger,
+ val home: os.Path,
+ val env: Map[String, String],
+ val reporter: Int => Option[BuildProblemReporter],
+ val testReporter: TestReporter
)
extends Ctx.Dest
with Ctx.Log