Skip to content

Commit 10dc726

Browse files
authored
Merge pull request #1397 from tpasternak/scalac-options-endpoint
Implement javacOptions endpoint
2 parents 76362d9 + 65abf1b commit 10dc726

File tree

4 files changed

+89
-28
lines changed

4 files changed

+89
-28
lines changed

frontend/src/main/scala/bloop/bsp/BloopBspServices.scala

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import java.util.concurrent.atomic.AtomicInteger
88
import java.nio.file.{FileSystems, Files, Path}
99
import java.util.concurrent.ConcurrentHashMap
1010
import java.util.stream.Collectors
11-
1211
import bloop.io.Environment.lineSeparator
1312
import bloop.io.ServerHandle
1413
import bloop.util.JavaRuntime
@@ -33,16 +32,15 @@ import ch.epfl.scala.bsp.{
3332
JvmEnvironmentItem,
3433
MessageType,
3534
ShowMessageParams,
35+
Uri,
3636
endpoints
3737
}
38-
3938
import scala.meta.jsonrpc.{JsonRpcClient, Response => JsonRpcResponse, Services => JsonRpcServices}
4039
import monix.eval.Task
4140
import monix.reactive.Observer
4241
import monix.execution.Scheduler
4342
import monix.execution.atomic.AtomicInt
4443
import monix.execution.atomic.AtomicBoolean
45-
4644
import scala.collection.concurrent.TrieMap
4745
import scala.collection.mutable
4846
import scala.collection.JavaConverters._
@@ -108,6 +106,7 @@ final class BloopBspServices(
108106
.requestAsync(endpoints.BuildTarget.sources)(p => schedule(sources(p)))
109107
.requestAsync(endpoints.BuildTarget.resources)(p => schedule(resources(p)))
110108
.requestAsync(endpoints.BuildTarget.scalacOptions)(p => schedule(scalacOptions(p)))
109+
.requestAsync(endpoints.BuildTarget.javacOptions)(p => schedule(javacOptions(p)))
111110
.requestAsync(endpoints.BuildTarget.compile)(p => schedule(compile(p)))
112111
.requestAsync(endpoints.BuildTarget.test)(p => schedule(test(p)))
113112
.requestAsync(endpoints.BuildTarget.run)(p => schedule(run(p)))
@@ -1118,32 +1117,39 @@ final class BloopBspServices(
11181117
}
11191118
}
11201119

1120+
private def getClasspath(state: State, project: Project): List[Uri] = {
1121+
val uris = mutable.Map.empty[Path, bsp.Uri]
1122+
val dag = state.build.getDagFor(project)
1123+
val fullClasspath = project.fullClasspath(dag, state.client)
1124+
val classpath =
1125+
fullClasspath.map(e => uris.getOrElseUpdate(e.underlying, bsp.Uri(e.toBspUri))).toList
1126+
classpath
1127+
}
1128+
1129+
private def getClassesDir(state: State, project: Project): bsp.Uri = {
1130+
bsp.Uri(state.client.getUniqueClassesDirFor(project, forceGeneration = true).toBspUri)
1131+
}
1132+
11211133
def scalacOptions(
11221134
request: bsp.ScalacOptionsParams
11231135
): BspEndpointResponse[bsp.ScalacOptionsResult] = {
11241136
def scalacOptions(
11251137
projects: Seq[ProjectMapping],
11261138
state: State
11271139
): BspResult[bsp.ScalacOptionsResult] = {
1128-
val uris = mutable.Map.empty[Path, bsp.Uri]
11291140
val response = bsp.ScalacOptionsResult(
11301141
projects.iterator.map {
11311142
case (target, project) =>
1132-
val dag = state.build.getDagFor(project)
1133-
val fullClasspath = project.fullClasspath(dag, state.client)
1134-
val classpath =
1135-
fullClasspath.map(e => uris.getOrElseUpdate(e.underlying, bsp.Uri(e.toBspUri))).toList
1136-
val classesDir =
1137-
state.client.getUniqueClassesDirFor(project, forceGeneration = true).toBspUri
1143+
val classpath = getClasspath(state, project)
1144+
val classesDir = getClassesDir(state, project)
11381145
bsp.ScalacOptionsItem(
11391146
target = target,
11401147
options = project.scalacOptions.toList,
11411148
classpath = classpath,
1142-
classDirectory = bsp.Uri(classesDir)
1149+
classDirectory = classesDir
11431150
)
11441151
}.toList
11451152
)
1146-
11471153
Task.now((state, Right(response)))
11481154
}
11491155

@@ -1152,13 +1158,46 @@ final class BloopBspServices(
11521158
case Left(error) =>
11531159
// Log the mapping error to the user via a log event + an error status code
11541160
logger.error(error)
1155-
// TODO(jvican): Add status code to scalac options result
11561161
Task.now((state, Right(bsp.ScalacOptionsResult(Nil))))
11571162
case Right(mappings) => scalacOptions(mappings, state)
11581163
}
11591164
}
11601165
}
11611166

