Merge branch 'develop' into fix/1469-junit-xml-fork-stacktrace

This commit is contained in:
volcano303 2026-04-15 21:49:38 +02:00
commit 4436f061e4
98 changed files with 865 additions and 250 deletions

2
.gitattributes vendored
View File

@ -6,3 +6,5 @@ launcher-package/src/windows/sbt text eol=lf
**/contraband-scala/**/* -diff merge=ours
**/contraband-scala/**/* linguist-generated=true
**/contraband-scala/**/* diff
*.contra linguist-language=graphql

View File

@ -84,19 +84,21 @@ def commonSettings: Seq[Setting[?]] = Def.settings(
Test / testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"),
Test / testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2"),
compile / javacOptions ++= Seq("-Xlint", "-Xlint:-serial"),
/*
Compile / doc / scalacOptions ++= {
import scala.sys.process._
val devnull = ProcessLogger(_ => ())
val tagOrSha = ("git describe --exact-match" #|| "git rev-parse HEAD").lineStream(devnull).head
Seq(
"-sourcepath",
(LocalRootProject / baseDirectory).value.getAbsolutePath,
"-doc-source-url",
s"https://github.com/sbt/sbt/tree/$tagOrSha€{FILE_PATH}.scala"
)
if (Dependencies.sbtIoPath.isEmpty && Dependencies.sbtZincPath.isEmpty) {
import scala.sys.process.*
val devnull = ProcessLogger(_ => ())
val tagOrSha =
("git describe --exact-match" #|| "git rev-parse HEAD").lineStream(devnull).head
Seq(
"-source-links:github://sbt/sbt",
"-revision",
tagOrSha
)
} else {
Nil
}
},
*/
Compile / javafmtOnCompile := scalafmtOnCompile.value,
Test / javafmtOnCompile := (Test / scalafmtOnCompile).value,
Compile / unmanagedSources / inputFileStamps :=
@ -186,7 +188,6 @@ lazy val sbtRoot: Project = (project in file("."))
},
Utils.baseScalacOptions,
Docs.settings,
scalacOptions += "-Ymacro-expand:none", // for both sxr and doc
Utils.publishPomSettings,
otherRootSettings,
Utils.noPublish,
@ -742,8 +743,10 @@ lazy val mainProj = (project in file("main"))
Test / testOptions += Tests
.Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000"),
SettingKey[Boolean]("usePipelining") := false,
// TODO: Fix doc
Compile / doc / sources := Nil,
libraryDependencies += {
// https://github.com/scala/scala3/issues/18487
"net.hamnaberg" %% "dataclass-annotation" % dataclassScalafixVersion % Provided
},
mimaSettings,
mimaBinaryIssueFilters ++= Vector(
// Moved to sbt-ivy module (Step 5 of sbt#7640)
@ -782,8 +785,10 @@ lazy val sbtIvyProj = (project in file("sbt-ivy"))
name := "sbt-ivy",
sbtPlugin := true,
pluginCrossBuild / sbtVersion := version.value,
// TODO: Fix doc
Compile / doc / sources := Nil,
libraryDependencies += {
// https://github.com/scala/scala3/issues/18487
"net.hamnaberg" %% "dataclass-annotation" % dataclassScalafixVersion % Provided
},
mimaPreviousArtifacts := Set.empty, // new module, no previous artifacts
)
.configure(addSbtIO)
@ -1019,10 +1024,6 @@ lazy val sbtwProj = (project in file("sbtw"))
description := "Windows drop-in launcher for sbt (replaces sbt.bat)",
scalaVersion := "3.8.3",
crossPaths := false,
Compile / scalafix / unmanagedSources := {
// https://github.com/scalameta/scalameta/issues/4531
(Compile / unmanagedSources).value.filterNot(_.getName == "Main.scala")
},
Compile / mainClass := Some("sbtw.Main"),
libraryDependencies += "com.github.scopt" %% "scopt" % "4.1.0",
libraryDependencies += scalaVerify % Test,

View File

