Refactor bspBuildTargetSources to be an input task + ScopeFilter

This commit is contained in:
Eugene Yokota 2020-02-24 00:23:19 -05:00 committed by Adrien Piquerez
parent 1ccff0ca6d
commit 10b2154d2e
4 changed files with 82 additions and 53 deletions

View File

@ -43,6 +43,7 @@ import sbt.internal.librarymanagement.mavenint.{
import sbt.internal.librarymanagement.{ CustomHttp => _, _ }
import sbt.internal.nio.{ CheckBuildSources, Globs }
import sbt.internal.server.{
BuildServerProtocol,
Definition,
LanguageServerProtocol,
LanguageServerReporter,
@ -383,7 +384,9 @@ object Defaults extends BuildCommon {
sys.env.contains("CI") || SysProp.ci,
// watch related settings
pollInterval :== Watch.defaultPollInterval,
) ++ LintUnused.lintSettings ++ DefaultBackgroundJobService.backgroundJobServiceSettings
) ++ BuildServerProtocol.globalSettings
++ LintUnused.lintSettings
++ DefaultBackgroundJobService.backgroundJobServiceSettings
)
def defaultTestTasks(key: Scoped): Seq[Setting[_]] =
@ -2219,7 +2222,7 @@ object Classpaths {
val stamper = (managedSourcePaths / outputFileStamper).value
dependencyClasspathFiles.value.flatMap(p => cache.getOrElseUpdate(p, stamper).map(p -> _))
}
)
) ++ BuildServerProtocol.configSettings
private[this] def exportClasspath(s: Setting[Task[Classpath]]): Setting[Task[Classpath]] =
s.mapInitialize(init => Def.task { exportClasspath(streams.value, init.value) })

View File

@ -21,6 +21,7 @@ import sbt.Def.ScopedKey
import sbt.KeyRanks._
import sbt.internal.InMemoryCacheStore.CacheStoreFactoryFactory
import sbt.internal._
import sbt.internal.bsp._
import sbt.internal.inc.ScalaInstance
import sbt.internal.io.WatchState
import sbt.internal.librarymanagement.{ CompatibilityWarningOptions, IvySbt }
@ -337,6 +338,9 @@ object Keys {
val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on")
val closeClassLoaders = settingKey[Boolean]("Close classloaders in run and test when the task completes.").withRank(DSetting)
val allowZombieClassLoaders = settingKey[Boolean]("Allow a classloader that has previously been closed by `run` or `test` to continue loading classes.")
val buildTargetIdentifier = settingKey[BuildTargetIdentifier]("Id for BSP build target.").withRank(DSetting)
val bspBuildTargetSources = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetSourceItem = taskKey[SourcesItem]("").withRank(DTask)
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)

View File