1167+
def javacOptions(
1168+
request: bsp.JavacOptionsParams
1169+
): BspEndpointResponse[bsp.JavacOptionsResult] = {
1170+
def javacOptions(
1171+
projects: Seq[ProjectMapping],
1172+
state: State
1173+
): BspResult[bsp.JavacOptionsResult] = {
1174+
val response = bsp.JavacOptionsResult(
1175+
projects.iterator.map {
1176+
case (target, project) =>
1177+
val classpath = getClasspath(state, project)
1178+
val classesDir = getClassesDir(state, project)
1179+
bsp.JavacOptionsItem(
1180+
target = target,
1181+
options = project.javacOptions.toList,
1182+
classpath = classpath,
1183+
classDirectory = classesDir
1184+
)
1185+
}.toList
1186+
)
1187+
Task.now((state, Right(response)))
1188+
}
1189+
1190+
ifInitialized(None) { (state: State, logger: BspServerLogger) =>
1191+
mapToProjects(request.targets, state) match {
1192+
case Left(error) =>
1193+
// Log the mapping error to the user via a log event + an error status code
1194+
logger.error(error)
1195+
Task.now((state, Right(bsp.JavacOptionsResult(Nil))))
1196+
case Right(mappings) => javacOptions(mappings, state)
1197+
}
1198+
}
1199+
}
1200+
11621201
val isShutdown = scala.concurrent.Promise[BspResponse[Unit]]()
11631202
val isShutdownTask = Task.fromFuture(isShutdown.future).memoize
11641203
def shutdown(shutdown: bsp.Shutdown): Unit = {

frontend/src/test/scala/bloop/bsp/BspBaseSuite.scala

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package bloop.bsp
33
import java.net.URI
44
import java.nio.file.Files
55
import java.util.concurrent.{ConcurrentHashMap, ExecutionException, TimeUnit}
6-
76
import bloop.TestSchedulers
87
import bloop.bsp.BloopBspDefinitions.BloopExtraBuildParams
98
import bloop.cli.{BspProtocol, Commands}
@@ -15,15 +14,14 @@ import bloop.logging.{BspClientLogger, RecordingLogger}
1514
import bloop.testing.BaseSuite
1615
import bloop.util.{TestProject, TestUtil}
1716
import ch.epfl.scala.bsp
18-
import ch.epfl.scala.bsp.{JvmTestEnvironmentResult, Uri, endpoints}
17+
import ch.epfl.scala.bsp.{JvmTestEnvironmentResult, ScalacOptionsResult, Uri, endpoints}
1918
import io.circe.Json
2019
import monix.eval.Task
2120
import monix.execution.atomic.AtomicInt
2221
import monix.execution.{CancelableFuture, Scheduler}
2322
import monix.reactive.Observable
2423
import monix.execution.Scheduler
2524
import monix.reactive.subjects.ConcurrentSubject
26-
2725
import scala.util.Try
2826
import scala.concurrent.Promise
2927
import scala.concurrent.duration.FiniteDuration
@@ -352,16 +350,9 @@ abstract class BspBaseSuite extends BaseSuite with BspClientTest {
352350
TestUtil.await(timeout)(session)
353351
}
354352

355-
def scalaOptions(project: TestProject): (ManagedBspTestState, bsp.ScalacOptionsResult) = {
356-
val scalacOptionsTask = runAfterTargets(project) { target =>
357-
endpoints.BuildTarget.scalacOptions.request(bsp.ScalacOptionsParams(List(target))).map {
358-
case Left(error) => fail(s"Received error ${error}")
359-
case Right(options) => options
360-
}
361-
}
362-
353+
def await[A](task: Task[A]) = {
363354
TestUtil.await(FiniteDuration(5, "s")) {
364-
scalacOptionsTask.flatMap { result =>
355+
task.flatMap { result =>
365356
serverStates.headL.map { state =>
366357
val latestServerState = new ManagedBspTestState(
367358
state,
@@ -378,6 +369,26 @@ abstract class BspBaseSuite extends BaseSuite with BspClientTest {
378369
}
379370
}
380371

372+
def scalaOptions(project: TestProject): (ManagedBspTestState, bsp.ScalacOptionsResult) = {
373+
val scalacOptionsTask: Task[ScalacOptionsResult] = runAfterTargets(project) { target =>
374+
endpoints.BuildTarget.scalacOptions.request(bsp.ScalacOptionsParams(List(target))).map {
375+
case Left(error) => fail(s"Received error ${error}")
376+
case Right(options) => options
377+
}
378+
}
379+
await(scalacOptionsTask)
380+
}
381+
382+
def javacOptions(project: TestProject): (ManagedBspTestState, bsp.JavacOptionsResult) = {
383+
val javacOptionsTask = runAfterTargets(project) { target =>
384+
endpoints.BuildTarget.javacOptions.request(bsp.JavacOptionsParams(List(target))).map {
385+
case Left(error) => fail(s"Received error ${error}")
386+
case Right(options) => options
387+
}
388+
}
389+
await(javacOptionsTask)
390+
}
391+
381392
def jvmRunEnvironment(
382393
project: TestProject,
383394
originId: Option[String]

frontend/src/test/scala/bloop/bsp/BspProtocolSpec.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class BspProtocolSpec(
2727
override val protocol: BspProtocol
2828
) extends BspBaseSuite {
2929
import ch.epfl.scala.bsp
30-
test("check the correct contents of scalac options") {
30+
test("check the correct contents of scalac/javac options") {
3131
TestUtil.withinWorkspace { workspace =>
3232
object Sources {
3333
val `A.scala` =
@@ -45,12 +45,17 @@ class BspProtocolSpec(
4545
val B = List("-Yprint-typer")
4646
}
4747

48+
object JavacOptions {
49+
val A = List("-source", "9")
50+
}
51+
4852
val logger = new RecordingLogger(ansiCodesSupported = false)
4953
val `A` = TestProject(
5054
workspace,
5155
"a",
5256
List(Sources.`A.scala`),
53-
scalacOptions = ScalacOptions.`A`
57+
scalacOptions = ScalacOptions.`A`,
58+
javacOptions = JavacOptions.A
5459
)
5560

5661
val `B` = TestProject(
@@ -93,6 +98,9 @@ class BspProtocolSpec(
9398
assert(stateB.status == ExitStatus.Ok)
9499
val classesDirB = stateB.toTestState.getClientExternalDir(`B`).underlying
95100
testOptions(resultB, ScalacOptions.B, classesDirB, `B`.bspId, List(classesDirB))
101+
102+
val (_, javacResultA) = state.javacOptions(`A`)
103+
assert(javacResultA.items.flatMap(_.options) == JavacOptions.A)
96104
}
97105
}
98106
}

frontend/src/test/scala/bloop/util/TestProject.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ abstract class BaseTestProject {
9898
strictDependencies: Boolean = false,
9999
enableTests: Boolean = false,
100100
scalacOptions: List[String] = Nil,
101+
javacOptions: List[String] = Nil,
101102
scalaOrg: Option[String] = None,
102103
scalaCompiler: Option[String] = None,
103104
scalaVersion: Option[String] = None,
@@ -154,6 +155,8 @@ abstract class BaseTestProject {
154155
Some(setup)
155156
)
156157

158+
val javacConfig = Config.Java(javacOptions)
159+
157160
val frameworks = if (enableTests) Config.TestFramework.DefaultFrameworks else Nil
158161
val testConfig = Config.Test(frameworks, Config.TestOptions.empty)
159162
val platform = Config.Platform.Jvm(
@@ -185,7 +188,7 @@ abstract class BaseTestProject {
185188
classes.underlying,
186189
resources = compileResourcesList,
187190
scala = Some(scalaConfig),
188-
java = None,
191+
java = Some(javacConfig),
189192
sbt = None,
190193
test = Some(testConfig),
191194
platform = Some(platform),

0 commit comments

Comments
 (0)