Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another update #165

Merged
merged 10 commits into from
Apr 23, 2024
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- uses: coursier/setup-action@v1.3.0
with:
jvm: "temurin:17"
apps: sbt
- name: Tests
run: |
.github/setup-test-projects.sh &&\
Expand All @@ -64,6 +65,7 @@ jobs:
- uses: coursier/setup-action@v1.3.0
with:
jvm: "temurin:17"
apps: sbt
- name: Compile and test main projects
# Only running the tests in 2.12 for now. Many test fixtures need
# to be updated for 2.13.
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main/scala/bloop/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.util.concurrent.Executor

import scala.collection.mutable
import scala.concurrent.Promise
import scala.util.control.NonFatal
import scala.util.Try

import bloop.io.AbsolutePath
import bloop.io.ParallelOps
Expand Down
23 changes: 20 additions & 3 deletions backend/src/main/scala/bloop/ScalaInstance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ final class ScalaInstance private (
val organization: String,
val name: String,
override val version: String,
override val allJars: Array[File]
override val allJars: Array[File],
val bridgeJarsOpt: Option[Seq[File]] = None
) extends xsbti.compile.ScalaInstance {

override lazy val loaderCompilerOnly: ClassLoader =
Expand Down Expand Up @@ -153,6 +154,15 @@ object ScalaInstance {

private[ScalaInstance] final val ScalacCompilerName = "scala-compiler"

def apply(
scalaOrg: String,
scalaName: String,
scalaVersion: String,
allJars: Seq[AbsolutePath],
logger: Logger
): ScalaInstance =
apply(scalaOrg, scalaName, scalaVersion, allJars, logger, None)

/**
* Reuses all jars to create an Scala instance if and only if all of them exist.
*
Expand All @@ -170,7 +180,8 @@ object ScalaInstance {
scalaName: String,
scalaVersion: String,
allJars: Seq[AbsolutePath],
logger: Logger
logger: Logger,
bridgeJarsOpt: Option[Seq[AbsolutePath]]
): ScalaInstance = {
val jarsKey = allJars.map(_.underlying).sortBy(_.toString).toList
if (allJars.nonEmpty) {
Expand All @@ -179,7 +190,13 @@ object ScalaInstance {
DebugFilter.Compilation
)
jarsKey.foreach(p => logger.debug(s" => $p")(DebugFilter.Compilation))
new ScalaInstance(scalaOrg, scalaName, scalaVersion, allJars.map(_.toFile).toArray)
new ScalaInstance(
scalaOrg,
scalaName,
scalaVersion,
allJars.map(_.toFile).toArray,
bridgeJarsOpt.map(_.map(_.toFile))
)
}

val nonExistingJars = allJars.filter(j => !Files.exists(j.underlying))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ object BloopComponentCompiler {
*/
private def compiledBridge(bridgeSources: ModuleID, scalaInstance: ScalaInstance): File = {
val raw = new RawCompiler(scalaInstance, ClasspathOptionsUtil.auto, logger)
val zinc = new BloopComponentCompiler(raw, manager, bridgeSources, logger)
val bridgeJarsOpt = scalaInstance match {
case b: _root_.bloop.ScalaInstance => b.bridgeJarsOpt
case _ => None
}
val zinc = new BloopComponentCompiler(raw, manager, bridgeSources, bridgeJarsOpt, logger)
logger.debug(s"Getting $bridgeSources for Scala ${scalaInstance.version}")(
DebugFilter.Compilation
)
Expand Down Expand Up @@ -229,6 +233,7 @@ private[inc] class BloopComponentCompiler(
compiler: RawCompiler,
manager: BloopComponentManager,
bridgeSources: ModuleID,
bridgeJarsOpt: Option[Seq[File]],
logger: BloopLogger
) {
implicit val debugFilter: DebugFilter.Compilation.type = DebugFilter.Compilation
Expand Down Expand Up @@ -257,23 +262,25 @@ private[inc] class BloopComponentCompiler(
IO.withTemporaryDirectory { _ =>
val shouldResolveSources =
bridgeSources.explicitArtifacts.exists(_.`type` == "src")
val allArtifacts = BloopDependencyResolution.resolveWithErrors(
List(
BloopDependencyResolution
.Artifact(bridgeSources.organization, bridgeSources.name, bridgeSources.revision)
),
logger,
resolveSources = shouldResolveSources,
List(
coursierapi.MavenRepository.of(
"https://scala-ci.typesafe.com/artifactory/scala-integration/"
val allArtifacts = bridgeJarsOpt.map(_.map(_.toPath)).getOrElse {
BloopDependencyResolution.resolveWithErrors(
List(
BloopDependencyResolution
.Artifact(bridgeSources.organization, bridgeSources.name, bridgeSources.revision)
),
logger,
resolveSources = shouldResolveSources,
List(
coursierapi.MavenRepository.of(
"https://scala-ci.typesafe.com/artifactory/scala-integration/"
)
)
)
) match {
case Right(paths) => paths.map(_.underlying).toVector
case Left(t) =>
val msg = s"Couldn't retrieve module $bridgeSources"
throw new InvalidComponent(msg, t)
) match {
case Right(paths) => paths.map(_.underlying).toVector
case Left(t) =>
val msg = s"Couldn't retrieve module $bridgeSources"
throw new InvalidComponent(msg, t)
}
}

if (!shouldResolveSources) {
Expand All @@ -286,7 +293,7 @@ private[inc] class BloopComponentCompiler(
if (!HydraSupport.isEnabled(compiler.scalaInstance)) (bridgeSources.name, sources)
else {
val hydraBridgeModule = HydraSupport.getModuleForBridgeSources(compiler.scalaInstance)
mergeBloopAndHydraBridges(sources, hydraBridgeModule) match {
mergeBloopAndHydraBridges(sources.toVector, hydraBridgeModule) match {
case Right(mergedHydraBridgeSourceJar) =>
(hydraBridgeModule.name, mergedHydraBridgeSourceJar)
case Left(error) =>
Expand Down
10 changes: 5 additions & 5 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ object Dependencies {

def asm = ivy"org.ow2.asm:asm:$asmVersion"
def asmUtil = ivy"org.ow2.asm:asm-util:$asmVersion"
def bloopConfig = ivy"ch.epfl.scala::bloop-config:1.5.5"
def bloopConfig = ivy"ch.epfl.scala::bloop-config:2.0.0"
def brave = ivy"io.zipkin.brave:brave:5.18.1"
def bsp4j = ivy"ch.epfl.scala:bsp4j:2.1.1"
def bsp4s = ivy"ch.epfl.scala::bsp4s:2.1.1"
Expand Down Expand Up @@ -61,7 +61,7 @@ object Dependencies {
def munit = ivy"org.scalameta::munit:0.7.29"
def nailgun = ivy"io.github.alexarchambault.bleep:nailgun-server:1.0.7"
def osLib = ivy"com.lihaoyi::os-lib:0.9.0"
def pprint = ivy"com.lihaoyi::pprint:0.8.1"
def pprint = ivy"com.lihaoyi::pprint:0.9.0"
def sbtTestAgent = ivy"org.scala-sbt:test-agent:1.9.9"
def sbtTestInterface = ivy"org.scala-sbt:test-interface:1.0"
def scalaDebugAdapter = ivy"ch.epfl.scala::scala-debug-adapter:4.0.3"
Expand All @@ -72,12 +72,12 @@ object Dependencies {
def scalaJsSbtTestAdapter1 = ivy"org.scala-js::scalajs-sbt-test-adapter:$scalaJs1Version"
def scalaJsLogging1 = ivy"org.scala-js::scalajs-logging:1.1.1"
def scalaNativeTools04 = ivy"org.scala-native::tools:0.4.17"
def scalaNativeTools05 = ivy"org.scala-native::tools:0.5.0-RC2"
def scalaNativeTools05 = ivy"org.scala-native::tools:0.5.1"
def scalazCore = ivy"org.scalaz::scalaz-core:7.3.8"
def snailgun = ivy"io.github.alexarchambault.scala-cli.snailgun::snailgun-core:0.4.1-sc2"
def sourcecode = ivy"com.lihaoyi::sourcecode:0.3.1"
def sourcecode = ivy"com.lihaoyi::sourcecode:0.4.1"
def svm = ivy"org.graalvm.nativeimage:svm:$graalvmVersion"
def utest = ivy"com.lihaoyi::utest:0.8.2"
def utest = ivy"com.lihaoyi::utest:0.8.3"
def xxHashLibrary = ivy"net.jpountz.lz4:lz4:1.3.0"
def zinc = ivy"org.scala-sbt::zinc:1.9.5"
def zipkinSender = ivy"io.zipkin.reporter2:zipkin-sender-urlconnection:2.17.2"
Expand Down
36 changes: 35 additions & 1 deletion frontend/src/main/scala/bloop/bsp/BloopBspServices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ final class BloopBspServices(
.requestAsync(endpoints.BuildTarget.sources)(p => schedule(sources(p)))
.requestAsync(endpoints.BuildTarget.inverseSources)(p => schedule(inverseSources(p)))
.requestAsync(endpoints.BuildTarget.resources)(p => schedule(resources(p)))
.requestAsync(endpoints.BuildTarget.outputPaths)(p => schedule(outputPaths(p)))
.requestAsync(endpoints.BuildTarget.scalacOptions)(p => schedule(scalacOptions(p)))
.requestAsync(endpoints.BuildTarget.javacOptions)(p => schedule(javacOptions(p)))
.requestAsync(endpoints.BuildTarget.compile)(p => schedule(compile(p)))
Expand Down Expand Up @@ -311,7 +312,7 @@ final class BloopBspServices(
dependencySourcesProvider = Some(true),
dependencyModulesProvider = Some(true),
resourcesProvider = Some(true),
outputPathsProvider = None,
outputPathsProvider = Some(true),
buildTargetChangedProvider = Some(false),
jvmTestEnvironmentProvider = Some(true),
jvmRunEnvironmentProvider = Some(true),
Expand Down Expand Up @@ -1204,6 +1205,39 @@ final class BloopBspServices(
}
}

def outputPaths(
request: bsp.OutputPathsParams
): BspEndpointResponse[bsp.OutputPathsResult] = {
def outputPaths(
projects: Seq[ProjectMapping],
state: State
): BspResult[bsp.OutputPathsResult] = {

val response = bsp.OutputPathsResult(
projects.iterator.map {
case (target, project) =>
val outputPathItems =
List(
bsp.OutputPathItem(bsp.Uri(project.out.toBspUri), bsp.OutputPathItemKind.Directory)
)
bsp.OutputPathsItem(target, outputPathItems)
}.toList
)

Task.now((state, Right(response)))
}

ifInitialized(None) { (state: State, logger: BspServerLogger) =>
mapToProjects(request.targets, state) match {
case Left(error) =>
// Log the mapping error to the user via a log event + an error status code
logger.error(error)
Task.now((state, Right(bsp.OutputPathsResult(Nil))))
case Right(mappings) => outputPaths(mappings, state)
}
}
}

def dependencyModules(
request: bsp.DependencyModulesParams
): BspEndpointResponse[bsp.DependencyModulesResult] = {
Expand Down
17 changes: 7 additions & 10 deletions frontend/src/main/scala/bloop/bsp/ProjectUris.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,16 @@ import bloop.engine.State
import bloop.io.AbsolutePath

object ProjectUris {
private val queryPrefix = "id="
def getProjectDagFromUri(projectUri: String, state: State): Either[String, Option[Project]] = {
if (projectUri.isEmpty) Left("URI cannot be empty.")
else {
val query = Try(new URI(projectUri).getRawQuery().split("&").map(_.split("="))).toEither
query match {
case Left(_) =>
Try(new URI(projectUri).getQuery()).toEither match {
case Right(query) if query.startsWith(queryPrefix) =>
val projectName = query.stripPrefix(queryPrefix)
Right(state.build.getProjectFor(projectName))
case _ =>
Left(s"URI '${projectUri}' has invalid format. Example: ${ProjectUris.Example}")
case Right(parsed) =>
parsed.headOption match {
case Some(Array("id", projectName)) => Right(state.build.getProjectFor(projectName))
case _ =>
Left(s"URI '${projectUri}' has invalid format. Example: ${ProjectUris.Example}")
}
}
}
}
Expand All @@ -39,7 +36,7 @@ object ProjectUris {
existingUri.getHost,
existingUri.getPort,
existingUri.getPath,
s"id=${id}",
s"$queryPrefix${id}",
existingUri.getFragment
)
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/main/scala/bloop/data/ClientInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import scala.collection.mutable
import scala.util.control.NonFatal
import scala.util.matching.Regex

import bloop.ClientClassesObserver
import bloop.io.AbsolutePath
import bloop.io.Filenames
import bloop.io.Paths
import bloop.util.UUIDUtil
import bloop.ClientClassesObserver

sealed trait ClientInfo {

Expand Down
9 changes: 8 additions & 1 deletion frontend/src/main/scala/bloop/data/Project.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,14 @@ object Project {
else {
val scalaJars = scala.jars.map(AbsolutePath.apply)
Some(
ScalaInstance(scala.organization, scala.name, scala.version, scalaJars, logger)
ScalaInstance(
scala.organization,
scala.name,
scala.version,
scalaJars,
logger,
scala.bridgeJars.map(_.map(AbsolutePath(_)))
)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bloop.engine.tasks.compilation

import scala.concurrent.Promise

import bloop.ClientClassesObserver
import bloop.CompileOutPaths
import bloop.Compiler
import bloop.ScalaInstance
Expand All @@ -23,7 +24,6 @@ import bloop.tracing.BraveTracer

import monix.reactive.Observable
import sbt.internal.inc.PlainVirtualFileConverter
import bloop.ClientClassesObserver

sealed trait CompileBundle

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bloop.engine.tasks.toolchains
import java.lang.reflect.InvocationTargetException
import java.nio.file.Path

import scala.concurrent.Future
import scala.util.Try

import bloop.DependencyResolution
Expand All @@ -14,7 +15,6 @@ import bloop.internal.build.BuildInfo
import bloop.io.AbsolutePath
import bloop.logging.Logger
import bloop.task.Task
import scala.concurrent.Future

final class ScalaNativeToolchain private (classLoader: ClassLoader) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.0.0")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.0-RC2")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.1")

val pluginVersion = sys.props.getOrElse(
"bloopVersion",
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/test/scala/bloop/bsp/BspBaseSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,19 @@ abstract class BspBaseSuite extends BaseSuite with BspClientTest {
TestUtil.await(FiniteDuration(5, "s"))(resourcesTask)
}

def requestOutputPaths(project: TestProject): bsp.OutputPathsResult = {
val outputPathsTask = {
client0
.request(endpoints.BuildTarget.outputPaths, bsp.OutputPathsParams(List(project.bspId)))
.map {
case RpcFailure(_, error) => fail(s"Received error ${error}")
case RpcSuccess(resources, _) => resources
}
}

TestUtil.await(FiniteDuration(5, "s"))(outputPathsTask)
}

def requestDependencyModules(project: TestProject): bsp.DependencyModulesResult = {
val dependencyModulesTask = {
client0
Expand Down
31 changes: 31 additions & 0 deletions frontend/src/test/scala/bloop/bsp/BspProtocolSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,37 @@ class BspProtocolSpec(
}
}

test("outputPaths request works") {
TestUtil.withinWorkspace { workspace =>
val logger = new RecordingLogger(ansiCodesSupported = false)
loadBspBuildFromResources("cross-test-build-scalajs-0.6", workspace, logger) { build =>
val mainProject = build.projectFor("test-project")
val testProject = build.projectFor("test-project-test")
val mainJsProject = build.projectFor("test-projectJS")
val testJsProject = build.projectFor("test-projectJS-test")
val rootMain = build.projectFor("cross-test-build-scalajs-0-6")
val rootTest = build.projectFor("cross-test-build-scalajs-0-6-test")

def checkOutputPaths(project: TestProject): Unit = {
val outputPathsResult = build.state.requestOutputPaths(project)
assert(outputPathsResult.items.size == 1)
val outputPathsItem = outputPathsResult.items.head
assert(outputPathsItem.target == project.bspId)
val outputPaths = outputPathsItem.outputPaths.map(_.uri.toPath)
val expectedOutputPaths = List(project.config.out.toAbsolutePath())
assert(outputPaths == expectedOutputPaths)
}

checkOutputPaths(mainProject)
checkOutputPaths(testProject)
checkOutputPaths(mainJsProject)
checkOutputPaths(testJsProject)
checkOutputPaths(rootMain)
checkOutputPaths(rootTest)
}
}
}

test("dependency modules request works") {
TestUtil.withinWorkspace { workspace =>
val logger = new RecordingLogger(ansiCodesSupported = false)
Expand Down
Loading
Loading