diff --git a/build.sbt b/build.sbt index 878e36390..404b0de63 100644 --- a/build.sbt +++ b/build.sbt @@ -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 += diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 81ef41c6b..63e6ef590 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -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: diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 8889de8d3..3ec96e89c 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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) diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index 0caf66bf3..3e1dabea6 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -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)) }) } } diff --git a/main/src/main/scala/sbt/ExecuteProgress2.scala b/main/src/main/scala/sbt/ExecuteProgress2.scala index d99d55258..fff7c95e5 100644 --- a/main/src/main/scala/sbt/ExecuteProgress2.scala +++ b/main/src/main/scala/sbt/ExecuteProgress2.scala @@ -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()) } diff --git a/main/src/main/scala/sbt/MainLoop.scala b/main/src/main/scala/sbt/MainLoop.scala index dd6debb3f..fac42e605 100644 --- a/main/src/main/scala/sbt/MainLoop.scala +++ b/main/src/main/scala/sbt/MainLoop.scala @@ -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 diff --git a/main/src/main/scala/sbt/RemoteCache.scala b/main/src/main/scala/sbt/RemoteCache.scala index 14bc67ccd..faf2e88c1 100644 --- a/main/src/main/scala/sbt/RemoteCache.scala +++ b/main/src/main/scala/sbt/RemoteCache.scala @@ -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 diff --git a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala index eecabcdc1..2d05d53c9 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala @@ -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 { diff --git a/main/src/main/scala/sbt/coursierint/LMCoursier.scala b/main/src/main/scala/sbt/coursierint/LMCoursier.scala index a20ac4d22..c940f3c7f 100644 --- a/main/src/main/scala/sbt/coursierint/LMCoursier.scala +++ b/main/src/main/scala/sbt/coursierint/LMCoursier.scala @@ -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 { diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index 8e6519c0a..54884a295 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -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, ) diff --git a/main/src/main/scala/sbt/internal/VirtualFileValueCache.scala b/main/src/main/scala/sbt/internal/VirtualFileValueCache.scala index ed47a10eb..fd3121c13 100644 --- a/main/src/main/scala/sbt/internal/VirtualFileValueCache.scala +++ b/main/src/main/scala/sbt/internal/VirtualFileValueCache.scala @@ -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( diff --git a/main/src/main/scala/sbt/internal/server/BspCompileTask.scala b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala index bdccf776d..d90f02fe5 100644 --- a/main/src/main/scala/sbt/internal/server/BspCompileTask.scala +++ b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala @@ -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) } } diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index dcc9b6425..0298bab85 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -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 } } diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index ead571b4f..3b796a408 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -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 diff --git a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/BatchScriptRunner.scala b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/BatchScriptRunner.scala index 2e6ed3e55..7f3966647 100644 --- a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/BatchScriptRunner.scala +++ b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/BatchScriptRunner.scala @@ -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) } } diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 6b33bac52..3247f1994 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -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 = diff --git a/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala b/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala index e2255cee2..d4245b7c4 100644 --- a/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala +++ b/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala @@ -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)