Skip to content

Commit

Permalink
Resolve Scala SDK independently for each target
Browse files Browse the repository at this point in the history
This prepares us for changes in `rules_scala` that will allow customizing the Scala version for each target.
In order to achieve that, we can no longer resolve the Scala SDK globally as the maximal version used. We need to use per-target info.
Scala SDK will be still discovered based on the compiler class path.
Now though we will look into an implicit dependency of each target, the `_scalac`.

This change is backward-compatible, as the mentioned data is already available.
It is also forward-compatible with the anticipated cross-build feature of `rules_scala`.
(see: bazelbuild/rules_scala#1290)

The aspect will produce additional data – namely few compiler classpath jars per Scala target.
Perhaps we could review this change in the future to normalize the data back. Now it's not possible, as the data about alternative configurations (here: of scalac) is discarded in the server.
  • Loading branch information
aszady committed Apr 10, 2024
1 parent 86a3f57 commit 08d034a
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 29 deletions.
4 changes: 4 additions & 0 deletions aspects/rules/scala/scala_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ def extract_scala_info(target, ctx, output_groups, **kwargs):
# check of _scala_toolchain is necessary, because SCALA_TOOLCHAIN will always be present
if hasattr(ctx.rule.attr, "_scala_toolchain"):
common_scalac_opts = ctx.toolchains[SCALA_TOOLCHAIN].scalacopts
if hasattr(ctx.rule.attr, "_scalac"):
compiler_classpath = find_scalac_classpath(ctx.rule.attr._scalac.default_runfiles.files.to_list())
if compiler_classpath:
scala_info["compiler_classpath"] = map(file_location, compiler_classpath)
else:
common_scalac_opts = []
scala_info["scalac_opts"] = common_scalac_opts + getattr(ctx.rule.attr, "scalacopts", [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,29 +179,27 @@ class BazelProjectMapper(
private fun calculateScalaLibrariesMapper(targetsToImport: Sequence<TargetInfo>): Map<String, List<Library>> {
val projectLevelScalaSdkLibraries = calculateProjectLevelScalaLibraries()
val scalaTargets = targetsToImport.filter { it.hasScalaTargetInfo() }.map { it.id }
return projectLevelScalaSdkLibraries
?.let { libraries -> scalaTargets.associateWith { libraries } }
.orEmpty()
return scalaTargets.associateWith {
languagePluginsService.scalaLanguagePlugin.scalaSdks[it]?.compilerJars?.mapNotNull {
projectLevelScalaSdkLibraries[it]
}.orEmpty()
}
}

private fun calculateProjectLevelScalaLibraries(): List<Library>? {
val scalaSdkLibrariesJars = getProjectLevelScalaSdkLibrariesJars()
return if (scalaSdkLibrariesJars.isNotEmpty()) {
scalaSdkLibrariesJars.map {
Library(
label = Paths.get(it).name,
outputs = setOf(it),
sources = emptySet(),
dependencies = emptyList()
)
}
} else null
}
private fun calculateProjectLevelScalaLibraries(): Map<URI, Library> =
getProjectLevelScalaSdkLibrariesJars().associateWith {
Library(
label = Paths.get(it).name,
outputs = setOf(it),
sources = emptySet(),
dependencies = emptyList()
)
}

private fun getProjectLevelScalaSdkLibrariesJars(): Set<URI> =
languagePluginsService.scalaLanguagePlugin.scalaSdk
?.compilerJars
?.toSet().orEmpty()
languagePluginsService.scalaLanguagePlugin.scalaSdks.values.toSet().flatMap {
it.compilerJars
}.toSet()

private fun calculateAndroidLibrariesMapper(targetsToImport: Sequence<TargetInfo>): Map<String, List<Library>> =
targetsToImport.mapNotNull { target ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,25 @@ class ScalaLanguagePlugin(
private val bazelPathsResolver: BazelPathsResolver
) : LanguagePlugin<ScalaModule>() {

var scalaSdk: ScalaSdk? = null
var scalaSdks: Map<String, ScalaSdk> = emptyMap()

override fun prepareSync(targets: Sequence<BspTargetInfo.TargetInfo>) {
scalaSdk = ScalaSdkResolver(bazelPathsResolver).resolve(targets)
scalaSdks = targets.associateBy(
{ it.id },
ScalaSdkResolver(bazelPathsResolver)::resolveSdk
).filterValues{ it != null }.mapValues{ it.value!! }
}

override fun resolveModule(targetInfo: BspTargetInfo.TargetInfo): ScalaModule? {
if (!targetInfo.hasScalaTargetInfo()) {
return null
}
val scalaTargetInfo = targetInfo.scalaTargetInfo
val sdk = getScalaSdkOrThrow()
val sdk = scalaSdks[targetInfo.id] ?: return null
val scalacOpts = scalaTargetInfo.scalacOptsList
return ScalaModule(sdk, scalacOpts, javaLanguagePlugin.resolveModule(targetInfo))
}

private fun getScalaSdkOrThrow(): ScalaSdk =
scalaSdk ?: throw RuntimeException("Failed to resolve Scala SDK for project")

override fun dependencySources(
targetInfo: BspTargetInfo.TargetInfo,
dependencyGraph: DependencyGraph
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ class ScalaSdkResolver(private val bazelPathsResolver: BazelPathsResolver) {
.sortedWith(SCALA_VERSION_COMPARATOR)
.lastOrNull()

private fun resolveSdk(targetInfo: BspTargetInfo.TargetInfo): ScalaSdk? {
if (!targetInfo.hasScalaToolchainInfo()) {
fun resolveSdk(targetInfo: BspTargetInfo.TargetInfo): ScalaSdk? {
if (!targetInfo.hasScalaTargetInfo()) {
return null
}
val scalaToolchain = targetInfo.scalaToolchainInfo
val scalaTarget = targetInfo.scalaTargetInfo
val compilerJars =
bazelPathsResolver.resolvePaths(scalaToolchain.compilerClasspathList).sorted()
bazelPathsResolver.resolvePaths(scalaTarget.compilerClasspathList).sorted()
val maybeVersions = compilerJars.mapNotNull(::extractVersion)
if (maybeVersions.none()) {
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ message JavaRuntimeInfo {

message ScalaTargetInfo {
repeated string scalac_opts = 1;
repeated FileLocation compiler_classpath = 2;
}

message ScalaToolchainInfo {
Expand Down

0 comments on commit 08d034a

Please sign in to comment.