@ -11,49 +11,69 @@ package server
import java.net.URI
import sbt.internal.bsp._
import sbt.internal.util.complete.DefaultParsers
import sbt.librarymanagement.{ Configuration, Configurations }
import Configurations.{ Compile, Test }
import sbt.SlashSyntax0._
import sbt.BuildSyntax._
import scala.collection.mutable
import sjsonnew.support.scalajson.unsafe.Converter
import Def._
import Keys._
import ScopeFilter.Make._
object BuildServerProtocol {
private[sbt] val idMap: mutable.Map[BuildTargetIdentifier, (ProjectRef, Configuration)] =
mutable.Map.empty
val BspBuildTargetSource = "bspBuildTargetSources"
def commands: List[Command] = List(bspBuildTargetSources)
def commands: List[Command] = List()
/**
* Command that expects list of URIs.
* https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
*/
def bspBuildTargetSources: Command = Command.args(BspBuildTargetSource, "<args>") {
(s0: State, args: Seq[String]) =>
import sbt.internal.bsp.codec.JsonProtocol._
var s: State = s0
val items = args map { arg =>
val id = BuildTargetIdentifier(new URI(arg))
val pair = idMap(id)
println(pair.toString)
val dirs = s0.setting(pair._1 / pair._2 / Keys.unmanagedSourceDirectories)
val (next, managed) = s.unsafeRunTask(pair._1 / pair._2 / Keys.managedSources)
s = next
val items = (dirs.toVector map { dir =>
SourceItem(dir.toURI, SourceItemKind.Directory, false)
}) ++
(managed.toVector map { x =>
SourceItem(x.toURI, SourceItemKind.File, true)
})
SourcesItem(id, items)
lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
// https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
bspBuildTargetSources := (Def.inputTaskDyn {
import DefaultParsers._
val s = state.value
val args: Seq[String] = spaceDelimited("<arg>").parsed
val filter = toScopeFilter(args)
// run bspBuildTargetSourceItem concurrently
Def.task {
import sbt.internal.bsp.codec.JsonProtocol._
val items = bspBuildTargetSourceItem.all(filter).value
val result = SourcesResult(items.toVector)
s.respondEvent(result)
}
val result = SourcesResult(items.toVector)
s0.respondEvent(result)
s
}
}).evaluated
)
// def json(s: String): JValue = Parser.parseUnsafe(s)
// This will be coped to Compile, Test, etc
lazy val configSettings: Seq[Def.Setting[_]] = Seq(
buildTargetIdentifier := {
val ref = thisProjectRef.value
val c = configuration.value
toId(ref, c)
},
bspBuildTargetSourceItem := {
val id = buildTargetIdentifier.value
val dirs = unmanagedSourceDirectories.value
val managed = managedSources.value
val items = (dirs.toVector map { dir =>
SourceItem(dir.toURI, SourceItemKind.Directory, false)
}) ++
(managed.toVector map { x =>
SourceItem(x.toURI, SourceItemKind.File, true)
})
SourcesItem(id, items)
}
)
def toScopeFilter(args: Seq[String]): ScopeFilter = {
val filters = args map { arg =>
val id = BuildTargetIdentifier(new URI(arg))
val pair = idMap(id)
ScopeFilter(inProjects(pair._1), inConfigurations(pair._2))
}
filters.tail.foldLeft(filters.head) { _ || _ }
}
def toId(ref: ProjectReference, config: Configuration): BuildTargetIdentifier =
ref match {
@ -61,25 +81,6 @@ object BuildServerProtocol {
BuildTargetIdentifier(new URI(s"$build#$project/${config.id}"))
case _ => sys.error(s"unexpected $ref")
}
def idForConfig(
ref: ClasspathDep[ProjectRef],
from: Configuration
): Seq[BuildTargetIdentifier] = {
val configStr = ref.configuration.getOrElse("compile")
val configExprs0 = configStr.split(",").toList
val configExprs1 = configExprs0 map { expr =>
if (expr.contains("->")) {
val xs = expr.split("->")
(xs(0), xs(1))
} else ("compile", expr)
}
configExprs1 flatMap {
case (fr, "compile") if fr == from.name => Some(toId(ref.project, Compile))
case (fr, "test") if fr == from.name => Some(toId(ref.project, Test))
case _ => None
}
}
}
// This is mixed into NetworkChannel
@ -117,7 +118,7 @@ trait BuildServerImpl { self: LanguageServerProtocol with NetworkChannel =>
case (p, ref) =>
val baseOpt = getSetting(ref / Keys.baseDirectory).map(_.toURI)
val internalCompileDeps = p.dependencies.flatMap(idForConfig(_, Compile)).toVector
val compileId = toId(ref, Compile)
val compileId = getSetting(ref / Compile / Keys.buildTargetIdentifier).get
idMap(compileId) = (ref, Compile)
val compileData = ScalaBuildTarget(
scalaOrganization = getSetting(ref / Compile / Keys.scalaOrganization).get,
@ -136,7 +137,7 @@ trait BuildServerImpl { self: LanguageServerProtocol with NetworkChannel =>
dataKind = Some("scala"),
data = Some(Converter.toJsonUnsafe(compileData)),
)
val testId = toId(ref, Test)
val testId = getSetting(ref / Test / Keys.buildTargetIdentifier).get
idMap(testId) = (ref, Test)
// encode Test extending Compile
val internalTestDeps =
@ -164,4 +165,25 @@ trait BuildServerImpl { self: LanguageServerProtocol with NetworkChannel =>
}
WorkspaceBuildTargetsResult(ts.toVector)
}
def idForConfig(
ref: ClasspathDep[ProjectRef],
from: Configuration
): Seq[BuildTargetIdentifier] = {
val configStr = ref.configuration.getOrElse("compile")
val configExprs0 = configStr.split(",").toList
val configExprs1 = configExprs0 map { expr =>
if (expr.contains("->")) {
val xs = expr.split("->")
(xs(0), xs(1))
} else ("compile", expr)
}
configExprs1 flatMap {
case (fr, "compile") if fr == from.name =>
Some(getSetting(ref.project / Compile / Keys.buildTargetIdentifier).get)
case (fr, "test") if fr == from.name =>
Some(getSetting(ref.project / Test / Keys.buildTargetIdentifier).get)
case _ => None
}
}
}

View File

@ -109,7 +109,7 @@ private[sbt] object LanguageServerProtocol {
val param = Converter.fromJson[SourcesParams](json(r)).get
appendExec(
Exec(
s"""${BuildServerProtocol.BspBuildTargetSource} ${param.targets
s"""${Keys.bspBuildTargetSources.key} ${param.targets
.map(_.uri)
.mkString(" ")}""",
Option(r.id),