Skip to content

Commit

Permalink
Merge pull request #2097 from tgodzik/fallback-semanticdb
Browse files Browse the repository at this point in the history
improvement: Try and find latest supported semanticdb version
  • Loading branch information
tgodzik authored Jul 3, 2023
2 parents e9e7c15 + c8d68ab commit d46a3fa
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@ package bloop.engine.caches

import java.nio.file.Path

import scala.collection.JavaConverters._
import scala.concurrent.Await
import scala.concurrent.duration.FiniteDuration
import scala.util.Failure
import scala.util.Success
import scala.util.Try

import bloop.DependencyResolution
import bloop.SemanticDBCacheLock
import bloop.engine.ExecutionContext
import bloop.io.AbsolutePath
import bloop.io.Paths
import bloop.logging.Logger
import bloop.task.Task

import sbt.internal.inc.BloopComponentCompiler
import sbt.internal.inc.BloopComponentManager
import sbt.internal.inc.IfMissing
import java.util.concurrent.ConcurrentHashMap
import scala.concurrent.Future

object SemanticDBCache {
// to avoid resolving the same fallback semanticdb version multiple times
private val supportedFallbackSemanticdbVersions = new ConcurrentHashMap[String, String]()
private def fetchPlugin(
artifact: DependencyResolution.Artifact,
logger: Logger
Expand Down Expand Up @@ -57,6 +66,41 @@ object SemanticDBCache {
}
}

private def fallbackSemanticdbFetch(
scalaVersion: String,
artifact: DependencyResolution.Artifact,
logger: Logger
): Either[String, AbsolutePath] = {
// if scala version is no longer supported find the latest supported semanticdb version
def versionFuture =
Future {
coursierapi.Complete
.create()
.withScalaVersion(scalaVersion)
.withScalaBinaryVersion(scalaVersion.split('.').take(2).mkString("."))
.withInput(s"org.scalameta:semanticdb-scalac_$scalaVersion:")
.complete()
.getCompletions()
.asScala
.lastOption
}(ExecutionContext.ioScheduler)

def version =
try
Await.result(versionFuture, FiniteDuration(10, "s"))
catch {
case _: Throwable => None
}

Option(supportedFallbackSemanticdbVersions.get(scalaVersion)).orElse(version) match {
case None =>
Left(s"After retry no existing semanticdb version found for scala version $scalaVersion")
case Some(semanticdbVersion) =>
supportedFallbackSemanticdbVersions.put(scalaVersion, semanticdbVersion)
fetchPlugin(artifact.copy(version = semanticdbVersion), logger)
}
}

@volatile private var latestResolvedScalaSemanticDB: Path = null
def fetchScalaPlugin(
scalaVersion: String,
Expand All @@ -77,7 +121,16 @@ object SemanticDBCache {
latestResolvedPlugin
}
}
} else fetchPlugin(artifact, logger)
} else {
fetchPlugin(artifact, logger) match {
case Right(plugin) => Right(plugin)
case Left(error) =>
fallbackSemanticdbFetch(scalaVersion, artifact, logger) match {
case Left(newError) => Left(error + "\n" + newError)
case Right(plugin) => Right(plugin)
}
}
}
}

@volatile private var latestResolvedJavaSemanticDB: Path = null
Expand Down
60 changes: 34 additions & 26 deletions frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,32 +87,6 @@ class BspMetalsClientSpec(
}
}

test("do not initialize metals client and save settings with unsupported scala version") {
TestUtil.withinWorkspace { workspace =>
val `A` = TestProject(workspace, "A", Nil, scalaVersion = Some("2.12.4"))
val projects = List(`A`)
val configDir = TestProject.populateWorkspace(workspace, projects)
val logger = new RecordingLogger(ansiCodesSupported = false)
val extraParams = BloopExtraBuildParams(
ownsBuildFiles = None,
clientClassesRootDir = None,
semanticdbVersion = Some(semanticdbVersion), // Doesn't support 2.12.4
supportedScalaVersions = Some(List(testedScalaVersion)),
javaSemanticdbVersion = Some(javaSemanticdbVersion)
)

loadBspState(workspace, projects, logger, "Metals", bloopExtraParams = extraParams) { state =>
assertNoDiffInSettingsFile(
configDir,
expectedConfig
)
// Expect only range positions to be added, semanticdb is not supported
assertScalacOptions(state, `A`, "-Yrangepos")
assertNoDiff(logger.warnings.mkString(lineSeparator), "")
}
}
}

test("initialize metals client in workspace with already enabled semanticdb") {
TestUtil.withinWorkspace { workspace =>
val pluginPath = s"-Xplugin:path-to-plugin/$semanticdbJar"
Expand Down Expand Up @@ -333,6 +307,40 @@ class BspMetalsClientSpec(
}
}

test("compile with old semanticDB") {
TestUtil.withinWorkspace { workspace =>
object JavacOptions {
// This will cause to use the forked javac compiler, since addong any `-J` property causes it
val A = List("-J-Xms48m")
}

val `A` =
TestProject(
workspace,
"A",
dummyFooScalaAndBarJavaSources,
javacOptions = JavacOptions.A,
// this Scala version is not supported in the newest semanticdb
scalaVersion = Some("2.12.8")
)
val projects = List(`A`)
val configDir = TestProject.populateWorkspace(workspace, projects)
val logger = new RecordingLogger(ansiCodesSupported = false)
WorkspaceSettings.writeToFile(
configDir,
WorkspaceSettings
.fromSemanticdbSettings("0.5.7", semanticdbVersion, List(testedScalaVersion)),
logger
)
loadBspState(workspace, projects, logger) { state =>
val compiledState = state.compile(`A`).toTestState
assert(compiledState.status == ExitStatus.Ok)
assertSemanticdbFileFor("Foo.scala", compiledState)
assertSemanticdbFileFor("Bar.java", compiledState)
}
}
}

test("compile with semanticDB using cached plugin") {
TestUtil.withinWorkspace { workspace =>
val `A` = TestProject(workspace, "A", dummyFooScalaAndBarJavaSources)
Expand Down

0 comments on commit d46a3fa

Please sign in to comment.