@ -200,6 +200,8 @@ object Tests {
new Group(name, tests, runPolicy, tags)
}
override def hashCode(): Int = (name, tests, runPolicy, tags).##
override def equals(x$1: Any): Boolean = {
this.eq(x$1.asInstanceOf[Object]) || (x$1.isInstanceOf[Group] && ({
val Group$1: Group = x$1.asInstanceOf[Group]

View File

@ -149,7 +149,9 @@ $HelpCommand <regular expression>
remaining commands with the exception that the JVM is not shut down.
If 'dev' is specified, the current sbt artifacts from the boot directory
(`~/.sbt/boot` by default) are deleted before restarting.
(under the default global base; `sbt.global.base` selects that location) are deleted
before restarting, and the compiler bridge secondary cache at `zinc/org.scala-sbt`
(honoring `sbt.global.base` and `sbt.global.zinc`) is removed.
This forces an update of sbt and Scala, which is useful when working with development
versions of sbt.
If 'full' is specified, the boot directory is wiped out before restarting.

View File

@ -181,6 +181,7 @@ class NetworkClient(
def success(message: => String): Unit = ()
def log(level: Level.Value, message: => String): Unit = console.appendLog(level, message)
}
private val interactive = arguments.commandArguments.isEmpty
private[sbt] def connectOrStartServerAndConnect(
promptCompleteUsers: Boolean,
@ -712,8 +713,19 @@ class NetworkClient(
case (`clientJob`, Some(json)) =>
import sbt.internal.worker.codec.JsonProtocol.given
Converter.fromJson[ClientJobParams](json) match {
case Success(params) => clientSideRun(params).get; Vector.empty
case Failure(_) => Vector.empty
case Success(params) =>
clientSideRun(params) match
case Success(_) =>
if interactive then console.success("ok")
else ()
Vector.empty
case Failure(e) =>
if interactive then
Vector(
(Level.Error, e.getMessage)
)
else throw e
case Failure(_) => Vector.empty
}
case (`Shutdown`, Some(_)) => Vector.empty
case (msg, _) if msg.startsWith("build/") => Vector.empty
@ -921,9 +933,8 @@ class NetworkClient(
withSignalHandler(contHandler, Signals.CONT) {
interactiveThread.set(Thread.currentThread)
val cleaned = arguments.commandArguments
val userCommands = cleaned.takeWhile(_ != TerminateAction)
val interactive = cleaned.isEmpty
val exit = cleaned.nonEmpty && userCommands.isEmpty
val userCommands = arguments.commandArguments.takeWhile(_ != TerminateAction)
val exit = arguments.commandArguments.nonEmpty && userCommands.isEmpty
attachUUID.set(sendJson(attach, s"""{"interactive": $interactive}"""))
val handler: () => Unit = () => {
def exitAbruptly() = {

View File

@ -30,7 +30,10 @@ object ServerHandler {
lazy val fallback: ServerHandler = ServerHandler({ handler =>
ServerIntent(
onRequest = { case x => handler.log.debug(s"Unhandled request received: ${x.method}: $x") },
onRequest = { case x =>
handler.log.debug(s"Unhandled request received: ${x.method}: $x")
handler.jsonRpcRespondError(Some(x.id), -32601, s"Unknown method: ${x.method}")
},
onResponse = { case x => handler.log.debug(s"Unhandled response received") },
onNotification = { case x =>
handler.log.debug(s"Unhandled notification received: ${x.method}: $x")

View File

@ -41,7 +41,7 @@ object Cross {
private def switchParser(state: State): Parser[Switch] = {
import DefaultParsers.*
def versionAndCommand(spacePresent: Boolean) = {
def versionAndCommand(commandName: String)(spacePresent: Boolean) = {
val x = Project.extract(state)
import x.*
val knownVersions = crossVersions(x, currentRef)
@ -56,7 +56,7 @@ object Cross {
ScalaHomeVersion(new File(home), Some(v).filterNot(_.isEmpty), force)
}
}
val spacedVersion = if (spacePresent) version else version & spacedFirst(SwitchCommand)
val spacedVersion = if (spacePresent) version else version & spacedFirst(commandName)
val verboseOpt = Parser.opt(token(Space ~> "-v"))
// Accept valid commands, or project/command patterns that may reference projects
// not yet available after version switch (fixes #7574)
@ -74,19 +74,24 @@ object Cross {
switch1 | switch2
}
token(SwitchCommand ~> OptSpace) flatMap { sp =>
versionAndCommand(sp.nonEmpty)
}
def parse(commandName: String) =
token(commandName ~> OptSpace) flatMap { sp =>
versionAndCommand(commandName)(sp.nonEmpty)
}
parse(SwitchCommand) | parse(SwitchAlias)
}
private case class CrossArgs(command: String, verbose: Boolean)
private def crossParser(state: State): Parser[CrossArgs] =
token(CrossCommand <~ OptSpace) flatMap { _ =>
(token(Parser.opt("-v" <~ Space)) ~ token(matched(state.combinedParser))).map {
(verbose, command) => CrossArgs(command, verbose.isDefined)
private def crossParser(state: State): Parser[CrossArgs] = {
def parse(commandName: String) =
token(commandName <~ OptSpace) flatMap { _ =>
(token(Parser.opt("-v" <~ Space)) ~ token(matched(state.combinedParser))).map {
(verbose, command) => CrossArgs(command, verbose.isDefined)
}
}
}
parse(CrossCommand) | parse(CrossAlias)
}
private def crossRestoreSessionParser: Parser[String] = token(CrossRestoreSessionCommand)

View File

@ -4289,7 +4289,9 @@ object Classpaths {
configuration.allRepositories,
)
val processed = configuration.process(pomXml)
scala.xml.XML.save(file.getAbsolutePath, processed, "UTF-8", xmlDecl = true)
val printer = new scala.xml.PrettyPrinter(1000, 4)
val formatted = scala.xml.XML.loadString(printer.format(processed))
scala.xml.XML.save(file.getAbsolutePath, formatted, "UTF-8", xmlDecl = true)
log.info("Wrote " + file.getAbsolutePath)
file
})

View File

@ -479,6 +479,8 @@ object Keys {
val bspBuildTargetResourcesItem = taskKey[ResourcesItem]("").withRank(DTask)
val bspBuildTargetDependencySources = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetDependencySourcesItem = taskKey[DependencySourcesItem]("").withRank(DTask)
val bspBuildTargetDependencyModules = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetDependencyModulesItem = taskKey[DependencyModulesItem]("").withRank(DTask)
val bspBuildTargetOutputPaths = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetOutputPathsItem = taskKey[OutputPathsItem]("").withRank(DTask)
val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask)

View File

@ -1144,12 +1144,20 @@ object BuiltinCommands {
.getOpt(Keys.minForcegcInterval)
.getOrElse(GCUtil.defaultMinForcegcInterval)
val exec: Exec = getExec(s1, minGCInterval)
val isInteractive = exec.source match {
case Some(src) if src.channelName.startsWith("network") =>
exchange.channelForName(src.channelName) match {
case Some(nc: NetworkChannel) => nc.isInteractive
case _ => true
}
case _ => true
}
val newState = s1
.copy(
onFailure = Some(Exec(Shell, None)),
remainingCommands = exec +: Exec(Shell, None) +: s1.remainingCommands
)
.setInteractive(true)
.setInteractive(isInteractive)
val res =
if (exec.commandLine.trim.isEmpty) newState
else newState.clearGlobalLog

View File

@ -22,6 +22,8 @@ import sbt.internal.util.{
Terminal as ITerminal
}
import sbt.io.{ IO, Using }
import sbt.io.syntax.*
import sbt.librarymanagement.SbtArtifacts
import sbt.protocol.*
import sbt.util.{ Logger, LoggerContext }
@ -75,6 +77,10 @@ private[sbt] object MainLoop:
case e: RebootCurrent =>
deleteLastLog(logBacking)
deleteCurrentArtifacts(state)
deleteZincBridgeSecondaryCache(
state.log,
BuildPaths.getZincDirectory(state, BuildPaths.getGlobalBase(state)),
)
throw new xsbti.FullReload(e.arguments.toArray, false)
case NonFatal(e) =>
System.err.println(
@ -89,7 +95,6 @@ private[sbt] object MainLoop:
/** Deletes the current sbt artifacts from boot. */
private[sbt] def deleteCurrentArtifacts(state: State): Unit = {
import sbt.io.syntax.*
val provider = state.configuration.provider
val appId = provider.id
// If we can obtain boot directory more accurately it'd be better.
@ -109,6 +114,13 @@ private[sbt] object MainLoop:
}
}
/** Removes the Zinc compiler bridge secondary cache (`zincDir/org.scala-sbt`). */
private[sbt] def deleteZincBridgeSecondaryCache(log: Logger, zincDir: File): Unit =
val bridgeCache = zincDir / SbtArtifacts.Organization
if bridgeCache.exists() then
log.info(s"deleting $bridgeCache")
IO.delete(bridgeCache)
/** Runs the next sequence of commands with global logging in place. */
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
Using.fileWriter(append = true)(logBacking.file) { writer =>

View File

@ -17,6 +17,7 @@ import sbt.internal.util.complete.Parser
import sbt.internal.util.complete.Parser.{ failure, seq, success }
import sbt.internal.util.*
import sbt.internal.client.NetworkClient
import sbt.internal.worker.ClientJobParams
import sbt.std.Transform.DummyTaskMap
import sbt.util.{ Logger, Show }
import scala.annotation.tailrec
@ -87,16 +88,18 @@ object Aggregation {
import complete.*
val log = state.log
val extracted = Project.extract(state)
val success = results match
case Result.Value(_) => true
case Result.Inc(_) => false
// omit success printing for client-side run
val (success, jobParams) = results match
case Result.Value(Seq(KeyValue(_, p: ClientJobParams))) => (true, true)
case Result.Value(_) => (true, false)
case Result.Inc(_) => (false, false)
val isPaused = currentChannel(state) match
case Some(channel) => channel.isPaused
case None => false
results.toEither.foreach { r =>
if show.taskValues then printSettings(r, show.print) else ()
}
if !isPaused && show.success && !state.get(suppressShow).getOrElse(false) then
if !isPaused && show.success && !state.get(suppressShow).getOrElse(false) && !jobParams then
printSuccess(start, stop, extracted, success, cacheSummary, log)
else ()

View File

@ -226,6 +226,13 @@ private[sbt] object Clean {
case d: DiskActionCacheStore => d.clear()
case _ => ()
IO.delete(outputDirectory.toFile())
IO.delete(
s.configuration
.provider()
.scalaProvider()
.launcher()
.bootDirectory()
)
s
Command.command(CleanFull, h)(expunge andThen clearCachesFun)
}

View File

@ -331,15 +331,19 @@ defaults
Nil
val CrossCommand = "+"
val CrossAlias = "cross"
val CrossRestoreSessionCommand = "+-"
val SwitchCommand = "++"
val SwitchAlias = "switch"
def crossHelp: Help = Help.more(CrossCommand, CrossDetailed)
def crossHelp: Help =
Help.more(CrossCommand, CrossDetailed) ++ Help.more(CrossAlias, CrossDetailed)
def crossRestoreSessionHelp = Help.more(CrossRestoreSessionCommand, CrossRestoreSessionDetailed)
def switchHelp: Help = Help.more(SwitchCommand, SwitchDetailed)
def switchHelp: Help =
Help.more(SwitchCommand, SwitchDetailed) ++ Help.more(SwitchAlias, SwitchDetailed)
def CrossDetailed =
s"""$CrossCommand [-v] <command>
s"""$CrossCommand (or $CrossAlias) [-v] <command>
Runs <command> for each Scala version specified for cross-building.
For each string in `crossScalaVersions` in each project project, this command sets
@ -359,7 +363,7 @@ defaults
"""
def SwitchDetailed =
s"""$SwitchCommand <scala-version>[!] [-v] [<command>]
s"""$SwitchCommand (or $SwitchAlias) <scala-version>[!] [-v] [<command>]
Changes the Scala version and runs a command.
<scala-version> may be an actual Scala version such as 3.1.3, or a Semantic Version selector

View File

@ -23,7 +23,7 @@ object LintUnused {
keyName => includes(keyName)
},
lintExcludeFilter := {
val excludedPrefixes = List("release", "sonatype", "watch", "whitesource")
val excludedPrefixes = List("release", "sonatype", "watch")
val excludes = excludeLintKeys.value.map(_.scopedKey.key.label)
keyName => excludes(keyName) || excludedPrefixes.exists(keyName.startsWith(_))
},

View File

@ -46,6 +46,8 @@ private[sbt] object PomGenerator:
<modelVersion>4.0.0</modelVersion>
{makeModuleID(crossMid)}
{info.map(i => <name>{i.nameFormal}</name>).getOrElse(NodeSeq.Empty)}
{info.map(makeDescription).getOrElse(NodeSeq.Empty)}
{info.map(makeHomePage).getOrElse(NodeSeq.Empty)}
{info.map(makeStartYear).getOrElse(NodeSeq.Empty)}
{info.map(makeOrganization).getOrElse(NodeSeq.Empty)}
{info.map(makeScmInfo).getOrElse(NodeSeq.Empty)}
@ -96,6 +98,16 @@ private[sbt] object PomGenerator:
private val IgnoreTypes: Set[String] =
Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
private def makeDescription(info: ModuleInfo): NodeSeq =
if info.description != null && info.description.nonEmpty then
<description>{info.description}</description>
else NodeSeq.Empty
private def makeHomePage(info: ModuleInfo): NodeSeq =
info.homepage match
case Some(h) => <url>{h}</url>
case _ => NodeSeq.Empty
private def makeStartYear(info: ModuleInfo): NodeSeq =
info.startYear match
case Some(y) => <inceptionYear>{y}</inceptionYear>

View File

@ -166,6 +166,21 @@ object BuildServerProtocol {
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetDependencySources / aggregate := false,
bspBuildTargetDependencyModules := bspInputTask { (workspace, filter) =>
val items = bspBuildTargetDependencyModulesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val buildItems = workspace.builds
.map { case (targetId, loadedBuildUnit) =>
val projRef = ProjectRef(loadedBuildUnit.unit.uri, loadedBuildUnit.root)
(projRef / updateSbtClassifiers).map(getDependencyModulesItem(targetId, _))
}
.toSeq
.join
.value
val result = DependencyModulesResult((successfulItems ++ buildItems).toVector)
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetDependencyModules / aggregate := false,
bspBuildTargetCompile := bspInputTask { (workspace, filter) =>
val s = state.value
workspace.warnIfBuildsNonEmpty(Method.Compile, s.log)
@ -306,6 +321,7 @@ object BuildServerProtocol {
ResourcesItem(id, uris)
},
bspBuildTargetDependencySourcesItem := dependencySourcesItemTask.value,
bspBuildTargetDependencyModulesItem := dependencyModulesItemTask.value,
bspBuildTargetOutputPathsItem := {
val id = bspTargetIdentifier.value
OutputPathsItem(id, Vector(OutputPathItem(target.value.toURI, OutputPathItemKind.Directory)))
@ -374,6 +390,7 @@ object BuildServerProtocol {
final val Resources = "buildTarget/resources"
final val OutputPaths = "buildTarget/outputPaths"
final val DependencySources = "buildTarget/dependencySources"
final val DependencyModules = "buildTarget/dependencyModules"
final val Compile = "buildTarget/compile"
final val Test = "buildTarget/test"
final val Run = "buildTarget/run"
@ -439,6 +456,12 @@ object BuildServerProtocol {
val command = Keys.bspBuildTargetDependencySources.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.DependencyModules =>
val param = Converter.fromJson[DependencyModulesParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
val command = Keys.bspBuildTargetDependencyModules.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.Compile =>
val param = Converter.fromJson[CompileParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
@ -856,6 +879,13 @@ object BuildServerProtocol {
)
}
private def dependencyModulesItemTask: Def.Initialize[Task[DependencyModulesItem]] = Def.task {
getDependencyModulesItem(
Keys.bspTargetIdentifier.value,
Keys.updateClassifiers.value
)
}
private def getDependencySourceItem(
targetId: BuildTargetIdentifier,
updateReport: UpdateReport
@ -869,6 +899,25 @@ object BuildServerProtocol {
DependencySourcesItem(targetId, sources.toVector.distinct)
}
private def getDependencyModulesItem(
targetId: BuildTargetIdentifier,
updateReport: UpdateReport
): DependencyModulesItem = {
val modules = for {
configuration <- updateReport.configurations.view
module <- configuration.modules.view
} yield {
val moduleId = module.module
DependencyModule(
name = s"${moduleId.organization}:${moduleId.name}",
version = moduleId.revision,
dataKind = None,
data = None,
)
}
DependencyModulesItem(targetId, modules.toVector.distinct)
}
private def bspCompileState: Initialize[BuildServerProtocol.BspCompileState] = Def.setting {
new BuildServerProtocol.BspCompileState()
}

View File

@ -0,0 +1,49 @@
/*
* sbt
* Copyright 2023, Scala center
* Copyright 2011 - 2022, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
import java.io.File
import sbt.internal.util.{ ConsoleOut, GlobalLogging, MainAppender }
import sbt.io.IO
import sbt.io.syntax.*
import sbt.librarymanagement.SbtArtifacts
import sbt.util.Logger
object MainLoopZincCacheTest extends verify.BasicTestSuite:
private def withTestLog[A](f: Logger => A): A =
val logFile = File.createTempFile("sbt-mlz", ".log")
try
val gl = GlobalLogging.initial(
MainAppender.globalDefault(ConsoleOut.globalProxy),
logFile,
ConsoleOut.globalProxy
)
f(gl.full)
finally IO.delete(logFile)
test("deleteZincBridgeSecondaryCache removes org.scala-sbt under zincDir"):
IO.withTemporaryDirectory: tmp =>
val zincRoot = tmp / "zinc"
val bridge = zincRoot / SbtArtifacts.Organization
IO.write(bridge / "marker.txt", "cached")
withTestLog: log =>
MainLoop.deleteZincBridgeSecondaryCache(log, zincRoot)
assert(!bridge.exists(), s"expected $bridge deleted")
test("deleteZincBridgeSecondaryCache is a no-op when org.scala-sbt is absent"):
IO.withTemporaryDirectory: tmp =>
val zincRoot = tmp / "zinc"
IO.createDirectory(zincRoot)
withTestLog: log =>
MainLoop.deleteZincBridgeSecondaryCache(log, zincRoot)
assert(zincRoot.exists())
end MainLoopZincCacheTest

View File

@ -36,8 +36,6 @@ object Dependencies {
}
lazy val sbtIoPath = getSbtModulePath("sbtio.path")
lazy val sbtUtilPath = getSbtModulePath("sbtutil.path")
lazy val sbtLmPath = getSbtModulePath("sbtlm.path")
lazy val sbtZincPath = getSbtModulePath("sbtzinc.path")
def addSbtModule(

View File

@ -0,0 +1,57 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param name Module name
* @param version Module version
* @param dataKind Kind of data to expect in the `data` field.
* @param data Language-specific metadata about this module.
*/
final class DependencyModule private (
val name: String,
val version: String,
val dataKind: Option[String],
val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModule => (this.name == x.name) && (this.version == x.version) && (this.dataKind == x.dataKind) && (this.data == x.data)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModule".##) + name.##) + version.##) + dataKind.##) + data.##)
}
override def toString: String = {
"DependencyModule(" + name + ", " + version + ", " + dataKind + ", " + data + ")"
}
private def copy(name: String = name, version: String = version, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): DependencyModule = {
new DependencyModule(name, version, dataKind, data)
}
def withName(name: String): DependencyModule = {
copy(name = name)
}
def withVersion(version: String): DependencyModule = {
copy(version = version)
}
def withDataKind(dataKind: Option[String]): DependencyModule = {
copy(dataKind = dataKind)
}
def withDataKind(dataKind: String): DependencyModule = {
copy(dataKind = Option(dataKind))
}
def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = {
copy(data = data)
}
def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = {
copy(data = Option(data))
}
}
object DependencyModule {
def apply(name: String, version: String, dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = new DependencyModule(name, version, dataKind, data)
def apply(name: String, version: String, dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = new DependencyModule(name, version, Option(dataKind), Option(data))
}

View File

@ -0,0 +1,40 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
final class DependencyModulesItem private (
val target: Option[sbt.internal.bsp.BuildTargetIdentifier],
val modules: Vector[sbt.internal.bsp.DependencyModule]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModulesItem => (this.target == x.target) && (this.modules == x.modules)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesItem".##) + target.##) + modules.##)
}
override def toString: String = {
"DependencyModulesItem(" + target + ", " + modules + ")"
}
private def copy(target: Option[sbt.internal.bsp.BuildTargetIdentifier] = target, modules: Vector[sbt.internal.bsp.DependencyModule] = modules): DependencyModulesItem = {
new DependencyModulesItem(target, modules)
}
def withTarget(target: Option[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesItem = {
copy(target = target)
}
def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): DependencyModulesItem = {
copy(target = Option(target))
}
def withModules(modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = {
copy(modules = modules)
}
}
object DependencyModulesItem {
def apply(target: Option[sbt.internal.bsp.BuildTargetIdentifier], modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(target, modules)
def apply(target: sbt.internal.bsp.BuildTargetIdentifier, modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(Option(target), modules)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** Dependency Modules Request */
final class DependencyModulesParams private (
val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModulesParams => (this.targets == x.targets)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesParams".##) + targets.##)
}
override def toString: String = {
"DependencyModulesParams(" + targets + ")"
}
private def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = {
new DependencyModulesParams(targets)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = {
copy(targets = targets)
}
}
object DependencyModulesParams {
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = new DependencyModulesParams(targets)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** Dependency Modules Result */
final class DependencyModulesResult private (
val items: Vector[sbt.internal.bsp.DependencyModulesItem]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModulesResult => (this.items == x.items)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesResult".##) + items.##)
}
override def toString: String = {
"DependencyModulesResult(" + items + ")"
}
private def copy(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = {
new DependencyModulesResult(items)
}
def withItems(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = {
copy(items = items)
}
}
object DependencyModulesResult {
def apply(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = new DependencyModulesResult(items)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModuleFormats { self: sbt.internal.util.codec.JValueFormats & sjsonnew.BasicJsonProtocol =>
given DependencyModuleFormat: JsonFormat[sbt.internal.bsp.DependencyModule] = new JsonFormat[sbt.internal.bsp.DependencyModule] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModule = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val name = unbuilder.readField[String]("name")
val version = unbuilder.readField[String]("version")
val dataKind = unbuilder.readField[Option[String]]("dataKind")
val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data")
unbuilder.endObject()
sbt.internal.bsp.DependencyModule(name, version, dataKind, data)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModule, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("name", obj.name)
builder.addField("version", obj.version)
builder.addField("dataKind", obj.dataKind)
builder.addField("data", obj.data)
builder.endObject()
}
}
}

View File

@ -0,0 +1,29 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats =>
given DependencyModulesItemFormat: JsonFormat[sbt.internal.bsp.DependencyModulesItem] = new JsonFormat[sbt.internal.bsp.DependencyModulesItem] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesItem = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val target = unbuilder.readField[Option[sbt.internal.bsp.BuildTargetIdentifier]]("target")
val modules = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModule]]("modules")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesItem(target, modules)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesItem, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("target", obj.target)
builder.addField("modules", obj.modules)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol =>
given DependencyModulesParamsFormat: JsonFormat[sbt.internal.bsp.DependencyModulesParams] = new JsonFormat[sbt.internal.bsp.DependencyModulesParams] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesParams = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesParams(targets)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("targets", obj.targets)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesResultFormats { self: sbt.internal.bsp.codec.DependencyModulesItemFormats & sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats =>
given DependencyModulesResultFormat: JsonFormat[sbt.internal.bsp.DependencyModulesResult] = new JsonFormat[sbt.internal.bsp.DependencyModulesResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val items = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModulesItem]]("items")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesResult(items)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("items", obj.items)
builder.endObject()
}
}
}

View File

@ -43,6 +43,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.DependencySourcesParamsFormats
with sbt.internal.bsp.codec.DependencySourcesItemFormats
with sbt.internal.bsp.codec.DependencySourcesResultFormats
with sbt.internal.bsp.codec.DependencyModulesParamsFormats
with sbt.internal.bsp.codec.DependencyModuleFormats
with sbt.internal.bsp.codec.DependencyModulesItemFormats
with sbt.internal.bsp.codec.DependencyModulesResultFormats
with sbt.internal.bsp.codec.TaskStartParamsFormats
with sbt.internal.bsp.codec.TaskProgressParamsFormats
with sbt.internal.bsp.codec.TaskFinishParamsFormats

View File

@ -409,6 +409,35 @@ type DependencySourcesItem {
sources: [java.net.URI]
}
## Dependency Modules Request
type DependencyModulesParams {
targets: [sbt.internal.bsp.BuildTargetIdentifier]
}
## Dependency Modules Result
type DependencyModulesResult {
items: [sbt.internal.bsp.DependencyModulesItem]
}
type DependencyModulesItem {
target: sbt.internal.bsp.BuildTargetIdentifier
modules: [sbt.internal.bsp.DependencyModule]
}
type DependencyModule {
## Module name
name: String!
## Module version
version: String!
## Kind of data to expect in the `data` field.
dataKind: String
## Language-specific metadata about this module.
data: sjsonnew.shaded.scalajson.ast.unsafe.JValue
}
## Task Notifications
type TaskStartParams {

4
sbt
View File

@ -142,7 +142,7 @@ download_url () {
local jar="$2"
mkdir -p $(dirname "$jar") && {
if command -v curl > /dev/null; then
curl --silent -L "$url" --output "$jar"
curl --fail --silent -L "$url" --output "$jar"
elif command -v wget > /dev/null; then
wget --quiet -O "$jar" "$url"
else
@ -362,7 +362,7 @@ addSbtScriptProperty () {
}
addJdkWorkaround () {
local is_25="$(expr $java_version "=" 25)"
local is_25="$(expr $java_version ">=" 25)"
if [[ "$hide_jdk_warnings" == "0" ]]; then
:
else

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration/>

View File

@ -15,7 +15,7 @@ def completionsParser(state: State) =
{
val notQuoted = (NotQuoted ~ any.*) map { case (nq, s) => (nq +: s).mkString }
val quotedOrUnquotedSingleArgument = Space ~> (StringVerbatim | StringEscapable | notQuoted)
applyEffect(token(quotedOrUnquotedSingleArgument ?? "" examples ("", " ")))(runCompletions(state))
applyEffect(token((quotedOrUnquotedSingleArgument ?? "").examples("", " ")))(runCompletions(state))
}
def runCompletions(state: State)(input: String): State = {
val xs = Parser.completions(state.combinedParser, input, 9).get map {

View File

@ -5,7 +5,7 @@ lazy val bar = taskKey[Unit]("Runs the bar task")
def makeFoo(config: Configuration): Setting[?] =
config / foo := IO.write(file(s"${config.name}-foo"), "foo")
lazy val PerformanceTest = (config("pt") extend Test)
lazy val PerformanceTest = config("pt").extend(Test)
lazy val root = (project in file("."))
.configs(PerformanceTest)

View File

@ -0,0 +1,9 @@
lazy val scala212 = "2.12.21"
lazy val scala213 = "2.13.12"
ThisBuild / scalaVersion := scala212
lazy val root = (project in file("."))
.settings(
crossScalaVersions := Seq(scala212, scala213),
)

View File

@ -0,0 +1,11 @@
# Test that "cross" works as an alias for "+"
> cross clean
# Test that "cross" works with verbose flag
> cross -v compile
# Test that "switch" works as an alias for "++"
> switch 2.13.12!
# Test that "switch" works with a command
> switch 2.12.21! compile

View File

@ -2,7 +2,7 @@
import sbt.TupleSyntax.*
lazy val root = (project in file(".")).settings(
a := (baseDirectory mapN (b => if ((b / "succeed").exists) () else sys.error("fail"))).value,
a := baseDirectory.mapN(b => if ((b / "succeed").exists) () else sys.error("fail")).value,
// deprecated?
// b := (a.task(at => nop dependsOn(at))).value,
c := (a mapN { _ => () }).value,

View File

@ -17,7 +17,7 @@ val aResolver = Def.setting {
val bResolver = Def.setting {
val dir = (ThisBuild / baseDirectory).value / "b-repo"
Resolver.file("b-resolver", dir)(Resolver.defaultIvyPatterns)
Resolver.file("b-resolver", dir)(using Resolver.defaultIvyPatterns)
}
val apiBaseSetting = apiURL := Some(apiBase(name.value))

View File

@ -14,11 +14,11 @@ val check = inputKey[Unit]("")
val sample = AttributeKey[Int]("demo-key")
val dummyKey = taskKey[Unit]("")
def updateDemoInit = state map { s => (s get sample getOrElse 9) + 1 }
def updateDemoInit = state map { s => s.get(sample).getOrElse(9) + 1 }
lazy val root = (project in file(".")).
settings(
updateDemo := (updateDemoInit updateState demoState).value,
updateDemo := updateDemoInit.updateState(demoState).value,
check := checkInit.evaluated,
inMemorySetting,
persistedSetting,
@ -27,19 +27,19 @@ lazy val root = (project in file(".")).
dummyKey := (),
)
def demoState(s: State, i: Int): State = s put (sample, i + 1)
def demoState(s: State, i: Int): State = s.put(sample, i + 1)
def checkInit: Initialize[InputTask[Unit]] = Def inputTask {
val key = (token(Space ~> IntBasic) ~ token(Space ~> IntBasic).?).parsed
val (curExpected, prevExpected) = key
val value = updateDemo.value
val prev = state.value get sample
val prev = state.value.get(sample)
assert(value == curExpected, s"Expected current value to be $curExpected, got $value")
assert(prev == prevExpected, s"Expected previous value to be $prevExpected, got $prev")
}
def inMemorySetting = keep := (getPrevious(keep) map { case None => 3; case Some(x) => x + 1} keepAs(keep)).value
def persistedSetting = persist := (loadPrevious(persist) map { case None => 17; case Some(x) => x + 1} storeAs(persist)).value
def inMemorySetting = keep := getPrevious(keep) .map { case None => 3; case Some(x) => x + 1}.keepAs(keep).value
def persistedSetting = persist := loadPrevious(persist).map { case None => 17; case Some(x) => x + 1}.storeAs(persist).value
def inMemoryCheck = checkKeep := (inputCheck( (ctx, s) => Space ~> str( getFromContext( keep, ctx, s)) )).evaluated
def persistedCheck = checkPersist := (inputCheck( (ctx, s) => Space ~> str(loadFromContext(persist, ctx, s)) )).evaluated

View File

@ -0,0 +1,11 @@
lazy val helloWithoutStreams = taskKey[Unit]("")
lazy val helloWithStreams = taskKey[Unit]("")
helloWithoutStreams := {
throw new RuntimeException("boom without streams!")
}
helloWithStreams := {
val log = streams.value.log
throw new RuntimeException("boom with streams!")
}

View File

@ -0,0 +1,2 @@
-> helloWithoutStreams
-> helloWithStreams

View File

@ -63,7 +63,7 @@ def org = "test"
def mainArtifact = Artifact(artifactID, tpe, ext, classifier)
// define the IDs to use for publishing and retrieving
def publishedID = org % artifactID % vers artifacts(mainArtifact)
def publishedID = (org % artifactID % vers).artifacts(mainArtifact)
def retrieveID = org % "test-retrieve" % "2.0"
// check that the test class is on the compile classpath, either because it was compiled or because it was properly retrieved
@ -80,5 +80,5 @@ def checkTask(classpath: TaskKey[Classpath]) =
// use the user local resolver to fetch the SNAPSHOT version of the compiler-bridge
def userLocalFileResolver(appConfig: AppConfiguration): Resolver = {
val ivyHome = appConfig.provider.scalaProvider.launcher.ivyHome
Resolver.file("User Local", ivyHome / "local")(Resolver.defaultIvyPatterns)
Resolver.file("User Local", ivyHome / "local")(using Resolver.defaultIvyPatterns)
}

View File

@ -33,5 +33,5 @@ val a = project
// use the user local resolver to fetch the SNAPSHOT version of the compiler-bridge
def userLocalFileResolver(appConfig: AppConfiguration): Resolver = {
val ivyHome = appConfig.provider.scalaProvider.launcher.ivyHome
Resolver.file("User Local", ivyHome / "local")(Resolver.defaultIvyPatterns)
Resolver.file("User Local", ivyHome / "local")(using Resolver.defaultIvyPatterns)
}

View File

@ -2,7 +2,7 @@ lazy val check = taskKey[Unit]("check classifier in update report")
lazy val root = (project in file(".")).settings(
scalaVersion := "2.13.16",
libraryDependencies += "io.netty" % "netty-transport-native-epoll" % "4.1.118.Final" classifier "linux-x86_64",
libraryDependencies += ("io.netty" % "netty-transport-native-epoll" % "4.1.118.Final").classifier("linux-x86_64"),
check := {
val report = update.value
val modules = report.configurations.flatMap(_.modules)

View File

@ -1,4 +1,4 @@
ivyPaths := IvyPaths(baseDirectory.value.toString, Some(((ThisBuild / baseDirectory).value / "ivy" / "cache").toString))
ThisBuild / csrCacheDirectory := (ThisBuild / baseDirectory).value / "coursier-cache"
libraryDependencies += "org.testng" % "testng" % "5.7" classifier "jdk15"
libraryDependencies += ("org.testng" % "testng" % "5.7").classifier("jdk15")

View File

@ -1,2 +1,2 @@
ThisBuild / scalaVersion := "2.11.12"
libraryDependencies += "org.jclouds.api" % "nova" % "1.5.9" classifier "tests"
libraryDependencies += ("org.jclouds.api" % "nova" % "1.5.9").classifier("tests")

View File

@ -10,8 +10,8 @@ libraryDependencies += "bad" % "mvn" % "1.0"
TaskKey[Unit]("check") := {
val cp = (Compile / fullClasspath).value
def isTestJar(n: String): Boolean =
(n contains "scalacheck") ||
(n contains "specs2")
n.contains("scalacheck") ||
n.contains("specs2")
val testLibs = cp map (_.data.name) filter isTestJar
assert(testLibs.isEmpty, s"Compile Classpath has test libs:\n * ${testLibs.mkString("\n * ")}")
}

View File

@ -1,4 +1,4 @@
resolvers += Resolver.file("buggy", file("repo"))(
resolvers += Resolver.file("buggy", file("repo"))(using
Patterns(
ivyPatterns = Vector("[organization]/[module]/[revision]/ivy.xml"),
artifactPatterns = Vector("[organization]/[module]/[revision]/[artifact].[ext]"),
@ -8,5 +8,5 @@ resolvers += Resolver.file("buggy", file("repo"))(
)
)
libraryDependencies += "a" % "b" % "1.0.0" % "compile->runtime" artifacts(Artifact("b1", "jar", "jar"))
libraryDependencies += "a" % "b" % "1.0.0" % "test->runtime" artifacts(Artifact("b1", "jar", "jar"))
libraryDependencies += ("a" % "b" % "1.0.0" % "compile->runtime").artifacts(Artifact("b1", "jar", "jar"))
libraryDependencies += ("a" % "b" % "1.0.0" % "test->runtime").artifacts(Artifact("b1", "jar", "jar"))

View File

@ -61,5 +61,5 @@ val use2 = project
// use the user local resolver to fetch the SNAPSHOT version of the compiler-bridge
def userLocalFileResolver(appConfig: AppConfiguration): Resolver = {
val ivyHome = appConfig.provider.scalaProvider.launcher.ivyHome
Resolver.file("User Local", ivyHome / "local")(Resolver.defaultIvyPatterns)
Resolver.file("User Local", ivyHome / "local")(using Resolver.defaultIvyPatterns)
}

View File

@ -1,3 +1,3 @@
libraryDependencies += "org.vaadin" % "dontpush-addon-ozonelayer" % "0.4.6" exclude("org.atmosphere", "atmosphere-compat-jetty")
libraryDependencies += ("org.vaadin" % "dontpush-addon-ozonelayer" % "0.4.6").exclude("org.atmosphere", "atmosphere-compat-jetty")
resolvers += "asdf" at "https://maven.vaadin.com/vaadin-addons"

View File

@ -15,7 +15,7 @@ def check(className: String): Def.Initialize[Task[Unit]] =
import sbt.TupleSyntax.*
(Compile / fullClasspath, fileConverter.toTaskable) mapN { (cp, c) =>
given FileConverter = c
val existing = cp.files.filter(_.toFile.getName contains "scala-library")
val existing = cp.files.filter(_.toFile.getName.contains("scala-library"))
println("Full classpath: " + cp.mkString("\n\t", "\n\t", ""))
println("scala-library.jar: " + existing.mkString("\n\t", "\n\t", ""))
val loader = ClasspathUtilities.toLoader(existing.map(_.toFile()))

View File

@ -19,7 +19,7 @@ def libraryDeps(base: File) = {
def check(ver: String) =
(Compile / dependencyClasspath) map { jars =>
val log4j = jars map (_.data) collect {
case f if f.name contains "log4j-" => f.name
case f if f.name.contains("log4j-") => f.name
}
if (log4j.size != 1 || !log4j.head.contains(ver))
sys.error("Did not download the correct jar.")

View File

@ -13,7 +13,7 @@ val publishPort = 3030
// Publish to HTTP server (localhost) - ivyless publish uses PUT
// Resolver.url expects java.net.URL; in build.sbt "url" is sbt.URI, so use java.net.URL explicitly
publishTo := Some(
Resolver.url("test-repo", new java.net.URI(s"http://localhost:$publishPort/").toURL)(Resolver.ivyStylePatterns)
Resolver.url("test-repo", new java.net.URI(s"http://localhost:$publishPort/").toURL)(using Resolver.ivyStylePatterns)
.withAllowInsecureProtocol(true)
)

View File

@ -9,7 +9,7 @@ scalaVersion := "3.8.3"
val publishRepoBase = settingKey[File]("Base directory for publish repo")
publishRepoBase := baseDirectory.value / "repo"
publishTo := Some(Resolver.file("test-repo", publishRepoBase.value)(Resolver.ivyStylePatterns))
publishTo := Some(Resolver.file("test-repo", publishRepoBase.value)(using Resolver.ivyStylePatterns))
useIvy := false

View File

@ -12,7 +12,7 @@ version := ( if(stable.value) "1.0" else "1.1-SNAPSHOT" )
publishTo := {
val base = baseDirectory.value / ( if(stable.value) "stable" else "snapshot" )
Some( Resolver.file("local-" + base, base)(Resolver.ivyStylePatterns) )
Some( Resolver.file("local-" + base, base)(using Resolver.ivyStylePatterns) )
}
publishMavenStyle := false

View File

@ -1,6 +1,6 @@
addSbtPlugin("org.example" % "def" % "latest.integration")
resolvers ++= {
def r(tpe: String) = Resolver.file(s"local-$tpe", baseDirectory.value / ".." / tpe)(Resolver.ivyStylePatterns)
def r(tpe: String) = Resolver.file(s"local-$tpe", baseDirectory.value / ".." / tpe)(using Resolver.ivyStylePatterns)
r("snapshot") :: r("stable") :: Nil
}

View File

@ -1,11 +1,13 @@
import scala.xml._
lazy val root = (project in file(".")) settings (
lazy val root = (project in file(".")).settings(
readPom := Def.uncached {
val vf = makePom.value
val converter = fileConverter.value
XML.loadFile(converter.toPath(vf).toFile)
},
description := "pom.xml test description",
homepage := Some(url("https://example.com/pom_test_url")),
TaskKey[Unit]("checkPom") := checkPom.value,
TaskKey[Unit]("checkExtra") := checkExtra.value,
TaskKey[Unit]("checkVersionPlusMapping") := checkVersionPlusMapping.value,
@ -65,13 +67,17 @@ lazy val checkReleaseNotesURL = readPom.map: pomXml =>
lazy val checkPom = Def.task {
val pomXML = readPom.value
checkProject(pomXML)
val urlFromPom = (pomXML \ "url").text
assert(urlFromPom == "https://example.com/pom_test_url", s"Expected homepage url, got: $urlFromPom")
val descriptionFromPom = (pomXML \ "description").text
assert(descriptionFromPom == "pom.xml test description", s"Expected description, got: $descriptionFromPom")
val ivyRepositories = fullResolvers.value
withRepositories(pomXML) { repositoriesElement =>
val repositories = repositoriesElement \ "repository"
val writtenRepositories = repositories.map(read).distinct
val mavenStyleRepositories = (ivyRepositories.collect {
case x: MavenRepository
if (x.name != "public") && (x.name != "jcenter") && !(x.root startsWith "file:") =>
if (x.name != "public") && (x.name != "jcenter") && !(x.root.startsWith("file:")) =>
normalize(x)
}).distinct

View File

@ -10,7 +10,7 @@ TaskKey[Unit]("checkName") := Def.uncached {
val path = converter.toPath(vf).toAbsolutePath.toString
val module = moduleName.value
val n = name.value
assert(path contains module, s"Path $path did not contain module name $module")
assert(path.contains(module), s"Path $path did not contain module name $module")
assert(!path.contains(n), s"Path $path contained $n")
()
}

View File

@ -1,5 +1,5 @@
libraryDependencies ++= Seq("natives-windows", "natives-linux", "natives-osx") map ( c =>
"org.lwjgl.lwjgl" % "lwjgl-platform" % "2.8.2" classifier c
("org.lwjgl.lwjgl" % "lwjgl-platform" % "2.8.2").classifier(c)
)
autoScalaLibrary := false

View File

@ -7,7 +7,7 @@ def commonSettings: Seq[Def.Setting[?]] =
scalaVersion := "2.10.4",
ThisBuild / organization := "org.example",
ThisBuild / version := "1.0-SNAPSHOT",
resolvers += Resolver.file("old-local", file(sys.props("user.home") + "/.ivy2/local"))(Resolver.ivyStylePatterns)
resolvers += Resolver.file("old-local", file(sys.props("user.home") + "/.ivy2/local"))(using Resolver.ivyStylePatterns)
)
lazy val main = project.

View File

@ -7,7 +7,7 @@ lazy val root = (project in file("."))
dependencyOverrides += "org.webjars.npm" % "is-number" % "5.0.0",
check := {
val cp = (Compile / externalDependencyClasspath).value.map {_.data.name}.sorted
if (!(cp contains "is-number-5.0.0.jar")) {
if (!cp.contains("is-number-5.0.0.jar")) {
sys.error("is-number-5.0.0 not found when it should be included: " + cp.toString)
}
}

View File

@ -29,7 +29,7 @@ def pomIncludeRepository(base: File, prev: MavenRepository => Boolean): MavenRep
}
def addSlash(s: String): String = s match {
case s if s endsWith "/" => s
case s if s.endsWith("/") => s
case _ => s + "/"
}

View File

@ -4,7 +4,7 @@ lazy val root = (project in file("."))
.settings(
scalaVersion := "2.13.16",
autoScalaLibrary := false,
libraryDependencies += "org.eclipse.jetty" % "jetty-webapp" % "11.0.15" artifacts (Artifact("jetty-webapp", "war", "war")),
libraryDependencies += ("org.eclipse.jetty" % "jetty-webapp" % "11.0.15").artifacts(Artifact("jetty-webapp", "war", "war")),
libraryDependencies += "com.typesafe" % "config" % "1.4.3",
// classified artifact with non-default type: both <type> and <classifier> must appear
libraryDependencies += ("com.example" % "classified-war" % "1.0")

View File

@ -1,8 +1,8 @@
val root = project in file(".")
val subJar = project in file("subJar")
def warArtifact = (Compile / packageBin / artifact) ~= (_ withType "war" withExtension "war")
val subWar = project in file("subWar") settings warArtifact
val subParent = project in file("subParent") settings ((Compile / publishArtifact) := false)
def warArtifact = (Compile / packageBin / artifact) ~= (_.withType("war").withExtension("war"))
val subWar = project.in(file("subWar")).settings(warArtifact)
val subParent = project.in(file("subParent")).settings((Compile / publishArtifact) := false)
val checkPom = taskKey[Unit]("")
(ThisBuild / checkPom) := {

View File

@ -15,8 +15,8 @@ lazy val root = (project in file(".")).
"d" % "d" % "1.0" % "test",
"e" % "e" % "1.0" % Custom,
"f" % "f" % "1.0" % "custom,optional,runtime",
"g" % "g" % "1.0" % "custom,runtime" classifier "foo",
"h" % "h" % "1.0" % "custom,optional,runtime" classifier "foo"
("g" % "g" % "1.0" % "custom,runtime").classifier("foo"),
("h" % "h" % "1.0" % "custom,optional,runtime").classifier("foo")
)
)

View File

@ -27,7 +27,7 @@ lazy val root = (project in file(".")).
)
def checkServletAPI(paths: Seq[File], shouldBeIncluded: Boolean, label: String) = {
val servletAPI = paths.find(_.getName contains "servlet-api")
val servletAPI = paths.find(_.getName.contains("servlet-api"))
if (shouldBeIncluded) {
if (servletAPI.isEmpty) sys.error(s"Servlet API should have been included in $label.")
} else

View File

@ -7,7 +7,7 @@ lazy val root = (project in file(".")).
organization := "A",
version := "1.0",
ivyPaths := baseDirectory( dir => IvyPaths(dir, Some(dir / "ivy" / "cache")) ).value,
externalResolvers := (baseDirectory map { base => Resolver.file("local", base / "ivy" / "local" asFile)(Resolver.ivyStylePatterns) :: Nil }).value
externalResolvers := (baseDirectory map { base => Resolver.file("local", base / "ivy" / "local" asFile)(using Resolver.ivyStylePatterns) :: Nil }).value
)),
mavenStyle,
interProject,

View File

@ -5,7 +5,7 @@ lazy val root = (project in file(".")).
organization := "A",
version := "1.0",
ivyPaths := baseDirectory( dir => IvyPaths(dir, Some(dir / "ivy" / "cache")) ).value,
externalResolvers := (baseDirectory map { base => Resolver.file("local", base / "ivy" / "local" asFile)(Resolver.ivyStylePatterns) :: Nil }).value
externalResolvers := (baseDirectory map { base => Resolver.file("local", base / "ivy" / "local" asFile)(using Resolver.ivyStylePatterns) :: Nil }).value
)),
mavenStyle,
name := "Retrieve Test",

View File

@ -17,11 +17,11 @@ libraryDependencies += "org.scala-lang" % "scala-actors" % "2.11.12"
lazy val check = taskKey[Unit]("Runs the check")
check := {
val lastLog = BuiltinCommands lastLogFile state.value
val lastLog = BuiltinCommands.lastLogFile(state.value)
val last = IO read lastLog.get
def containsWarn1 = last contains "Binary version (1.1.0) for dependency org.scala-lang#scala-actors-migration_2.11;1.1.0"
def containsWarn2 = last contains "Binary version (0.9.1) for dependency org.scala-lang#scala-pickling_2.11;0.9.1"
def containsWarn3 = last contains "differs from Scala binary version in project (2.11)."
def containsWarn1 = last.contains("Binary version (1.1.0) for dependency org.scala-lang#scala-actors-migration_2.11;1.1.0")
def containsWarn2 = last.contains("Binary version (0.9.1) for dependency org.scala-lang#scala-pickling_2.11;0.9.1")
def containsWarn3 = last.contains("differs from Scala binary version in project (2.11).")
if (containsWarn1 && containsWarn3) sys error "scala-actors-migration isn't exempted from the Scala binary version check"
if (containsWarn2 && containsWarn3) sys error "scala-pickling isn't exempted from the Scala binary version check"
}

View File

@ -7,7 +7,7 @@ def localCache =
lazy val sharedResolver: Resolver = {
val r = Resolver.defaultShared
r withConfiguration (r.configuration withIsLocal false)
r.withConfiguration(r.configuration.withIsLocal(false))
//MavenRepository("example-shared-repo", "file:///tmp/shared-maven-repo-bad-example")
//Resolver.file("example-shared-repo", repoDir)(Resolver.defaultPatterns)
}

View File

@ -9,7 +9,7 @@ def localCache =
lazy val sharedResolver: Resolver = {
val r = Resolver.defaultShared
r withConfiguration (r.configuration withIsLocal false)
r.withConfiguration(r.configuration.withIsLocal(false))
//MavenRepository("example-shared-repo", "file:///tmp/shared-maven-repo-bad-example")
//Resolver.file("example-shared-repo", repoDir)(Resolver.defaultPatterns)
}

View File

@ -5,8 +5,8 @@ lazy val root = (project in file("."))
autoScalaLibrary := false,
managedScalaInstance := false,
transitiveClassifiers := Seq("sources"),
TaskKey[Unit]("checkSources") := (updateClassifiers map checkSources).value,
TaskKey[Unit]("checkBinaries") := (update map checkBinaries).value,
TaskKey[Unit]("checkSources") := updateClassifiers.map(checkSources).value,
TaskKey[Unit]("checkBinaries") := update.map(checkBinaries).value,
)
def getSources(report: UpdateReport) = report.matching(artifactFilter(`classifier` = "sources") )

View File

@ -3,8 +3,8 @@ ThisBuild / scalaVersion := "2.12.12"
lazy val root = (project in file("."))
.settings(
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.5.22",
TaskKey[Unit]("checkSources") := (updateClassifiers map checkSources).value,
TaskKey[Unit]("checkBinaries") := (update map checkBinaries).value
TaskKey[Unit]("checkSources") := updateClassifiers.map(checkSources).value,
TaskKey[Unit]("checkBinaries") := update.map(checkBinaries).value
)
def getSources(report: UpdateReport) = report.matching(artifactFilter(`classifier` = "sources") )

View File

@ -1,3 +1,3 @@
libraryDependencies += "org.example" % "def" % "2.0" classifier("tests")
libraryDependencies += ("org.example" % "def" % "2.0").classifier("tests")
externalResolvers := Seq("example" at (baseDirectory.value / "ivy-repo").toURI.toString)

View File

@ -9,9 +9,9 @@ libraryDependencies += "exclude.test" % "app" % "1.0.0"
val checkDependencies = taskKey[Unit]("Checks that dependencies are correct.")
checkDependencies := {
val hasBadJar = (Compile / fullClasspath).value.exists { jar => jar.data.name contains "bottom-1.0.0.jar"}
val hasBadJar = (Compile / fullClasspath).value.exists { jar => jar.data.name.contains("bottom-1.0.0.jar")}
val errorJarString = (Compile / fullClasspath).value.map(_.data.name).mkString(" * ", "\n * ", "")
val hasBadMiddleJar = (Compile / fullClasspath).value.exists { jar => jar.data.name contains "middle-1.0.0.jar"}
val hasBadMiddleJar = (Compile / fullClasspath).value.exists { jar => jar.data.name.contains("middle-1.0.0.jar")}
assert(!hasBadMiddleJar, s"Failed to exclude excluded dependency on classpath!\nFound:\n$errorJarString")
assert(!hasBadJar, s"Failed to exclude transitive excluded dependency on classpath!\nFound:\n$errorJarString")
val modules =

View File

@ -1,3 +1,3 @@
ThisBuild / scalaVersion := "2.11.12"
libraryDependencies += "ccl.northwestern.edu" % "netlogo" % "5.3.1" % "provided" from s"https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar"
libraryDependencies += ("ccl.northwestern.edu" % "netlogo" % "5.3.1" % "provided").from(s"https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar")

View File

@ -8,7 +8,7 @@ def localCache =
lazy val root = (project in file(".")).
settings(
localCache,
libraryDependencies += "org.jsoup" % "jsoup" % "1.9.1" % Test from "https://jsoup.org/packages/jsoup-1.9.1.jar",
libraryDependencies += ("org.jsoup" % "jsoup" % "1.9.1" % Test).from("https://jsoup.org/packages/jsoup-1.9.1.jar"),
ivyLoggingLevel := UpdateLogging.Full,
TaskKey[Unit]("checkInTest") := checkClasspath(Test).value,
TaskKey[Unit]("checkInCompile") := checkClasspath(Compile).value

View File

@ -14,7 +14,7 @@ val commonSettings = Seq[Def.Setting[?]](
lazy val bippy = project settings (
commonSettings,
resolvers += Resolver
.file("ivy-local", file(sys.props("user.home")) / ".ivy2" / "local")(Resolver.ivyStylePatterns),
.file("ivy-local", file(sys.props("user.home")) / ".ivy2" / "local")(using Resolver.ivyStylePatterns),
publishTo := Some(Resolver.file("local-repo", localRepo.value))
)
@ -40,6 +40,6 @@ InputKey[Unit]("check") := {
val s = IO readStream jar.getInputStream(jar.getJarEntry("Bippy.scala"))
val expected = s"def release = $n"
assert(s contains expected, s"""Bippy should contain $expected, contents:\n$s""")
assert(s.contains(expected), s"""Bippy should contain $expected, contents:\n$s""")
()
}

View File

@ -1 +1 @@
resolvers += Resolver.file("ivy-local", file(sys.props("user.home")) / ".ivy2" / "local")(Resolver.ivyStylePatterns)
resolvers += Resolver.file("ivy-local", file(sys.props("user.home")) / ".ivy2" / "local")(using Resolver.ivyStylePatterns)

View File

@ -31,10 +31,10 @@ lazy val root = (project in file(".")).
val acp = (a / Compile / externalDependencyClasspath).value.sortBy {_.data.name}
val bcp = (b / Compile / externalDependencyClasspath).value.sortBy {_.data.name}
if (acp exists { _.data.name contains "slf4j-api-1.7.5.jar" }) {
if (acp exists { _.data.name.contains("slf4j-api-1.7.5.jar") }) {
sys.error("slf4j-api-1.7.5.jar found when it should NOT be included: " + acp.toString)
}
if (bcp exists { _.data.name contains "dispatch-core_2.11-0.11.1.jar" }) {
if (bcp exists { _.data.name.contains("dispatch-core_2.11-0.11.1.jar") }) {
sys.error("dispatch-core_2.11-0.11.1.jar found when it should NOT be included: " + bcp.toString)
}

View File

@ -10,7 +10,7 @@ lazy val b = project
lazy val bResolver = Def.setting {
val dir = (ThisBuild / baseDirectory).value / "b-repo"
Resolver.file("b-resolver", dir)(Resolver.defaultIvyPatterns)
Resolver.file("b-resolver", dir)(using Resolver.defaultIvyPatterns)
}
lazy val check = taskKey[Unit]("")

View File

@ -1,2 +1,2 @@
scalaVersion := "2.12.8"
libraryDependencies += "org.jclouds.api" % "nova" % "1.5.9" classifier "tests"
libraryDependencies += ("org.jclouds.api" % "nova" % "1.5.9").classifier("tests")

View File

@ -1,3 +1,3 @@
scalaVersion := "2.12.21"
libraryDependencies += "ccl.northwestern.edu" % "netlogo" % "5.3.1" % "provided" from s"https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar"
libraryDependencies += ("ccl.northwestern.edu" % "netlogo" % "5.3.1" % "provided").from(s"https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar")

View File

@ -1,3 +1,3 @@
scalaVersion := "2.12.8"
resolvers += Resolver.file("space-repo", file(raw"/tmp/space the final frontier/repo"))(Resolver.ivyStylePatterns)
resolvers += Resolver.file("space-repo", file(raw"/tmp/space the final frontier/repo"))(using Resolver.ivyStylePatterns)

View File

@ -10,7 +10,7 @@ mainClass := Some("jartest.Main")
Compile / packageBin / packageOptions := {
def manifestExtra = {
val mf = new Manifest
mf.getMainAttributes.put(Attributes.Name.CLASS_PATH, makeString(scalaInstance.value.libraryJars))
mf.getMainAttributes.put(Attributes.Name.CLASS_PATH, makeString(scalaInstance.value.libraryJars.toSeq))
mf
}
(Compile / packageBin / packageOptions).value :+ Package.JarManifest(manifestExtra)

View File

@ -9,7 +9,7 @@ packageOptions := {
def manifestExtra = {
import java.util.jar._
val mf = new Manifest
mf.getMainAttributes.put(Attributes.Name.CLASS_PATH, makeString(scalaInstance.value.libraryJars))
mf.getMainAttributes.put(Attributes.Name.CLASS_PATH, makeString(scalaInstance.value.libraryJars.toSeq))
mf
}
Package.JarManifest(manifestExtra) +: packageOptions.value

View File

@ -1,4 +1,4 @@
val test123 = project in file(".") enablePlugins TestP settings(
val test123 = project.in(file(".")).enablePlugins(TestP).settings(
Compile / resourceGenerators += Def.task {
streams.value.log.info("resource generated in settings")
Seq.empty[File]
@ -6,9 +6,9 @@ val test123 = project in file(".") enablePlugins TestP settings(
)
TaskKey[Unit]("check") := {
val last = IO read (BuiltinCommands lastLogFile state.value).get
val last = IO.read(BuiltinCommands.lastLogFile(state.value).get)
def assertContains(expectedString: String) =
if (!(last contains expectedString)) sys error s"Expected string $expectedString to be present"
if (!last.contains(expectedString)) sys error s"Expected string $expectedString to be present"
assertContains("resource generated in settings")
assertContains("resource generated in plugin")
}

View File

@ -2,7 +2,7 @@ val root = (project in file("."))
TaskKey[Unit]("checkScalaVersion", "test") := Def.uncached {
val sv = scalaVersion.value
assert(sv startsWith "3.", s"Found $sv!")
assert(sv.startsWith("3."), s"Found $sv!")
}
TaskKey[Unit]("checkArtifacts", "test") := Def.uncached {

View File

@ -2,7 +2,7 @@
val loadCount = AttributeKey[Int]("load-count")
val unloadCount = AttributeKey[Int]("unload-count")
def f(key: AttributeKey[Int]) = (s: State) => {
val previous = s get key getOrElse 0
val previous = s.get(key)getOrElse(0)
s.put(key, previous + 1)
}
Seq(
@ -14,7 +14,7 @@
InputKey[Unit]("checkCount") := {
val s = state.value
val args = Def.spaceDelimited().parsed
def get(label: String) = s get AttributeKey[Int](label) getOrElse 0
def get(label: String) = s.get(AttributeKey[Int](label)).getOrElse(0)
val loadCount = get("load-count")
val unloadCount = get("unload-count")
val expectedLoad = args(0).toInt

View File

@ -21,7 +21,7 @@ object Common {
val UpdateK3 = Command.command("UpdateK3"): (st: State) =>
val ex = Project extract st
val ex = Project.extract(st)
import ex._
val session2 = BuiltinCommands.setThis(ex, Seq(k3 := {}), """k3 := {
|//

View File

@ -15,7 +15,7 @@ lazy val commonSettings = Seq(
val ivyHome = Classpaths.bootIvyHome(appConfiguration.value) getOrElse sys.error(
"Launcher did not provide the Ivy home directory."
)
Resolver.file("real-local", ivyHome / "local")(Resolver.ivyStylePatterns)
Resolver.file("real-local", ivyHome / "local")(using Resolver.ivyStylePatterns)
},
resolvers += Resolver.mavenLocal,
resolvers += ("test-repo" at ((ThisBuild / baseDirectory).value / "repo/").asURL.toString)

View File

@ -1,2 +1,2 @@
lazy val a = project in file(".") dependsOn(b)
lazy val a = project.in(file(".")).dependsOn(b)
lazy val b = project

View File

@ -4,5 +4,5 @@ lazy val dep = project
lazy val use = project.
settings(
(Compile / unmanagedJars) += ((dep / Compile / packageBin) map Attributed.blank).value
(Compile / unmanagedJars) += (dep / Compile / packageBin).map(Attributed.blank).value
)

View File

@ -10,8 +10,9 @@ object Main:
val sbtHome = new File(
sys.env
.get("SBT_HOME")
.getOrElse:
.getOrElse(
sys.env.get("SBT_BIN_DIR").map(d => new File(d).getParent).getOrElse(cwd.getAbsolutePath)
)
)
val sbtBinDir = new File(sbtHome, "bin")
@ -26,86 +27,88 @@ object Main:
System.exit(if exitCode == 0 then 0 else 1)
private def run(cwd: File, sbtHome: File, sbtBinDir: File, opts: LauncherOptions): Int =
if opts.help then return printUsage()
if opts.version || opts.numericVersion || opts.scriptVersion then
return handleVersionCommands(cwd, sbtHome, sbtBinDir, opts)
if opts.shutdownAll then
if opts.help then printUsage()
else if opts.version || opts.numericVersion || opts.scriptVersion then
handleVersionCommands(cwd, sbtHome, sbtBinDir, opts)
else if opts.shutdownAll then
val javaCmd = Runner.findJavaCmd(opts.javaHome)
return Runner.shutdownAll(javaCmd)
if !opts.allowEmpty && !opts.sbtNew && !ConfigLoader.isSbtProjectDir(cwd) then
Runner.shutdownAll(javaCmd)
else if !opts.allowEmpty && !opts.sbtNew && !ConfigLoader.isSbtProjectDir(cwd) then
System.err.println(
"[error] Neither build.sbt nor a 'project' directory in the current directory: " + cwd
)
System.err.println("[error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'.")
return 1
1
else
val buildPropsVersion = ConfigLoader.sbtVersionFromBuildProperties(cwd)
val buildPropsVersion = ConfigLoader.sbtVersionFromBuildProperties(cwd)
val javaCmd = Runner.findJavaCmd(opts.javaHome)
val javaVer = Runner.javaVersion(javaCmd)
val minJdk = Runner.minimumJdkVersion(buildPropsVersion)
if javaVer > 0 && javaVer < minJdk then
if minJdk >= 17 then
System.err.println(
"[error] sbt 2.x requires JDK 17 or above, but you have JDK " + javaVer
)
else System.err.println("[error] sbt requires at least JDK 8+, you have " + javaVer)
1
else
val bspMode = opts.residual.exists(a => a == "bsp" || a == "-bsp" || a == "--bsp")
val clientOpt = opts.client || sys.env.get("SBT_NATIVE_CLIENT").contains("true")
val useNativeClient =
if bspMode then false
else shouldRunNativeClient(opts.copy(client = clientOpt), buildPropsVersion)
val javaCmd = Runner.findJavaCmd(opts.javaHome)
val javaVer = Runner.javaVersion(javaCmd)
val minJdk = Runner.minimumJdkVersion(buildPropsVersion)
if javaVer > 0 && javaVer < minJdk then
if minJdk >= 17 then
System.err.println("[error] sbt 2.x requires JDK 17 or above, but you have JDK " + javaVer)
else System.err.println("[error] sbt requires at least JDK 8+, you have " + javaVer)
return 1
if useNativeClient then
val scriptPath = sbtBinDir.getAbsolutePath.replace("\\", "/") + "/sbt.bat"
Runner.runNativeClient(sbtBinDir, scriptPath, opts)
else
val sbtJar = opts.sbtJar
.filter(p => new File(p).isFile)
.getOrElse(new File(sbtBinDir, "sbt-launch.jar").getAbsolutePath)
if !new File(sbtJar).isFile then
System.err.println("[error] Launcher jar not found: " + sbtJar)
1
else
var javaOpts = ConfigLoader.loadJvmOpts(cwd)
if javaOpts.isEmpty then javaOpts = ConfigLoader.defaultJavaOpts
var sbtOpts = Runner.buildSbtOpts(opts)
val bspMode = opts.residual.exists(a => a == "bsp" || a == "-bsp" || a == "--bsp")
val clientOpt = opts.client || sys.env.get("SBT_NATIVE_CLIENT").contains("true")
val useNativeClient =
if bspMode then false
else shouldRunNativeClient(opts.copy(client = clientOpt), buildPropsVersion)
val (residualJava, bootArgs) = Runner.splitResidual(opts.residual)
javaOpts = javaOpts ++ residualJava
if useNativeClient then
val scriptPath = sbtBinDir.getAbsolutePath.replace("\\", "/") + "/sbt.bat"
return Runner.runNativeClient(sbtBinDir, scriptPath, opts)
val (finalJava, finalSbt) = if opts.mem.isDefined then
val evictedJava = Memory.evictMemoryOpts(javaOpts)
val evictedSbt = Memory.evictMemoryOpts(sbtOpts)
val memOpts = Memory.addMemory(opts.mem.get, javaVer)
(evictedJava ++ memOpts, evictedSbt)
else Memory.addDefaultMemory(javaOpts, sbtOpts, javaVer, LauncherOptions.defaultMemMb)
sbtOpts = finalSbt
val sbtJar = opts.sbtJar
.filter(p => new File(p).isFile)
.getOrElse(new File(sbtBinDir, "sbt-launch.jar").getAbsolutePath)
if !new File(sbtJar).isFile then
System.err.println("[error] Launcher jar not found: " + sbtJar)
return 1
if !opts.noHideJdkWarnings && javaVer >= 25 then
sbtOpts = sbtOpts ++ Seq(
"--sun-misc-unsafe-memory-access=allow",
"--enable-native-access=ALL-UNNAMED"
)
val javaOptsWithDebug = opts.jvmDebug.fold(finalJava)(port =>
finalJava :+ s"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$port"
)
var javaOpts = ConfigLoader.loadJvmOpts(cwd)
if javaOpts.isEmpty then javaOpts = ConfigLoader.defaultJavaOpts
var sbtOpts = Runner.buildSbtOpts(opts)
val (residualJava, bootArgs) = Runner.splitResidual(opts.residual)
javaOpts = javaOpts ++ residualJava
val (finalJava, finalSbt) = if opts.mem.isDefined then
val evictedJava = Memory.evictMemoryOpts(javaOpts)
val evictedSbt = Memory.evictMemoryOpts(sbtOpts)
val memOpts = Memory.addMemory(opts.mem.get, javaVer)
(evictedJava ++ memOpts, evictedSbt)
else Memory.addDefaultMemory(javaOpts, sbtOpts, javaVer, LauncherOptions.defaultMemMb)
sbtOpts = finalSbt
if !opts.noHideJdkWarnings && javaVer == 25 then
sbtOpts = sbtOpts ++ Seq(
"--sun-misc-unsafe-memory-access=allow",
"--enable-native-access=ALL-UNNAMED"
)
val javaOptsWithDebug = opts.jvmDebug.fold(finalJava)(port =>
finalJava :+ s"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$port"
)
Runner.runJvm(javaCmd, javaOptsWithDebug, sbtOpts, sbtJar, bootArgs, opts.verbose)
Runner.runJvm(javaCmd, javaOptsWithDebug, sbtOpts, sbtJar, bootArgs, opts.verbose)
private def shouldRunNativeClient(
opts: LauncherOptions,
buildPropsVersion: Option[String]
): Boolean =
if opts.sbtNew then return false
if opts.jvmClient then return false
val version = buildPropsVersion.getOrElse(LauncherOptions.initSbtVersion)
val parts = version.split("[.-]").take(2).flatMap(s => scala.util.Try(s.toInt).toOption)
val (major, minor) = (parts.lift(0).getOrElse(0), parts.lift(1).getOrElse(0))
if major >= 2 then !opts.server
else if major >= 1 && minor >= 4 then opts.client
else false
if opts.sbtNew then false
else if opts.jvmClient then false
else
val version = buildPropsVersion.getOrElse(LauncherOptions.initSbtVersion)
val parts = version.split("[.-]").take(2).flatMap(s => scala.util.Try(s.toInt).toOption)
val (major, minor) = (parts.lift(0).getOrElse(0), parts.lift(1).getOrElse(0))
if major >= 2 then !opts.server
else if major >= 1 && minor >= 4 then opts.client
else false
private def handleVersionCommands(
cwd: File,
@ -115,8 +118,8 @@ object Main:
): Int =
if opts.scriptVersion then
println(LauncherOptions.initSbtVersion)
return 0
if opts.version then
0
else if opts.version then
if ConfigLoader.isSbtProjectDir(cwd) then
projectSbtVersion(cwd).foreach: version =>
println("sbt version in this project: " + version)
@ -125,21 +128,22 @@ object Main:
System.err.println(
"[info] Actual version of sbt is declared using project\\build.properties for each build."
)
return 0
if opts.numericVersion then
0
else if opts.numericVersion then
val javaCmd = Runner.findJavaCmd(opts.javaHome)
val sbtJar = opts.sbtJar
.filter(p => new File(p).isFile)
.getOrElse(new File(sbtBinDir, "sbt-launch.jar").getAbsolutePath)
if !new File(sbtJar).isFile then
System.err.println("[error] Launcher jar not found for version check")
return 1
try
val out = Process(Seq(javaCmd, "-jar", sbtJar, "sbtVersion")).!!
println(out.linesIterator.toSeq.lastOption.map(_.trim).getOrElse(""))
return 0
catch { case _: Exception => return 1 }
0
1
else
try
val out = Process(Seq(javaCmd, "-jar", sbtJar, "sbtVersion")).!!
println(out.linesIterator.toSeq.lastOption.map(_.trim).getOrElse(""))
0
catch { case _: Exception => 1 }
else 0
private def projectSbtVersion(cwd: File): Option[String] =
ConfigLoader.sbtVersionFromBuildProperties(cwd).flatMap(normalizeVersion)

View File

@ -524,6 +524,19 @@ class BuildServerTest extends AbstractServerTest {
)
}
test("buildTarget/dependencyModules") {
val buildTarget = buildTargetUri("runAndTest", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
val targets = Vector(buildTarget, badBuildTarget).map(BuildTargetIdentifier.apply)
val id = dependencyModules(targets.map(_.uri))
val res = svr.session.waitForResultInResponseMsg[DependencyModulesResult](10.seconds, id).get
val runAndTestItem = res.items.find(_.target.contains(BuildTargetIdentifier(buildTarget))).get
assert(
runAndTestItem.modules.exists(_.name.contains("jsoniter-scala-core")),
s"dependencyModules should include jsoniter-scala-core, got: ${runAndTestItem.modules.map(_.name)}"
)
}
test("buildTarget/outputPaths") {
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
@ -753,6 +766,11 @@ class BuildServerTest extends AbstractServerTest {
sendRequest("buildTarget/sources", SourcesParams(targets))
}
private def dependencyModules(buildTargets: Seq[URI]): String = {
val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector
sendRequest("buildTarget/dependencyModules", DependencyModulesParams(targets))
}
private def sendRequest(method: String): String = {
val id = svr.session.nextId()
svr.session.sendJsonRpc(id, method, "{}").get

View File

@ -79,6 +79,16 @@ class ResponseTest extends AbstractServerTest {
}
}
test("unknown method returns error") {
val id = svr.session.nextId()
svr.session.sendJsonRpc(id, "build/foo", "{}").get
val response = svr.session.waitForResponseMsg(10.seconds, id).get
assert(
response.error.exists(_.code == -32601),
s"Expected method-not-found error, got: $response"
)
}
private def neverReceiveResponse(
duration: FiniteDuration
)(predicate: sbt.internal.protocol.JsonRpcResponseMessage => Boolean): Unit =

View File

@ -13,9 +13,9 @@ import java.util.concurrent.atomic.AtomicReference
import testing.{ Event as TEvent, OptionalThrowable, Status as TStatus, TestSelector }
import util.{ AbstractLogger, Level, ControlEvent, LogEvent }
import sbt.io.IO
import sbt.protocol.testing.TestResult
import sbt.internal.worker1.ForkTestMain
import sbt.io.IO
import verify.BasicTestSuite
import scala.xml.XML

View File

@ -10,7 +10,7 @@ package sbt.util
import java.io.{ File, IOException }
import java.nio.charset.StandardCharsets
import java.nio.file.{ Files, Path, Paths, StandardCopyOption }
import java.nio.file.{ AtomicMoveNotSupportedException, Files, Path, Paths, StandardCopyOption }
import sbt.internal.util.{ ActionCacheEvent, CacheEventLog, StringVirtualFile1 }
import sbt.io.syntax.*
import sbt.io.IO
@ -82,40 +82,40 @@ object ActionCache:
case e: Exception =>
cacheEventLog.append(ActionCacheEvent.Error)
throw e
val json = Converter.toJsonUnsafe(result)
val normalizedOutputDir = outputDirectory.toAbsolutePath.normalize()
val uncacheableOutputs =
outputs.filter(f =>
f match
case vf if vf.id.endsWith(ActionCache.dirZipExt) =>
false
case _ =>
val outputPath = fileConverter.toPath(f).toAbsolutePath.normalize()
!outputPath.startsWith(normalizedOutputDir)
)
if uncacheableOutputs.nonEmpty then
cacheEventLog.append(ActionCacheEvent.Error)
logger.error(
s"Cannot cache task because its output files are outside the output directory: \n" +
uncacheableOutputs.mkString(" - ", "\n - ", "")
)
result
else
cacheEventLog.append(ActionCacheEvent.OnsiteTask)
val (input, valuePath) = mkInput(key, codeContentHash, extraHash, config.cacheVersion)
val valueFile = StringVirtualFile1(valuePath, CompactPrinter(json))
val newOutputs = Vector(valueFile) ++ outputs.toVector
try
try
val json = Converter.toJsonUnsafe(result)
val normalizedOutputDir = outputDirectory.toAbsolutePath.normalize()
val uncacheableOutputs =
outputs.filter(f =>
f match
case vf if vf.id.endsWith(ActionCache.dirZipExt) =>
false
case _ =>
val outputPath = fileConverter.toPath(f).toAbsolutePath.normalize()
!outputPath.startsWith(normalizedOutputDir)
)
if uncacheableOutputs.nonEmpty then
cacheEventLog.append(ActionCacheEvent.Error)
logger.error(
s"Cannot cache task because its output files are outside the output directory: \n" +
uncacheableOutputs.mkString(" - ", "\n - ", "")
)
result
else
cacheEventLog.append(ActionCacheEvent.OnsiteTask)
val (input, valuePath) = mkInput(key, codeContentHash, extraHash, config.cacheVersion)
val valueFile = StringVirtualFile1(valuePath, CompactPrinter(json))
val newOutputs = Vector(valueFile) ++ outputs.toVector
store.put(UpdateActionResultRequest(input, newOutputs, exitCode = 0)) match
case Right(cachedResult) =>
store.syncBlobs(cachedResult.outputFiles, outputDirectory)
result
case Left(e) => throw e
catch
case e: IOException =>
logger.debug(s"Skipping cache storage due to error: ${e.getMessage}")
cacheEventLog.append(ActionCacheEvent.Error)
result
catch
case e: IOException =>
logger.debug(s"Skipping cache storage due to error: ${e.getMessage}")
cacheEventLog.append(ActionCacheEvent.Error)
result
// Single cache lookup - use exitCode to distinguish success from failure
getWithFailure(key, codeContentHash, extraHash, tags, config) match
@ -270,6 +270,36 @@ object ActionCache:
private val default2010Timestamp: Long = 1262304000000L
/**
* Publishes `builtZip` as `destZip` by staging next to the destination and renaming into place.
* Avoids races from a direct `Files.copy` into `destZip` under parallel task execution.
*/
private def installPackagedZip(builtZip: Path, destZip: Path, fallbackStagingDir: Path): Unit =
val stagingDir = Option(destZip.getParent) match
case Some(parent) =>
Files.createDirectories(parent)
parent
case None => fallbackStagingDir
val staging = Files.createTempFile(
stagingDir,
destZip.getFileName.toString + ".",
dirZipExt + ".tmp",
)
try
Files.copy(builtZip, staging, StandardCopyOption.REPLACE_EXISTING)
try
Files.move(
staging,
destZip,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.ATOMIC_MOVE,
)
catch
case _: AtomicMoveNotSupportedException =>
Files.move(staging, destZip, StandardCopyOption.REPLACE_EXISTING)
finally Files.deleteIfExists(staging)
def packageDirectory(
dir: VirtualFileRef,
conv: FileConverter,
@ -311,7 +341,7 @@ object ActionCache:
tempZipPath.toFile(),
Some(default2010Timestamp)
)
Files.copy(tempZipPath, zipPath, StandardCopyOption.REPLACE_EXISTING)
installPackagedZip(tempZipPath, zipPath, tempDir.toPath())
conv.toVirtualFile(zipPath)

View File

@ -1,5 +1,10 @@
package sbt.util
import java.nio.charset.StandardCharsets
import java.nio.file.{ Files, Path, Paths }
import java.util.Optional
import java.util.concurrent.{ CyclicBarrier, ExecutorService, Executors, TimeUnit }
import sbt.internal.util.CacheEventLog
import sbt.internal.util.StringVirtualFile1
import sbt.io.IO
@ -7,18 +12,15 @@ import sbt.io.syntax.*
import verify.BasicTestSuite
import xsbti.{
CompileFailed,
FileConverter,
HashedVirtualFileRef,
Problem,
Position,
Severity,
VirtualFile,
FileConverter,
VirtualFileRef
VirtualFileRef,
}
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.Files
import java.util.Optional
import ActionCache.InternalActionResult
object ActionCacheTest extends BasicTestSuite:
@ -259,6 +261,36 @@ object ActionCacheTest extends BasicTestSuite:
assert(v2 == 42)
assert(called == 2)
test("packageDirectory is safe when many threads package the same directory concurrently"):
IO.withTemporaryDirectory: tmp =>
val root = tmp.toPath
val classesDir = root.resolve("classes")
Files.createDirectories(classesDir)
Files.writeString(classesDir.resolve("A.class"), "compiled")
val classesPathStr = classesDir.toString
val dirRef = VirtualFileRef.of(classesPathStr)
val conv = new FileConverter:
override def toPath(ref: VirtualFileRef): Path = Paths.get(ref.id)
override def toVirtualFile(path: Path): VirtualFile =
val content =
if Files.isRegularFile(path) then
new String(Files.readAllBytes(path), StandardCharsets.UTF_8)
else ""
StringVirtualFile1(path.toString, content)
val threadCount = 64
val barrier = new CyclicBarrier(threadCount)
val pool: ExecutorService = Executors.newFixedThreadPool(threadCount)
try
val tasks =
for _ <- 1 to threadCount yield pool.submit: () =>
barrier.await(30, TimeUnit.SECONDS)
ActionCache.packageDirectory(dirRef, conv, root)
tasks.foreach(_.get(60, TimeUnit.SECONDS))
val zipPath = Paths.get(classesPathStr + ActionCache.dirZipExt)
assert(Files.isRegularFile(zipPath))
assert(Files.size(zipPath) > 0L)
finally pool.shutdown()
test("Changing cacheVersion invalidates the cache"):
withDiskCache(testCacheVersionInvalidation)