mirror of https://github.com/sbt/sbt.git
fix internal transitive mgmt in BSP
This commit is contained in:
parent
068fe2ad0a
commit
98750817c6
|
|
@ -349,6 +349,7 @@ object Keys {
|
||||||
val bspBuildTargetCompileItem = taskKey[Int]("").withRank(DTask)
|
val bspBuildTargetCompileItem = taskKey[Int]("").withRank(DTask)
|
||||||
val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask)
|
val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask)
|
||||||
val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask)
|
val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask)
|
||||||
|
val bspInternalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on, possibly transitivly")
|
||||||
|
|
||||||
val useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)
|
val useCoursier = settingKey[Boolean]("Use Coursier for dependency resolution.").withRank(BSetting)
|
||||||
val csrCacheDirectory = settingKey[File]("Coursier cache directory. Uses -Dsbt.coursier.home or Coursier's default.").withRank(CSetting)
|
val csrCacheDirectory = settingKey[File]("Coursier cache directory. Uses -Dsbt.coursier.home or Coursier's default.").withRank(CSetting)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import sbt.internal.bsp._
|
||||||
import sbt.internal.langserver.ErrorCodes
|
import sbt.internal.langserver.ErrorCodes
|
||||||
import sbt.internal.protocol.JsonRpcRequestMessage
|
import sbt.internal.protocol.JsonRpcRequestMessage
|
||||||
import sbt.librarymanagement.Configuration
|
import sbt.librarymanagement.Configuration
|
||||||
import sbt.librarymanagement.Configurations.{ Compile, Test }
|
|
||||||
import sjsonnew.shaded.scalajson.ast.unsafe.JValue
|
import sjsonnew.shaded.scalajson.ast.unsafe.JValue
|
||||||
import sjsonnew.support.scalajson.unsafe.Converter
|
import sjsonnew.support.scalajson.unsafe.Converter
|
||||||
|
|
||||||
|
|
@ -28,19 +27,19 @@ object BuildServerProtocol {
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
import sbt.internal.bsp.codec.JsonProtocol._
|
||||||
private val bspVersion = "2.0.0-M5"
|
private val bspVersion = "2.0.0-M5"
|
||||||
private val languageIds = Vector("scala")
|
private val languageIds = Vector("scala")
|
||||||
|
private val bspTargetConfigs = Set("compile", "test")
|
||||||
private val capabilities = BuildServerCapabilities(CompileProvider(languageIds))
|
private val capabilities = BuildServerCapabilities(CompileProvider(languageIds))
|
||||||
|
|
||||||
lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
|
lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
|
||||||
bspWorkspace := Def.taskDyn {
|
bspWorkspace := Def.taskDyn {
|
||||||
val structure = Keys.buildStructure.value
|
val structure = Keys.buildStructure.value
|
||||||
val scopes: Seq[Scope] = structure.allProjectRefs.flatMap { ref =>
|
val scopes: Seq[Scope] = structure.allProjectRefs.flatMap { ref =>
|
||||||
Seq(Scope.Global.in(ref, Compile), Scope.Global.in(ref, Test))
|
bspTargetConfigs.toSeq.map(name => Scope.Global.in(ref, ConfigKey(name)))
|
||||||
}
|
}
|
||||||
Def.task {
|
Def.task {
|
||||||
val targetIds = scopes.map(_ / Keys.buildTargetIdentifier).join.value
|
val targetIds = scopes.map(_ / Keys.buildTargetIdentifier).join.value
|
||||||
targetIds.zip(scopes).toMap
|
targetIds.zip(scopes).toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
}.value,
|
}.value,
|
||||||
bspWorkspaceBuildTargets := Def.taskDyn {
|
bspWorkspaceBuildTargets := Def.taskDyn {
|
||||||
val workspace = Keys.bspWorkspace.value
|
val workspace = Keys.bspWorkspace.value
|
||||||
|
|
@ -100,7 +99,7 @@ object BuildServerProtocol {
|
||||||
val c = configuration.value
|
val c = configuration.value
|
||||||
toId(ref, c)
|
toId(ref, c)
|
||||||
},
|
},
|
||||||
bspBuildTarget := bspBuildTargetTask.value,
|
bspBuildTarget := buildTargetTask.value,
|
||||||
bspBuildTargetSourcesItem := {
|
bspBuildTargetSourcesItem := {
|
||||||
val id = buildTargetIdentifier.value
|
val id = buildTargetIdentifier.value
|
||||||
val dirs = unmanagedSourceDirectories.value
|
val dirs = unmanagedSourceDirectories.value
|
||||||
|
|
@ -114,14 +113,8 @@ object BuildServerProtocol {
|
||||||
SourcesItem(id, items)
|
SourcesItem(id, items)
|
||||||
},
|
},
|
||||||
bspBuildTargetCompileItem := bspCompileTask.value,
|
bspBuildTargetCompileItem := bspCompileTask.value,
|
||||||
bspBuildTargetScalacOptionsItem := {
|
bspBuildTargetScalacOptionsItem := scalacOptionsTask.value,
|
||||||
ScalacOptionsItem(
|
bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value
|
||||||
target = buildTargetIdentifier.value,
|
|
||||||
options = scalacOptions.value.toVector,
|
|
||||||
classpath = dependencyClasspath.value.map(_.data.toURI).toVector,
|
|
||||||
classDirectory = classDirectory.value.toURI
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def handler(sbtVersion: String): ServerHandler = ServerHandler { callback =>
|
def handler(sbtVersion: String): ServerHandler = ServerHandler { callback =>
|
||||||
|
|
@ -133,34 +126,32 @@ object BuildServerProtocol {
|
||||||
callback.jsonRpcRespond(response, Some(r.id)); ()
|
callback.jsonRpcRespond(response, Some(r.id)); ()
|
||||||
|
|
||||||
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
|
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
|
||||||
val _ = callback.appendExec(Keys.bspWorkspaceBuildTargets.key.toString, None)
|
val _ = callback.appendExec(Keys.bspWorkspaceBuildTargets.key.toString, Some(r.id))
|
||||||
|
|
||||||
case r: JsonRpcRequestMessage if r.method == "build/shutdown" =>
|
case r: JsonRpcRequestMessage if r.method == "build/shutdown" =>
|
||||||
()
|
()
|
||||||
|
|
||||||
case r: JsonRpcRequestMessage if r.method == "build/exit" =>
|
case r: JsonRpcRequestMessage if r.method == "build/exit" =>
|
||||||
val _ = callback.appendExec("shutdown", None)
|
val _ = callback.appendExec("shutdown", Some(r.id))
|
||||||
|
|
||||||
case r: JsonRpcRequestMessage if r.method == "buildTarget/sources" =>
|
case r: JsonRpcRequestMessage if r.method == "buildTarget/sources" =>
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val param = Converter.fromJson[SourcesParams](json(r)).get
|
val param = Converter.fromJson[SourcesParams](json(r)).get
|
||||||
val targets = param.targets.map(_.uri).mkString(" ")
|
val targets = param.targets.map(_.uri).mkString(" ")
|
||||||
val command = Keys.bspBuildTargetSources.key
|
val command = Keys.bspBuildTargetSources.key
|
||||||
val _ = callback.appendExec(s"$command $targets", None)
|
val _ = callback.appendExec(s"$command $targets", Some(r.id))
|
||||||
|
|
||||||
case r if r.method == "buildTarget/compile" =>
|
case r if r.method == "buildTarget/compile" =>
|
||||||
val param = Converter.fromJson[CompileParams](json(r)).get
|
val param = Converter.fromJson[CompileParams](json(r)).get
|
||||||
callback.log.info(param.toString)
|
callback.log.info(param.toString)
|
||||||
val targets = param.targets.map(_.uri).mkString(" ")
|
val targets = param.targets.map(_.uri).mkString(" ")
|
||||||
val command = Keys.bspBuildTargetCompile.key
|
val command = Keys.bspBuildTargetCompile.key
|
||||||
val _ = callback.appendExec(s"$command $targets", None)
|
val _ = callback.appendExec(s"$command $targets", Some(r.id))
|
||||||
|
|
||||||
case r: JsonRpcRequestMessage if r.method == "buildTarget/scalacOptions" =>
|
case r: JsonRpcRequestMessage if r.method == "buildTarget/scalacOptions" =>
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val param = Converter.fromJson[ScalacOptionsParams](json(r)).get
|
val param = Converter.fromJson[ScalacOptionsParams](json(r)).get
|
||||||
val targets = param.targets.map(_.uri).mkString(" ")
|
val targets = param.targets.map(_.uri).mkString(" ")
|
||||||
val command = Keys.bspBuildTargetScalacOptions.key
|
val command = Keys.bspBuildTargetScalacOptions.key
|
||||||
val _ = callback.appendExec(s"$command $targets", None)
|
val _ = callback.appendExec(s"$command $targets", Some(r.id))
|
||||||
},
|
},
|
||||||
PartialFunction.empty
|
PartialFunction.empty
|
||||||
)
|
)
|
||||||
|
|
@ -174,11 +165,11 @@ object BuildServerProtocol {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private def bspBuildTargetTask: Def.Initialize[Task[BuildTarget]] = Def.taskDyn {
|
private def buildTargetTask: Def.Initialize[Task[BuildTarget]] = Def.taskDyn {
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val buildTargetIdentifier = Keys.buildTargetIdentifier.value
|
val buildTargetIdentifier = Keys.buildTargetIdentifier.value
|
||||||
val thisProject = Keys.thisProject.value
|
val thisProject = Keys.thisProject.value
|
||||||
val thisProjectRef = Keys.thisProjectRef.value
|
val thisProjectRef = Keys.thisProjectRef.value
|
||||||
|
val thisConfig = Keys.configuration.value
|
||||||
val scalaJars = Keys.scalaInstance.value.allJars.map(_.toURI.toString)
|
val scalaJars = Keys.scalaInstance.value.allJars.map(_.toURI.toString)
|
||||||
val compileData = ScalaBuildTarget(
|
val compileData = ScalaBuildTarget(
|
||||||
scalaOrganization = scalaOrganization.value,
|
scalaOrganization = scalaOrganization.value,
|
||||||
|
|
@ -193,34 +184,50 @@ object BuildServerProtocol {
|
||||||
case configName => s"${thisProject.id}-$configName"
|
case configName => s"${thisProject.id}-$configName"
|
||||||
}
|
}
|
||||||
val baseDirectory = Keys.baseDirectory.value.toURI
|
val baseDirectory = Keys.baseDirectory.value.toURI
|
||||||
val allDependencies = configuration.name match {
|
val projectDependencies = for {
|
||||||
case "test" =>
|
(dep, configs) <- Keys.bspInternalDependencyConfigurations.value
|
||||||
thisProject.dependencies :+
|
config <- configs if (dep != thisProjectRef || config != thisConfig.name) && bspTargetConfigs.contains(config)
|
||||||
ResolvedClasspathDependency(thisProjectRef, Some("test->compile"))
|
} yield Keys.buildTargetIdentifier.in(dep, ConfigKey(config))
|
||||||
case _ => thisProject.dependencies
|
|
||||||
}
|
|
||||||
val capabilities = BuildTargetCapabilities(canCompile = true, canTest = false, canRun = false)
|
val capabilities = BuildTargetCapabilities(canCompile = true, canTest = false, canRun = false)
|
||||||
val tags = BuildTargetTag.fromConfig(configuration.name)
|
val tags = BuildTargetTag.fromConfig(configuration.name)
|
||||||
Def.task {
|
Def.task {
|
||||||
val allDepIds = allDependencies
|
|
||||||
.flatMap(dependencyTargetKeys(_, configuration))
|
|
||||||
.join
|
|
||||||
.value
|
|
||||||
|
|
||||||
BuildTarget(
|
BuildTarget(
|
||||||
buildTargetIdentifier,
|
buildTargetIdentifier,
|
||||||
Some(displayName),
|
Some(displayName),
|
||||||
Some(baseDirectory),
|
Some(baseDirectory),
|
||||||
tags,
|
tags,
|
||||||
capabilities,
|
capabilities,
|
||||||
languageIds = Vector("scala"),
|
languageIds,
|
||||||
dependencies = allDepIds.toVector,
|
projectDependencies.join.value.toVector,
|
||||||
dataKind = Some("scala"),
|
dataKind = Some("scala"),
|
||||||
data = Some(Converter.toJsonUnsafe(compileData)),
|
data = Some(Converter.toJsonUnsafe(compileData)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn {
|
||||||
|
val target = Keys.buildTargetIdentifier.value
|
||||||
|
val scalacOptions = Keys.scalacOptions.value
|
||||||
|
val classDirectory = Keys.classDirectory.value
|
||||||
|
val externalDependencyClasspath = Keys.externalDependencyClasspath.value
|
||||||
|
|
||||||
|
val internalDependencyClasspath = for {
|
||||||
|
(ref, configs) <- bspInternalDependencyConfigurations.value
|
||||||
|
config <- configs
|
||||||
|
} yield Keys.classDirectory.in(ref, ConfigKey(config))
|
||||||
|
|
||||||
|
Def.task {
|
||||||
|
val classpath = internalDependencyClasspath.join.value.distinct ++
|
||||||
|
externalDependencyClasspath.map(_.data)
|
||||||
|
ScalacOptionsItem(
|
||||||
|
target,
|
||||||
|
scalacOptions.toVector,
|
||||||
|
classpath.map(_.toURI).toVector,
|
||||||
|
classDirectory.toURI
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private def bspCompileTask: Def.Initialize[Task[Int]] = Def.task {
|
private def bspCompileTask: Def.Initialize[Task[Int]] = Def.task {
|
||||||
import sbt.Project._
|
import sbt.Project._
|
||||||
Keys.compile.result.value match {
|
Keys.compile.result.value match {
|
||||||
|
|
@ -231,6 +238,25 @@ object BuildServerProtocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def internalDependencyConfigurationsSetting = Def.settingDyn {
|
||||||
|
val directDependencies = Keys.internalDependencyConfigurations.value
|
||||||
|
val ref = Keys.thisProjectRef.value
|
||||||
|
val thisConfig = Keys.configuration.value
|
||||||
|
val transitiveDependencies = for {
|
||||||
|
(dep, configs) <- directDependencies
|
||||||
|
config <- configs if dep != ref || config != thisConfig.name
|
||||||
|
} yield Keys.bspInternalDependencyConfigurations.in(dep, ConfigKey(config))
|
||||||
|
Def.setting {
|
||||||
|
val allDependencies = directDependencies ++ transitiveDependencies.join.value.flatten
|
||||||
|
allDependencies
|
||||||
|
.groupBy(_._1)
|
||||||
|
.mapValues { deps =>
|
||||||
|
deps.flatMap { case (_, configs) => configs }.toSet
|
||||||
|
}
|
||||||
|
.toSeq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def scopeFilter(
|
def scopeFilter(
|
||||||
targets: Seq[BuildTargetIdentifier],
|
targets: Seq[BuildTargetIdentifier],
|
||||||
workspace: Map[BuildTargetIdentifier, Scope]
|
workspace: Map[BuildTargetIdentifier, Scope]
|
||||||
|
|
@ -244,22 +270,4 @@ object BuildServerProtocol {
|
||||||
BuildTargetIdentifier(new URI(s"$build#$project/${config.id}"))
|
BuildTargetIdentifier(new URI(s"$build#$project/${config.id}"))
|
||||||
case _ => sys.error(s"unexpected $ref")
|
case _ => sys.error(s"unexpected $ref")
|
||||||
}
|
}
|
||||||
|
|
||||||
private def dependencyTargetKeys(
|
|
||||||
ref: ClasspathDep[ProjectRef],
|
|
||||||
fromConfig: Configuration
|
|
||||||
): Seq[SettingKey[BuildTargetIdentifier]] = {
|
|
||||||
val from = fromConfig.name
|
|
||||||
val depConfig = ref.configuration.getOrElse("compile")
|
|
||||||
for {
|
|
||||||
configExpr <- depConfig.split(",").toSeq
|
|
||||||
depId <- configExpr.split("->").toList match {
|
|
||||||
case "compile" :: Nil | `from` :: "compile" :: Nil =>
|
|
||||||
Some(ref.project / Compile / Keys.buildTargetIdentifier)
|
|
||||||
case "test" :: Nil | `from` :: "test" :: Nil =>
|
|
||||||
Some(ref.project / Test / Keys.buildTargetIdentifier)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
} yield depId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue