Fix compilation

This commit is contained in:
Adrien Piquerez 2024-06-04 14:49:37 +02:00
parent 1034fb1859
commit 492cd2c091
17 changed files with 165 additions and 333 deletions

View File

@ -368,7 +368,7 @@ lazy val utilLogging = project
disruptor,
sjsonNewScalaJson.value,
),
libraryDependencies ++= Seq(scalacheck % "test", scalatest % "test"),
testDependencies,
Compile / generateContrabands / contrabandCodecsDependencies := List(sjsonNewCore.value),
Compile / generateContrabands / sourceManaged := baseDirectory.value / "src" / "main" / "contraband-scala",
Compile / managedSourceDirectories +=

View File

@ -21,7 +21,7 @@ import sbt.internal.util.MessageOnlyException
import sbt.internal.util.complete.DefaultParsers._
import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.io.IO
import sbt.librarymanagement.{ CrossVersion, SemanticSelector, VersionNumber }
import sbt.librarymanagement.{ SemanticSelector, VersionNumber }
/**
* Cross implements the Scala cross building commands:

View File

@ -2730,7 +2730,12 @@ object Defaults extends BuildCommon {
)
},
bspCompileTask :=
BspCompileTask.start(bspTargetIdentifier.value, thisProjectRef.value, configuration.value)
BspCompileTask.start(
bspTargetIdentifier.value,
thisProjectRef.value,
configuration.value,
compileInputs.value
)
)
}
@ -3148,7 +3153,7 @@ object Classpaths {
private lazy val publishSbtPluginMavenStyle = Def.task(sbtPlugin.value && publishMavenStyle.value)
private lazy val packagedDefaultArtifacts = packaged(defaultArtifactTasks)
private lazy val emptyArtifacts = Def.task(Map.empty[Artifact, File])
private lazy val emptyArtifacts = Def.task(Map.empty[Artifact, HashedVirtualFileRef])
val jvmPublishSettings: Seq[Setting[_]] = Seq(
artifacts := artifactDefs(defaultArtifactTasks).value,
@ -3159,7 +3164,7 @@ object Classpaths {
publishLocal / packagedArtifacts ++= {
if (sbtPlugin.value && !sbtPluginPublishLegacyMavenStyle.value) {
packagedDefaultArtifacts.value
} else Map.empty[Artifact, File]
} else Map.empty[Artifact, HashedVirtualFileRef]
}
) ++ RemoteCache.projectSettings
@ -3168,20 +3173,24 @@ object Classpaths {
* It adds the sbt-cross version suffix into the artifact names, and it generates a
* valid POM file, that is a POM file that Maven can resolve.
*/
private def mavenArtifactsOfSbtPlugin: Def.Initialize[Task[Map[Artifact, File]]] =
private def mavenArtifactsOfSbtPlugin: Def.Initialize[Task[Map[Artifact, HashedVirtualFileRef]]] =
Def.task {
val crossVersion = sbtCrossVersion.value
val legacyArtifact = (makePom / artifact).value
val pom = makeMavenPomOfSbtPlugin.value
val converter = fileConverter.value
val pom = converter.toVirtualFile(makeMavenPomOfSbtPlugin.value.toPath)
val legacyPackages = packaged(defaultPackages).value
def addSuffix(a: Artifact): Artifact = a.withName(crossVersion(a.name))
def copyArtifact(artifact: Artifact, file: File): (Artifact, File) = {
def copyArtifact(
artifact: Artifact,
fileRef: HashedVirtualFileRef
): (Artifact, HashedVirtualFileRef) = {
val nameWithSuffix = crossVersion(artifact.name)
val file = converter.toPath(fileRef).toFile
val targetFile =
new File(file.getParentFile, file.name.replace(artifact.name, nameWithSuffix))
IO.copyFile(file, targetFile)
artifact.withName(nameWithSuffix) -> targetFile
artifact.withName(nameWithSuffix) -> converter.toVirtualFile(targetFile.toPath)
}
val packages = legacyPackages.map { case (artifact, file) => copyArtifact(artifact, file) }
val legacyPackagedArtifacts = Def
@ -3376,10 +3385,7 @@ object Classpaths {
val sv = scalaVersion.value
s"$p/scala-$sv/$m"
},
ivyPaths := IvyPaths(
baseDirectory.value.toString,
bootIvyHome(appConfiguration.value).map(_.toString)
),
ivyPaths := IvyPaths(baseDirectory.value, bootIvyHome(appConfiguration.value)),
csrCacheDirectory := {
val old = csrCacheDirectory.value
val ac = appConfiguration.value
@ -3391,7 +3397,7 @@ object Classpaths {
else if (ip.ivyHome == defaultIvyCache) old
else
ip.ivyHome match {
case Some(home) => new File(home) / "coursier-cache"
case Some(home) => home / "coursier-cache"
case _ => old
}
} else Classpaths.dummyCoursierDirectory(ac)

View File

@ -162,7 +162,7 @@ final case class PluginData(
object PluginData {
private[sbt] def apply(dependencyClasspath: Def.Classpath, converter: FileConverter): PluginData =
PluginData(dependencyClasspath, Nil, None, None, Nil, Nil, Nil, Nil, Nil, None, converter)
PluginData(dependencyClasspath, Nil, None, None, Nil, Nil, Nil, Nil, Nil, Nil, None, converter)
}
object EvaluateTask {
@ -309,7 +309,7 @@ object EvaluateTask {
ExecuteProgress2.aggregate(reporters match {
case xs if xs.isEmpty => cmdProgress
case xs if xs.size == 1 => cmdProgress :+ new ExecuteProgressAdapter(xs.head)
case xs => cmdProgress :+ new ExecuteProgressAdapter(ExecuteProgress.aggregate[Task](xs))
case xs => cmdProgress :+ new ExecuteProgressAdapter(ExecuteProgress.aggregate(xs))
})
}
}

View File

@ -45,17 +45,18 @@ class ExecuteProgressAdapter(ep: ExecuteProgress) extends ExecuteProgress2 {
override def afterCommand(cmd: String, result: Either[Throwable, State]): Unit = {}
override def initial(): Unit = ep.initial()
override def afterRegistered(
task: Task[_],
allDeps: Iterable[Task[_]],
pendingDeps: Iterable[Task[_]]
task: TaskId[_],
allDeps: Iterable[TaskId[_]],
pendingDeps: Iterable[TaskId[_]]
): Unit = ep.afterRegistered(task, allDeps, pendingDeps)
override def afterReady(task: Task[_]): Unit = ep.afterReady(task)
override def beforeWork(task: Task[_]): Unit = ep.beforeWork(task)
override def afterWork[A](task: Task[A], result: Either[Task[A], Result[A]]): Unit =
override def afterReady(task: TaskId[_]): Unit = ep.afterReady(task)
override def beforeWork(task: TaskId[_]): Unit = ep.beforeWork(task)
override def afterWork[A](task: TaskId[A], result: Either[TaskId[A], Result[A]]): Unit =
ep.afterWork(task, result)
override def afterCompleted[A](task: Task[A], result: Result[A]): Unit =
override def afterCompleted[A](task: TaskId[A], result: Result[A]): Unit =
ep.afterCompleted(task, result)
override def afterAllCompleted(results: RMap[Task, Result]): Unit = ep.afterAllCompleted(results)
override def afterAllCompleted(results: RMap[TaskId, Result]): Unit =
ep.afterAllCompleted(results)
override def stop(): Unit = ep.stop()
}
@ -67,17 +68,17 @@ object ExecuteProgress2 {
xs.foreach(_.afterCommand(cmd, result))
override def initial(): Unit = xs.foreach(_.initial())
override def afterRegistered(
task: Task[_],
allDeps: Iterable[Task[_]],
pendingDeps: Iterable[Task[_]]
task: TaskId[_],
allDeps: Iterable[TaskId[_]],
pendingDeps: Iterable[TaskId[_]]
): Unit = xs.foreach(_.afterRegistered(task, allDeps, pendingDeps))
override def afterReady(task: Task[_]): Unit = xs.foreach(_.afterReady(task))
override def beforeWork(task: Task[_]): Unit = xs.foreach(_.beforeWork(task))
override def afterWork[A](task: Task[A], result: Either[Task[A], Result[A]]): Unit =
override def afterReady(task: TaskId[_]): Unit = xs.foreach(_.afterReady(task))
override def beforeWork(task: TaskId[_]): Unit = xs.foreach(_.beforeWork(task))
override def afterWork[A](task: TaskId[A], result: Either[TaskId[A], Result[A]]): Unit =
xs.foreach(_.afterWork(task, result))
override def afterCompleted[A](task: Task[A], result: Result[A]): Unit =
override def afterCompleted[A](task: TaskId[A], result: Result[A]): Unit =
xs.foreach(_.afterCompleted(task, result))
override def afterAllCompleted(results: RMap[Task, Result]): Unit =
override def afterAllCompleted(results: RMap[TaskId, Result]): Unit =
xs.foreach(_.afterAllCompleted(results))
override def stop(): Unit = xs.foreach(_.stop())
}

View File

@ -13,7 +13,13 @@ import sbt.ProjectExtra.extract
import sbt.internal.langserver.ErrorCodes
import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey
import sbt.internal.protocol.JsonRpcResponseError
import sbt.internal.util.{ ErrorHandling, GlobalLogBacking, Prompt, Terminal => ITerminal }
import sbt.internal.util.{
AttributeKey,
ErrorHandling,
GlobalLogBacking,
Prompt,
Terminal => ITerminal
}
import sbt.internal.{ FastTrackCommands, ShutdownHooks, SysProp, TaskProgress }
import sbt.io.{ IO, Using }
import sbt.protocol._
@ -254,16 +260,29 @@ object MainLoop {
*/
val newState =
try {
FastTrackCommands
var errorMsg: Option[String] = None
val res = FastTrackCommands
.evaluate(termState, exec.commandLine)
.getOrElse(Command.process(exec.commandLine, termState))
.getOrElse(Command.process(exec.commandLine, termState, m => errorMsg = Some(m)))
errorMsg match {
case Some(msg) =>
currentCmdProgress.foreach(
_.afterCommand(exec.commandLine, Left(new ParseException(msg, 0)))
)
case None => currentCmdProgress.foreach(_.afterCommand(exec.commandLine, Right(res)))
}
res
} catch {
case _: RejectedExecutionException =>
// No stack trace since this is just to notify the user which command they cancelled
object Cancelled extends Throwable(exec.commandLine, null, true, false) {
override def toString: String = s"Cancelled: ${exec.commandLine}"
}
throw Cancelled
val cancelled = new Cancelled(exec.commandLine)
currentCmdProgress
.foreach(_.afterCommand(exec.commandLine, Left(cancelled)))
throw cancelled
case e: Throwable =>
currentCmdProgress
.foreach(_.afterCommand(exec.commandLine, Left(e)))
throw e
} finally {
// Flush the terminal output after command evaluation to ensure that all output
// is displayed in the thin client before we report the command status. Also

View File

@ -80,7 +80,7 @@ object RemoteCache {
val app = appConfiguration.value
val base = app.baseDirectory.getCanonicalFile
// base is used only to resolve relative paths, which should never happen
IvyPaths(base.toString, localCacheDirectory.value.toString)
IvyPaths(base, localCacheDirectory.value)
},
rootOutputDirectory := {
appConfiguration.value.baseDirectory

View File

@ -70,7 +70,7 @@ object CoursierRepositoriesTasks {
val result2 =
paths.ivyHome match {
case Some(ivyHome) =>
val ivyHomeUri = ivyHome
val ivyHomeUri = ivyHome.toString
result1 map {
case r: FileRepository =>
val ivyPatterns = r.patterns.ivyPatterns map {

View File

@ -73,57 +73,6 @@ object LMCoursier {
def relaxedForAllModules: Seq[(ModuleMatchers, Reconciliation)] =
Vector((ModuleMatchers.all, Reconciliation.Relaxed))
// For binary compatibility / MiMa
def coursierConfiguration(
rs: Seq[Resolver],
interProjectDependencies: Seq[CProject],
extraProjects: Seq[CProject],
fallbackDeps: Seq[FallbackDependency],
appConfig: AppConfiguration,
classifiers: Option[Seq[Classifier]],
profiles: Set[String],
scalaOrg: String,
scalaVer: String,
scalaBinaryVer: String,
autoScalaLib: Boolean,
scalaModInfo: Option[ScalaModuleInfo],
excludeDeps: Seq[InclExclRule],
credentials: Seq[Credentials],
createLogger: Option[CacheLogger],
cacheDirectory: File,
reconciliation: Seq[(ModuleMatchers, Reconciliation)],
ivyHome: Option[String],
strict: Option[CStrict],
depsOverrides: Seq[ModuleID],
log: Logger
): CoursierConfiguration =
coursierConfiguration(
rs,
interProjectDependencies,
extraProjects,
fallbackDeps,
appConfig,
classifiers,
profiles,
scalaOrg,
scalaVer,
scalaBinaryVer,
autoScalaLib,
scalaModInfo,
excludeDeps,
credentials,
createLogger,
cacheDirectory,
reconciliation,
ivyHome,
strict,
depsOverrides,
None,
Nil,
log
)
// For binary compatibility / MiMa
def coursierConfiguration(
rs: Seq[Resolver],
interProjectDependencies: Seq[CProject],
@ -146,56 +95,6 @@ object LMCoursier {
strict: Option[CStrict],
depsOverrides: Seq[ModuleID],
updateConfig: Option[UpdateConfiguration],
log: Logger
): CoursierConfiguration =
coursierConfiguration(
rs,
interProjectDependencies,
extraProjects,
fallbackDeps,
appConfig,
classifiers,
profiles,
scalaOrg,
scalaVer,
scalaBinaryVer,
autoScalaLib,
scalaModInfo,
excludeDeps,
credentials,
createLogger,
cacheDirectory,
reconciliation,
ivyHome,
strict,
depsOverrides,
updateConfig,
Nil,
log
)
def coursierConfiguration(
rs: Seq[Resolver],
interProjectDependencies: Seq[CProject],
extraProjects: Seq[CProject],
fallbackDeps: Seq[FallbackDependency],
appConfig: AppConfiguration,
classifiers: Option[Seq[Classifier]],
profiles: Set[String],
scalaOrg: String,
scalaVer: String,
scalaBinaryVer: String,
autoScalaLib: Boolean,
scalaModInfo: Option[ScalaModuleInfo],
excludeDeps: Seq[InclExclRule],
credentials: Seq[Credentials],
createLogger: Option[CacheLogger],
cacheDirectory: File,
reconciliation: Seq[(ModuleMatchers, Reconciliation)],
ivyHome: Option[String],
strict: Option[CStrict],
depsOverrides: Seq[ModuleID],
updateConfig: Option[UpdateConfiguration],
sameVersions: Seq[Set[InclExclRule]],
log: Logger
): CoursierConfiguration = {
@ -245,7 +144,7 @@ object LMCoursier {
.withCache(cacheDirectory)
.withReconciliation(reconciliation.toVector)
.withLog(log)
.withIvyHome(ivyHome.map(new File(_)))
.withIvyHome(ivyHome)
.withStrict(strict)
.withForceVersions(userForceVersions.toVector)
.withMissingOk(missingOk)
@ -282,32 +181,10 @@ object LMCoursier {
}
def updateClassifierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task {
val sv = scalaVersion.value
coursierConfiguration(
csrRecursiveResolvers.value,
csrInterProjectDependencies.value.toVector,
csrExtraProjects.value.toVector,
csrFallbackDependencies.value,
appConfiguration.value,
Some(transitiveClassifiers.value.map(Classifier(_))),
csrMavenProfiles.value,
scalaOrganization.value,
sv,
scalaBinaryVersion.value,
autoScalaLibrary.value && !ScalaArtifacts.isScala3(sv) && !Classpaths.isScala213(sv),
scalaModuleInfo.value,
allExcludeDependencies.value,
CoursierInputsTasks.credentialsTask.value,
csrLogger.value,
csrCacheDirectory.value,
csrReconciliations.value,
ivyPaths.value.ivyHome,
CoursierInputsTasks.strictTask.value,
dependencyOverrides.value,
Some(updateConfiguration.value),
csrSameVersions.value,
streams.value.log
)
val classifiers = Some(transitiveClassifiers.value.map(Classifier(_)))
coursierConfigurationTask.value
.withClassifiers(classifiers.toVector.flatten.map(_.value))
.withHasClassifiers(classifiers.nonEmpty)
}
def updateSbtClassifierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task {

View File

@ -87,7 +87,7 @@ private[sbt] object Load {
val ivyConfiguration =
InlineIvyConfiguration()
.withPaths(
IvyPaths(baseDirectory.toString, bootIvyHome(state.configuration).map(_.toString))
IvyPaths(baseDirectory, bootIvyHome(state.configuration))
)
.withResolvers(Resolver.combineDefaultResolvers(Vector.empty))
.withLog(log)
@ -1379,19 +1379,7 @@ private[sbt] object Load {
loadPluginDefinition(
dir,
config,
PluginData(
config.globalPluginClasspath,
Nil,
None,
None,
Nil,
Nil,
Nil,
Nil,
Nil,
None,
config.converter,
)
PluginData(config.globalPluginClasspath, config.converter)
)
def buildPlugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins =
@ -1596,6 +1584,7 @@ final case class LoadBuildConfiguration(
Nil,
Nil,
Nil,
Nil,
None,
converter,
)

View File

@ -34,7 +34,7 @@ object VirtualFileValueCache {
def apply[A](converter: FileConverter)(f: VirtualFile => A): VirtualFileValueCache[A] = {
import collection.concurrent.Map
import java.util.concurrent.ConcurrentHashMap
import scala.collection.JavaConverters._
import scala.jdk.CollectionConverters._
val stampCache: Map[VirtualFileRef, (Long, XStamp)] = new ConcurrentHashMap().asScala
make(
Stamper.timeWrap(

View File

@ -10,9 +10,6 @@ package sbt.internal.server
import sbt._
import sbt.internal.bsp._
import sbt.internal.io.Retry
import sbt.internal.server.BspCompileTask.compileReport
import sbt.internal.server.BspCompileTask.exchange
import sbt.librarymanagement.Configuration
import sbt.util.InterfaceUtil
import sjsonnew.support.scalajson.unsafe.Converter
@ -20,46 +17,7 @@ import xsbti.compile.{ CompileAnalysis, Inputs }
import xsbti.{ CompileFailed, Problem, Severity }
object BspCompileTask {
private lazy val exchange = StandardMain.exchange
def start(
targetId: BuildTargetIdentifier,
project: ProjectRef,
config: Configuration
): BspCompileTask = {
val taskId = TaskId(BuildServerTasks.uniqueId, Vector())
val targetName = BuildTargetName.fromScope(project.project, config.name)
val task = BspCompileTask(targetId, targetName, taskId, System.currentTimeMillis())
task.notifyStart()
task
}
def compute(
targetId: BuildTargetIdentifier,
project: ProjectRef,
config: Configuration,
ci: Inputs
)(
compile: BspCompileTask => CompileResult
): CompileResult = {
val task = BspCompileTask(targetId, project, config, ci)
try {
task.notifyStart()
val result = Retry(compile(task))
task.notifySuccess(result)
result
} catch {
case NonFatal(cause) =>
val compileFailed = cause match {
case failed: CompileFailed => Some(failed)
case _ => None
}
task.notifyFailure(compileFailed)
throw cause
}
}
private def apply(
targetId: BuildTargetIdentifier,
project: ProjectRef,
config: Configuration,
@ -67,19 +25,9 @@ object BspCompileTask {
): BspCompileTask = {
val taskId = TaskId(BuildServerTasks.uniqueId, Vector())
val targetName = BuildTargetName.fromScope(project.project, config.name)
new BspCompileTask(targetId, targetName, taskId, inputs, System.currentTimeMillis())
}
private def compileReport(
problems: Seq[Problem],
targetId: BuildTargetIdentifier,
elapsedTimeMillis: Long,
isNoOp: Option[Boolean]
): CompileReport = {
val countBySeverity = problems.groupBy(_.severity()).mapValues(_.size)
val warnings = countBySeverity.getOrElse(Severity.Warn, 0)
val errors = countBySeverity.getOrElse(Severity.Error, 0)
CompileReport(targetId, None, errors, warnings, Some(elapsedTimeMillis.toInt), isNoOp)
val task = BspCompileTask(targetId, targetName, taskId, inputs, System.currentTimeMillis())
task.notifyStart()
task
}
}
@ -105,8 +53,8 @@ case class BspCompileTask private (
val elapsedTimeMillis = endTimeMillis - startTimeMillis
val sourceInfos = analysis.readSourceInfos().getAllSourceInfos.asScala
val problems = sourceInfos.values.flatMap(_.getReportedProblems).toSeq
val isNoOp = InterfaceUtil.toOption(inputs.previousResult.analysis).map(_ == result.analysis)
val report = compileReport(problems, targetId, elapsedTimeMillis, isNoOp)
val isNoOp = InterfaceUtil.toOption(inputs.previousResult.analysis).map(_ == analysis)
val report = compileReport(problems, elapsedTimeMillis, isNoOp)
val params = TaskFinishParams(
id,
endTimeMillis,
@ -139,7 +87,7 @@ case class BspCompileTask private (
val endTimeMillis = System.currentTimeMillis()
val elapsedTimeMillis = endTimeMillis - startTimeMillis
val problems = cause.map(_.problems().toSeq).getOrElse(Seq.empty[Problem])
val report = compileReport(problems, targetId, elapsedTimeMillis, None)
val report = compileReport(problems, elapsedTimeMillis, None)
val params = TaskFinishParams(
id,
endTimeMillis,
@ -151,10 +99,14 @@ case class BspCompileTask private (
StandardMain.exchange.notifyEvent("build/taskFinish", params)
}
private def compileReport(problems: Seq[Problem], elapsedTimeMillis: Long): CompileReport = {
val countBySeverity = problems.groupBy(_.severity).view.mapValues(_.size)
private def compileReport(
problems: Seq[Problem],
elapsedTimeMillis: Long,
isNoOp: Option[Boolean]
): CompileReport = {
val countBySeverity = problems.groupBy(_.severity()).view.mapValues(_.size).toMap
val warnings = countBySeverity.getOrElse(Severity.Warn, 0)
val errors = countBySeverity.getOrElse(Severity.Error, 0)
CompileReport(targetId, None, errors, warnings, Some(elapsedTimeMillis.toInt))
CompileReport(targetId, None, errors, warnings, Some(elapsedTimeMillis.toInt), isNoOp)
}
}

View File

@ -219,28 +219,25 @@ object BuildServerProtocol {
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetScalacOptions / aggregate := false,
bspBuildTargetJavacOptions := bspInputTask { (state, _, workspace, filter) =>
Def.task {
val items = bspBuildTargetJavacOptionsItem.result.all(filter).value
val appProvider = appConfiguration.value.provider()
val sbtJars = appProvider.mainClasspath()
val buildItems = workspace.builds.map { case (targetId, build) =>
Value(javacOptionsBuildItem(sbtJars, targetId, build))
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = JavacOptionsResult(successfulItems.toVector)
state.respondEvent(result)
bspBuildTargetJavacOptions := bspInputTask { (workspace, filter) =>
val items = bspBuildTargetJavacOptionsItem.result.all(filter).value
val appProvider = appConfiguration.value.provider()
val sbtJars = appProvider.mainClasspath()
val buildItems = workspace.builds.map { case (targetId, build) =>
Result.Value(javacOptionsBuildItem(sbtJars, targetId, build))
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = JavacOptionsResult(successfulItems.toVector)
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetJavacOptions / aggregate := false,
bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log)
Def.task {
val items = bspScalaTestClassesItem.result.all(filter).value
val successfulItems = anyOrThrow(items).flatten.toVector
val result = ScalaTestClassesResult(successfulItems.toVector, None)
state.respondEvent(result)
}
bspScalaTestClasses := bspInputTask { (workspace, filter) =>
val s = state.value
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, s.log)
val items = bspScalaTestClassesItem.result.all(filter).value
val successfulItems = anyOrThrow(items).flatten.toVector
val result = ScalaTestClassesResult(successfulItems.toVector, None)
s.respondEvent(result)
}.evaluated,
bspBuildTargetJVMRunEnvironment / aggregate := false,
bspBuildTargetJVMTestEnvironment := bspInputTask { (_, filter) =>
@ -323,21 +320,17 @@ object BuildServerProtocol {
val classpath = classpathTask.value
JavacOptionsItem(target, javacOptions, classpath, classDirectory.toURI)
},
bspBuildTargetJVMRunEnvironment := bspInputTask { (state, _, _, filter) =>
Def.task {
val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = JvmRunEnvironmentResult(successfulItems.toVector, None)
state.respondEvent(result)
}
bspBuildTargetJVMRunEnvironment := bspInputTask { (_, filter) =>
val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = JvmRunEnvironmentResult(successfulItems.toVector, None)
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetJVMTestEnvironment := bspInputTask { (state, _, _, filter) =>
Def.task {
val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = JvmTestEnvironmentResult(successfulItems.toVector, None)
state.respondEvent(result)
}
bspBuildTargetJVMTestEnvironment := bspInputTask { (_, filter) =>
val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = JvmTestEnvironmentResult(successfulItems.toVector, None)
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value,
bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value,
@ -743,39 +736,37 @@ object BuildServerProtocol {
): ScalacOptionsItem = {
val plugins: LoadedPlugins = build.unit.plugins
val scalacOptions = plugins.pluginData.scalacOptions.toVector
val pluginClassPath = plugins.classpath
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
val classDirectory = plugins.pluginData.classDirectory.map(_.toURI)
val converter = plugins.pluginData.converter
val classpath =
plugins.classpath.map(f => converter.toPath(f).toFile.toURI).toVector ++
sbtJars.map(_.toURI).toVector
val classDirectory = new File(build.localBase, "project/target").toURI
val item = ScalacOptionsItem(targetId, scalacOptions, classpath, classDirectory)
item
}
private def javacOptionsBuildItem(
sbtJars: Seq[File],
sbtJars: Array[File],
targetId: BuildTargetIdentifier,
build: LoadedBuildUnit
): JavacOptionsItem = {
val plugins: LoadedPlugins = build.unit.plugins
val javacOptions = plugins.pluginData.javacOptions.toVector
val pluginClassPath = plugins.classpath
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
val classDirectory = plugins.pluginData.classDirectory.map(_.toURI)
val converter = plugins.pluginData.converter
val classpath =
plugins.classpath.map(f => converter.toPath(f).toFile.toURI).toVector ++
sbtJars.map(_.toURI).toVector
val classDirectory = new File(build.localBase, "project/target").toURI
val item = JavacOptionsItem(targetId, javacOptions, classpath, classDirectory)
item
}
private def bspInputTask[T](
taskImpl: (
State,
Seq[BuildTargetIdentifier],
BspFullWorkspace,
ScopeFilter
) => Def.Initialize[Task[T]]
private inline def bspInputTask[T](
inline taskImpl: (BspFullWorkspace, ScopeFilter) => T
): Def.Initialize[InputTask[T]] =
Def
.input(_ => targetIdentifierParser)
.flatMapTask { targets =>
val s = state.value
val workspace: BspFullWorkspace = bspFullWorkspace.value.filter(targets)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
Def.task(taskImpl(workspace, filter))
@ -847,16 +838,16 @@ object BuildServerProtocol {
}
private lazy val classpathTask: Def.Initialize[Task[Vector[URI]]] = Def.taskDyn {
val converter = fileConverter.value
val externalDependencyClasspath = Keys.externalDependencyClasspath.value
.map(f => converter.toPath(f.data).toFile.toURI)
val internalDependencyClasspath = for {
(ref, configs) <- bspInternalDependencyConfigurations.value
config <- configs
} yield ref / config / Keys.classDirectory
Def.task {
val classpath = internalDependencyClasspath.join.value.distinct ++
externalDependencyClasspath.map(_.data)
classpath.map(_.toURI).toVector
internalDependencyClasspath.join.value.distinct.map(_.toURI).toVector ++
externalDependencyClasspath
}
}

View File

@ -127,8 +127,7 @@ final class BuildServerReporterImpl(
if (oldDocuments.nonEmpty || problems.nonEmpty || isFirstReport) {
val diagsByDocuments = problems
.flatMap(mapProblemToDiagnostic)
.groupBy { case (document, _) => document }
.mapValues(_.map { case (_, diag) => diag })
.groupMap((document, _) => document)((_, diag) => diag)
updateNewDocuments(source, diagsByDocuments.keys.toVector)
// send a report for the new documents, the old ones and the source file

View File

@ -44,29 +44,24 @@ private[sbt] class BatchScriptRunner extends ScriptRunner with AutoCloseable {
def processStatement(handler: StatementHandler, statement: Statement, states: States): Unit = {
val state = states(handler).asInstanceOf[handler.State]
val nextStateFuture = service.submit(() =>
val nextState =
try Right(handler(statement.command, statement.arguments, state))
catch { case e: Exception => Left(e) }
)
try {
nextStateFuture.get(timeout.toMillis, TimeUnit.MILLISECONDS) match {
case Left(err) =>
if (statement.successExpected) {
err match {
case t: TestFailed =>
throw new TestException(statement, "Command failed: " + t.getMessage, null)
case _ => throw new TestException(statement, "Command failed", err)
}
} else
()
case Right(s) =>
if (statement.successExpected)
states(handler) = s
else
throw new TestException(statement, "Command succeeded but failure was expected", null)
}
} catch {
case e: TimeoutException => throw new TestException(statement, "Command timed out", e)
nextState match {
case Left(err) =>
if (statement.successExpected) {
err match {
case t: TestFailed =>
throw new TestException(statement, "Command failed: " + t.getMessage, null)
case _ => throw new TestException(statement, "Command failed", err)
}
} else
()
case Right(s) =>
if (statement.successExpected)
states(handler) = s
else
throw new TestException(statement, "Command succeeded but failure was expected", null)
}
}

View File

@ -18,6 +18,7 @@ import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
import java.io.File
import java.net.URI
import java.nio.file.Files
import java.util.concurrent.atomic.AtomicInteger
import scala.concurrent.duration.*
// starts svr using server-test/buildserver and perform custom server tests
@ -26,6 +27,8 @@ class BuildServerTest extends AbstractServerTest {
import sbt.internal.bsp.codec.JsonProtocol._
override val testDirectory: String = "buildserver"
private val idGen: AtomicInteger = new AtomicInteger(0)
private def nextId(): Int = idGen.getAndIncrement()
test("build/initialize") {
initializeRequest()
@ -40,7 +43,7 @@ class BuildServerTest extends AbstractServerTest {
svr.sendJsonRpc(
"""{ "jsonrpc": "2.0", "id": "16", "method": "workspace/buildTargets", "params": {} }"""
)
assert(processing("workspace/buildTargets"))
assertProcessing("workspace/buildTargets")
val result = svr.waitFor[WorkspaceBuildTargetsResult](10.seconds)
val utilTarget = result.targets.find(_.displayName.contains("util")).get
assert(utilTarget.id.uri.toString.endsWith("#util/Compile"))
@ -97,7 +100,7 @@ class BuildServerTest extends AbstractServerTest {
test("buildTarget/compile - reports compilation progress") {
val buildTarget = buildTargetUri("runAndTest", "Compile")
compile(buildTarget, id = 33)
compile(buildTarget)
// This doesn't always come back in 10s on CI.
assert(svr.waitForString(20.seconds) { s =>
s.contains("build/taskStart") &&
@ -220,7 +223,7 @@ class BuildServerTest extends AbstractServerTest {
)
}
test("buildTarget/compile: Java diagnostics") { _ =>
test("buildTarget/compile: Java diagnostics") {
val buildTarget = buildTargetUri("javaProj", "Compile")
compile(buildTarget)
@ -242,7 +245,7 @@ class BuildServerTest extends AbstractServerTest {
)
}
test("buildTarget/scalacOptions, buildTarget/javacOptions") { _ =>
test("buildTarget/scalacOptions, buildTarget/javacOptions") {
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
@ -292,7 +295,7 @@ class BuildServerTest extends AbstractServerTest {
assert(res.cleaned)
}
test("workspace/reload") { _ =>
test("workspace/reload") {
val id = nextId()
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "$id", "method": "workspace/reload"}"""
@ -315,7 +318,7 @@ class BuildServerTest extends AbstractServerTest {
// reload
assertMessage(
s""""buildTarget":{"uri":"$metaBuildTarget"}""",
s""""textDocument":{"uri":"${otherBuildFile.toPath.toUri}"}""",
s""""textDocument":{"uri":"${otherBuildFile.toUri}"}""",
""""severity":1""",
""""reset":true"""
)()
@ -338,11 +341,11 @@ class BuildServerTest extends AbstractServerTest {
// assert received an empty diagnostic
assertMessage(
s""""buildTarget":{"uri":"$metaBuildTarget"}""",
s""""textDocument":{"uri":"${otherBuildFile.toPath.toUri}"}""",
s""""textDocument":{"uri":"${otherBuildFile.toUri}"}""",
""""diagnostics":[]""",
""""reset":true"""
)()
IO.delete(otherBuildFile)
Files.delete(otherBuildFile)
}
test("buildTarget/scalaMainClasses") {
@ -534,7 +537,7 @@ class BuildServerTest extends AbstractServerTest {
assert(actualResult == expectedResult)
}
test("buildTarget/compile: twirl diagnostics (sourcePositionMappers)") { _ =>
test("buildTarget/compile: twirl diagnostics (sourcePositionMappers)") {
val buildTarget = buildTargetUri("twirlProj", "Compile")
val testFile = new File(svr.baseDirectory, s"twirlProj/src/main/twirl/main.scala.html")
@ -598,7 +601,7 @@ class BuildServerTest extends AbstractServerTest {
if (debug) println(msg)
parts.forall(msg.contains)
}
if (message.nonEmpty) assert.apply(assertion, message) else assert(assertion)
if (message.nonEmpty) assert(assertion, message) else assert(assertion)
}
private def reloadWorkspace(): Int =

View File

@ -89,7 +89,7 @@ abstract class IvyBridgeProviderSpecification
val resolvers = resolvers0.toVector
val chainResolver = ChainedResolver("zinc-chain", resolvers)
InlineIvyConfiguration()
.withPaths(IvyPaths(baseDirectory.toString, Some(ivyHome.toString)))
.withPaths(IvyPaths(baseDirectory, Some(ivyHome)))
.withResolvers(resolvers)
.withModuleConfigurations(Vector(ModuleConfiguration("*", chainResolver)))
.withLock(None)