Merge branch 'develop' into patch-1

This commit is contained in:
Conny Brunnkvist 2022-07-14 16:01:45 +07:00 committed by GitHub
commit 10bfc4a5cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
213 changed files with 2700 additions and 1096 deletions

4
.gitattributes vendored
View File

@ -1,3 +1,7 @@
sbt text eol=lf
*.sh text eol=lf
launcher-package/src/windows/sbt text eol=lf
# Exclude contraband generated files from diff (by default - you can see it if you want)
**/contraband-scala/**/* -diff merge=ours
**/contraband-scala/**/* linguist-generated=true

View File

@ -7,4 +7,4 @@ assignees: ''
---
Please use https://discuss.lightbend.com/c/tooling including a specific user story instead of posting them to the issue tracker.
Please use https://github.com/sbt/sbt/discussions including a specific user story instead of posting them to the issue tracker.

View File

@ -10,38 +10,48 @@ jobs:
matrix:
include:
- os: ubuntu-latest
java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz"
java: 17
distribution: temurin
jobtype: 1
- os: ubuntu-latest
java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz"
java: 17
distribution: temurin
jobtype: 2
- os: ubuntu-latest
java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz"
java: 17
distribution: temurin
jobtype: 3
- os: ubuntu-latest
java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz"
java: 17
distribution: temurin
jobtype: 4
- os: ubuntu-latest
java: "17-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz"
java: 17
distribution: temurin
jobtype: 5
- os: ubuntu-latest
java: "adopt@1.8"
java: 8
distribution: adopt
jobtype: 6
- os: ubuntu-latest
java: "adopt@1.8"
java: 8
distribution: adopt
jobtype: 7
- os: macos-latest
java: "adopt@1.8"
java: 8
distribution: adopt
jobtype: 8
- os: windows-latest
java: "adopt@1.8"
java: 8
distribution: adopt
jobtype: 9
runs-on: ${{ matrix.os }}
env:
JAVA_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8
JVM_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8
SCALA_212: 2.12.15
SCALA_213: 2.13.6
SCALA_212: 2.12.16
SCALA_213: 2.13.8
SCALA_3: 3.1.0
UTIL_TESTS: "utilCache/test utilControl/test utilInterface/test utilLogging/test utilPosition/test utilRelation/test utilScripted/test utilTracking/test"
SBT_LOCAL: false
TEST_SBT_VER: 1.5.0
@ -50,119 +60,132 @@ jobs:
SPARK_LOCAL_IP: "127.0.0.1"
steps:
- name: Checkout sbt/sbt
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Checkout sbt/io
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/io
ref: develop
path: io
- name: Checkout sbt/librarymanagement
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/librarymanagement
ref: develop
path: librarymanagement
- name: Checkout sbt/zinc
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/zinc
ref: develop
path: zinc
- name: Setup
uses: olafurpg/setup-scala@v13
- name: Setup JDK
uses: actions/setup-java@v3
with:
distribution: "${{ matrix.distribution }}"
java-version: "${{ matrix.java }}"
- name: Set up Python 3.7
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.7
- name: Coursier cache
uses: coursier/cache-action@v6
- name: Cache sbt
uses: actions/cache@v2.1.6
uses: actions/cache@v3
with:
path: ~/.sbt
key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}
- name: Build and test
- name: Build and test (1)
if: ${{ matrix.jobtype == 1 }}
shell: bash
run: |
# ./sbt -v --client mimaReportBinaryIssues
./sbt -v --client javafmtCheck
./sbt -v --client "Test/javafmtCheck"
./sbt -v --client scalafmtCheckAll
./sbt -v --client scalafmtSbtCheck
./sbt -v --client serverTestProj/scalafmtCheckAll
./sbt -v --client headerCheck
./sbt -v --client "Test/headerCheck"
./sbt -v --client whitesourceOnPush
./sbt -v --client "Test/compile"
./sbt -v --client publishLocal
./sbt -v --client test
./sbt -v --client "serverTestProj/test"
./sbt -v --client doc
./sbt -v --client "all $UTIL_TESTS"
./sbt -v --client ++$SCALA_213
./sbt -v --client "all $UTIL_TESTS"
- name: Build and test (2)
if: ${{ matrix.jobtype == 2 }}
shell: bash
run: |
./sbt -v "scripted actions/* apiinfo/* compiler-project/* ivy-deps-management/* reporter/* tests/* watch/* classloader-cache/* package/*"
- name: Build and test (3)
if: ${{ matrix.jobtype == 3 }}
shell: bash
run: |
./sbt -v "dependencyTreeProj/publishLocal; scripted dependency-graph/* dependency-management/* plugins/* project-load/* java/* run/* nio/*"
- name: Build and test (4)
if: ${{ matrix.jobtype == 4 }}
shell: bash
run: |
./sbt -v "repoOverrideTest:scripted dependency-management/*; scripted source-dependencies/* project/*"
- name: Build and test (5)
if: ${{ matrix.jobtype == 5 }}
shell: bash
run: |
./sbt -v "++$SCALA_213!; test; ++$SCALA_3!; all utilControl/test utilRelation/test utilPosition/test"
- name: Build and test (6)
if: ${{ matrix.jobtype == 6 }}
shell: bash
run: |
# build from fresh IO, LM, and Zinc
BUILD_VERSION="1.5.0-SNAPSHOT"
cd io
sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal
cd ../
sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal"
rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true
sbt -v -Dsbt.version=$BUILD_VERSION "++$SCALA_213; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*"
- name: Build and test (7)
if: ${{ matrix.jobtype == 7 }}
shell: bash
run: |
# test launcher script
echo build using JDK 8 test using JDK 8 and JDK 11
cd launcher-package
sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest && ./test.sh
$HOME/bin/jabba install $JDK11 && exec $HOME/bin/jabba which --home $JDK11
java -Xmx32m -version
./test.sh
- name: Build and test (8)
if: ${{ matrix.jobtype == 8 }}
shell: bash
run: |
# test launcher script
echo build using JDK 8, test using JDK 8, on macOS
cd launcher-package
bin/coursier resolve
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest && ./test.sh
- name: Build and test (9)
if: ${{ matrix.jobtype == 9 }}
shell: bash
run: |
# test launcher script
echo build using JDK 8, test using JDK 8, on Windows
cd launcher-package
bin/coursier.bat resolve
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest
./test.bat
test3/test3.bat
- name: Cleanup
shell: bash
run: |
rm -rf "$HOME/.sbt/scripted/" || true
case ${{ matrix.jobtype }} in
1)
./sbt -v --client mimaReportBinaryIssues
./sbt -v --client javafmtCheck
./sbt -v --client "Test/javafmtCheck"
./sbt -v --client scalafmtCheckAll
./sbt -v --client scalafmtSbtCheck
./sbt -v --client serverTestProj/scalafmtCheckAll
./sbt -v --client headerCheck
./sbt -v --client "Test/headerCheck"
./sbt -v --client whitesourceOnPush
./sbt -v --client "Test/compile"
./sbt -v --client publishLocal
./sbt -v --client test
./sbt -v --client "serverTestProj/test"
./sbt -v --client doc
./sbt -v --client "all $UTIL_TESTS"
./sbt -v --client ++$SCALA_213
./sbt -v --client "all $UTIL_TESTS"
;;
2)
./sbt -v "scripted actions/* apiinfo/* compiler-project/* ivy-deps-management/* reporter/* tests/* watch/* classloader-cache/* package/*"
;;
3)
./sbt -v "dependencyTreeProj/publishLocal; scripted dependency-graph/* dependency-management/* plugins/* project-load/* java/* run/* nio/*"
;;
4)
./sbt -v "repoOverrideTest:scripted dependency-management/*; scripted source-dependencies/* project/*"
;;
5)
./sbt -v "++$SCALA_213!; test;"
;;
6)
# build from fresh IO, LM, and Zinc
BUILD_VERSION="1.5.0-SNAPSHOT"
cd io
sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal
cd ../
sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal"
rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true
sbt -v -Dsbt.version=$BUILD_VERSION "++$SCALA_213; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*"
;;
7)
# test launcher script
echo build using JDK 8 test using JDK 8 and JDK 11
cd launcher-package
sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest && ./test.sh
$HOME/bin/jabba install $JDK11 && exec $HOME/bin/jabba which --home $JDK11
java -Xmx32m -version
./test.sh
;;
8)
# test launcher script
echo build using JDK 8, test using JDK 8, on macOS
cd launcher-package
bin/coursier resolve
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest && ./test.sh
;;
9)
# test launcher script
echo build using JDK 8, test using JDK 8, on Windows
cd launcher-package
bin/coursier.bat resolve
sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test
cd citest
./test.bat
test3/test3.bat
;;
*)
echo unknown jobtype
exit 1
esac
rm -rf "$HOME/.sbt/scripted/" || true
rm -rf "$HOME/.ivy2/local" || true
rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true

View File

@ -16,21 +16,21 @@ jobs:
JAVA_OPTS: -Xms800M -Xmx800M -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8
steps:
- name: Checkout sbt/sbt
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Checkout sbt/io
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/io
ref: develop
path: io
- name: Checkout sbt/librarymanagement
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/librarymanagement
ref: develop
path: librarymanagement
- name: Checkout sbt/zinc
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: sbt/zinc
ref: develop

1
.gitignore vendored
View File

@ -11,5 +11,6 @@ npm-debug.log
.bloop
.metals
.bsp/
.vscode/
metals.sbt
launcher-package/citest/freshly-baked

View File

@ -21,3 +21,8 @@ align.openParenDefnSite = false
danglingParentheses = true
trailingCommas = preserve
# TODO update scalafmt and enable Scala 3
project.excludeFilters = [
"internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala"
]

View File

@ -151,14 +151,14 @@ suite with `sbt testOnly`
#### Integration tests
Scripted integration tests reside in `sbt/src/sbt-test` and are
Scripted integration tests reside in `sbt-app/src/sbt-test` and are
written using the same testing infrastructure sbt plugin authors can
use to test their own plugins with sbt. You can read more about this
style of tests [here](https://www.scala-sbt.org/1.0/docs/Testing-sbt-plugins).
You can run the integration tests with the `sbt scripted` sbt
command. To run a single test, such as the test in
`sbt/src/sbt-test/project/global-plugin`, simply run:
`sbt-app/src/sbt-test/project/global-plugin`, simply run:
sbt "scripted project/global-plugin"

View File

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.com/sbt/sbt.svg?branch=develop)](https://travis-ci.com/github/sbt/sbt)
[![CI](https://github.com/sbt/sbt/actions/workflows/ci.yml/badge.svg)](https://github.com/sbt/sbt/actions/workflows/ci.yml)
[![Latest version](https://img.shields.io/github/tag/sbt/sbt.svg)](https://index.scala-lang.org/sbt/sbt)
[![Gitter Chat](https://badges.gitter.im/sbt/sbt.svg)](https://gitter.im/sbt/sbt)

View File

@ -10,7 +10,7 @@ import scala.util.Try
// ThisBuild settings take lower precedence,
// but can be shared across the multi projects.
ThisBuild / version := {
val v = "1.6.0-SNAPSHOT"
val v = "1.7.0-SNAPSHOT"
nightlyVersion.getOrElse(v)
}
ThisBuild / version2_13 := "2.0.0-SNAPSHOT"
@ -46,7 +46,7 @@ ThisBuild / resolvers += Resolver.mavenLocal
Global / semanticdbEnabled := !(Global / insideCI).value
// Change main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala too, if you change this.
Global / semanticdbVersion := "4.4.28"
Global / semanticdbVersion := "4.5.9"
val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys")
Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty)
Global / excludeLint += componentID
@ -68,10 +68,6 @@ def commonBaseSettings: Seq[Setting[_]] = Def.settings(
componentID := None,
resolvers += Resolver.typesafeIvyRepo("releases").withName("typesafe-sbt-build-ivy-releases"),
resolvers += Resolver.sonatypeRepo("snapshots"),
resolvers += Resolver.url(
"bintray-scala-hedgehog",
url("https://dl.bintray.com/hedgehogqa/scala-hedgehog")
)(Resolver.ivyStylePatterns),
testFrameworks += TestFramework("hedgehog.sbt.Framework"),
testFrameworks += TestFramework("verify.runner.Framework"),
Global / concurrentRestrictions += Util.testExclusiveRestriction,
@ -106,8 +102,15 @@ def commonBaseSettings: Seq[Setting[_]] = Def.settings(
run / fork := true,
)
def commonSettings: Seq[Setting[_]] =
commonBaseSettings :+
addCompilerPlugin(kindProjector)
commonBaseSettings :+ {
libraryDependencies ++= {
if (scalaBinaryVersion.value == "3") {
Nil
} else {
Seq(compilerPlugin(kindProjector))
}
}
}
def utilCommonSettings: Seq[Setting[_]] =
baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil))
@ -467,7 +470,7 @@ lazy val utilScripted = (project in file("internal") / "util-scripted")
.settings(
utilCommonSettings,
name := "Util Scripted",
libraryDependencies += scalaParsers,
libraryDependencies += scalaParsers.value,
utilMimaSettings,
)
.configure(addSbtIO)
@ -481,7 +484,7 @@ lazy val testingProj = (project in file("testing"))
baseSettings,
name := "Testing",
libraryDependencies ++= Seq(
scalaXml,
scalaXml.value,
testInterface,
launcherInterface,
sjsonNewScalaJson.value
@ -807,7 +810,13 @@ lazy val coreMacrosProj = (project in file("core-macros"))
.settings(
baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)),
name := "Core Macros",
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value,
libraryDependencies += {
if (scalaBinaryVersion.value == "3") {
"org.scala-lang" % "scala-compiler" % scala213
} else {
"org.scala-lang" % "scala-compiler" % scalaVersion.value
}
},
SettingKey[Boolean]("exportPipelining") := false,
mimaSettings,
)
@ -917,7 +926,7 @@ lazy val mainProj = (project in file("main"))
}
},
libraryDependencies ++=
(Seq(scalaXml, launcherInterface, caffeine, lmCoursierShaded) ++ log4jModules),
(Seq(scalaXml.value, launcherInterface, caffeine, lmCoursierShaded) ++ log4jModules),
libraryDependencies ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List()
case _ => List(scalaPar)
@ -1048,6 +1057,7 @@ lazy val mainProj = (project in file("main"))
exclude[DirectMissingMethodProblem]("sbt.Defaults.earlyArtifactPathSetting"),
exclude[MissingClassProblem]("sbt.internal.server.BuildServerReporter$"),
exclude[IncompatibleTemplateDefProblem]("sbt.internal.server.BuildServerReporter"),
exclude[MissingClassProblem]("sbt.internal.CustomHttp*"),
)
)
.configure(
@ -1108,7 +1118,7 @@ lazy val serverTestProj = (project in file("server-test"))
val rawClasspath =
(Compile / fullClasspathAsJars).value.map(_.data).mkString(java.io.File.pathSeparator)
val cp =
if (scala.util.Properties.isWin) rawClasspath.replaceAllLiterally("\\", "\\\\")
if (scala.util.Properties.isWin) rawClasspath.replace("\\", "\\\\")
else rawClasspath
val content = {
s"""|

View File

@ -30,7 +30,7 @@ final case class HCons[H, T <: HList](head: H, tail: T) extends HList {
type Wrap[M[_]] = M[H] :+: T#Wrap[M]
def :+:[G](g: G): G :+: H :+: T = HCons(g, this)
override def toString = head + " :+: " + tail.toString
override def toString = head.toString + " :+: " + tail.toString
}
object HList {

View File

@ -43,7 +43,7 @@ private final class Settings0[ScopeType](
(data get scope).flatMap(_ get key)
def set[T](scope: ScopeType, key: AttributeKey[T], value: T): Settings[ScopeType] = {
val map = data getOrElse (scope, AttributeMap.empty)
val map = data.getOrElse(scope, AttributeMap.empty)
val newData = data.updated(scope, map.put(key, value))
new Settings0(newData, delegates)
}
@ -476,7 +476,7 @@ trait Init[ScopeType] {
if (posDefined.size == settings.size) "defined at:"
else
"some of the defining occurrences:"
header + (posDefined.distinct mkString ("\n\t", "\n\t", "\n"))
header + (posDefined.distinct.mkString("\n\t", "\n\t", "\n"))
} else ""
}
@ -711,10 +711,10 @@ trait Init[ScopeType] {
def mapReferenced(g: MapScoped): Setting[T] = make(key, init mapReferenced g, pos)
def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Setting[T]] =
(init validateReferenced g).right.map(newI => make(key, newI, pos))
(init validateReferenced g).map(newI => make(key, newI, pos))
private[sbt] def validateKeyReferenced(g: ValidateKeyRef): Either[Seq[Undefined], Setting[T]] =
(init validateKeyReferenced g).right.map(newI => make(key, newI, pos))
(init validateKeyReferenced g).map(newI => make(key, newI, pos))
def mapKey(g: MapScoped): Setting[T] = make(g(key), init, pos)
def mapInit(f: (ScopedKey[T], T) => T): Setting[T] = make(key, init(t => f(key, t)), pos)
@ -879,9 +879,8 @@ trait Init[ScopeType] {
def evaluate(ss: Settings[ScopeType]): T = f(in evaluate ss) evaluate ss
def mapReferenced(g: MapScoped) = new Bind[S, T](s => f(s) mapReferenced g, in mapReferenced g)
def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).right.map {
validIn =>
new Bind[S, T](s => handleUndefined(f(s) validateKeyReferenced g), validIn)
def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).map { validIn =>
new Bind[S, T](s => handleUndefined(f(s) validateKeyReferenced g), validIn)
}
def mapConstant(g: MapConstant) = new Bind[S, T](s => f(s) mapConstant g, in mapConstant g)
@ -898,7 +897,7 @@ trait Init[ScopeType] {
def validateKeyReferenced(g: ValidateKeyRef) = a match {
case None => Right(this)
case Some(i) => Right(new Optional(i.validateKeyReferenced(g).right.toOption, f))
case Some(i) => Right(new Optional(i.validateKeyReferenced(g).toOption, f))
}
def mapConstant(g: MapConstant): Initialize[T] = new Optional(a map mapConstantT(g).fn, f)

View File

@ -43,7 +43,7 @@ object Util {
def camelToHyphen(s: String): String =
Camel.replaceAllIn(s, m => m.group(1) + "-" + m.group(2).toLowerCase(Locale.ENGLISH))
def quoteIfKeyword(s: String): String = if (ScalaKeywords.values(s)) '`' + s + '`' else s
def quoteIfKeyword(s: String): String = if (ScalaKeywords.values(s)) s"`${s}`" else s
def ignoreResult[T](f: => T): Unit = macro Macro.ignore
@ -54,7 +54,7 @@ object Util {
System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")
lazy val isCygwin: Boolean = {
val os = Option(System.getenv("OSTYPE"))
val os = sys.env.get("OSTYPE")
os match {
case Some(x) => x.toLowerCase(Locale.ENGLISH).contains("cygwin")
case _ => false
@ -64,7 +64,7 @@ object Util {
lazy val isNonCygwinWindows: Boolean = isWindows && !isCygwin
lazy val isCygwinWindows: Boolean = isWindows && isCygwin
lazy val isEmacs: Boolean = Option(System.getenv("INSIDE_EMACS")).isDefined
lazy val isEmacs: Boolean = sys.env.contains("INSIDE_EMACS")
def nil[A]: List[A] = List.empty[A]
def nilSeq[A]: Seq[A] = Seq.empty[A]

View File

@ -7,6 +7,7 @@
package sbt.internal.util
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
abstract class UnitSpec extends FlatSpec with Matchers
abstract class UnitSpec extends AnyFlatSpec with Matchers

View File

@ -178,13 +178,7 @@ abstract class JLine extends LineReader {
protected[this] lazy val in: InputStream = Terminal.wrappedSystemIn
override def readLine(prompt: String, mask: Option[Char] = None): Option[String] =
try {
unsynchronizedReadLine(prompt, mask)
} catch {
case _: InterruptedException =>
// println("readLine: InterruptedException")
Option("")
}
unsynchronizedReadLine(prompt, mask)
private[this] def unsynchronizedReadLine(prompt: String, mask: Option[Char]): Option[String] =
readLineWithHistory(prompt, mask) map { x =>

View File

@ -909,7 +909,7 @@ private final class StringLiteral(str: String, start: Int) extends ValidParser[S
if (str.charAt(start) == c) stringLiteral(str, start + 1) else new Invalid(resultEmpty)
def completions(level: Int) = Completions.single(Completion.suggestion(str.substring(start)))
override def toString = '"' + str + '"'
override def toString = "\"" + str + "\""
}
private final class CharacterClass(f: Char => Boolean, label: String) extends ValidParser[Char] {

View File

@ -202,7 +202,7 @@ trait Parsers {
* Parses a potentially quoted String value. The value may be verbatim quoted ([[StringVerbatim]]),
* quoted with interpreted escapes ([[StringEscapable]]), or unquoted ([[NotQuoted]]).
*/
lazy val StringBasic = StringVerbatim | StringEscapable | NotQuoted
lazy val StringBasic = StringVerbatim | StringEscapable | NotQuoted | NotQuotedThenQuoted
/**
* Parses a verbatim quoted String value, discarding the quotes in the result. This kind of quoted text starts with triple quotes `"""`
@ -238,12 +238,12 @@ trait Parsers {
val notDelim = charClass(c => c != open && c != close).*.string
def impl(): Parser[String] = {
(open ~ (notDelim ~ close).?).flatMap {
case (l, Some((content, r))) => Parser.success(l + content + r)
case (l, Some((content, r))) => Parser.success(s"$l$content$r")
case (l, None) =>
((notDelim ~ impl()).map {
case (leftPrefix, nestedBraces) => leftPrefix + nestedBraces
}.+ ~ notDelim ~ close).map {
case ((nested, suffix), r) => l + nested.mkString + suffix + r
case ((nested, suffix), r) => s"$l${nested.mkString}$suffix$r"
}
}
}
@ -270,6 +270,11 @@ trait Parsers {
/** Parses an unquoted, non-empty String value that cannot start with a double quote and cannot contain whitespace.*/
lazy val NotQuoted = (NotDQuoteSpaceClass ~ OptNotSpace) map { case (c, s) => c.toString + s }
/** Parses a non-empty String value that cannot start with a double quote, but includes double quotes.*/
lazy val NotQuotedThenQuoted = (NotQuoted ~ StringEscapable) map {
case (s1, s2) => s"""$s1\"$s2\""""
}
/**
* Applies `rep` zero or more times, separated by `sep`.
* The result is the (possibly empty) sequence of results from the multiple `rep` applications. The `sep` results are discarded.

View File

@ -119,6 +119,8 @@ object ParserTest extends Properties("Completing Parser") {
property("repeatDep requires at least one token") = !matches(repeat, "")
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
property("parses string that doesn't start with quotes, but includes quotes within it") =
matches(StringBasic, "-Dsilicon:z3ConfigArgs=\"model=true model_validate=true\"")
}
object ParserExample {
val ws = charClass(_.isWhitespace, "whitespace").+

View File

@ -7,6 +7,7 @@
package sbt.internal.util
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
abstract class UnitSpec extends FlatSpec with Matchers
abstract class UnitSpec extends AnyFlatSpec with Matchers

View File

@ -7,9 +7,9 @@
package sbt.internal.util.complete
import org.scalatest.FlatSpec
import org.scalatest.flatspec.AnyFlatSpec
class SizeParserSpec extends FlatSpec {
class SizeParserSpec extends AnyFlatSpec {
"SizeParser" should "handle raw bytes" in {
assert(Parser.parse(str = "123456", SizeParser.value) == Right(123456L))
}

View File

@ -0,0 +1,23 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package xsbti;
import java.util.Optional;
/**
* A DiagnosticCode is a unique identifier that the compiler can associate with a diagnostic. This
* is useful for tools to be able to quickly identify what diagnostic is being reported without
* having to rely on parsing the actual diagnostic message, which might not be stable.
*/
public interface DiagnosticCode {
/** The unique code. This is typically in the format of E000 */
String code();
/** Possible explanation to explain the meaning of the code */
Optional<String> explanation();
}

View File

@ -0,0 +1,20 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package xsbti;
/**
* Related information for a given diagnostic. At times this can be another place in your code
* contributing to the diagnostic or just relevant code relating to the diagnostic.
*/
public interface DiagnosticRelatedInformation {
/** Position of the related information */
Position position();
/** Message indicating why this related information is attached to the diagnostic. */
String message();
}

View File

@ -7,6 +7,8 @@
package xsbti;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public interface Problem {
@ -26,4 +28,24 @@ public interface Problem {
default Optional<String> rendered() {
return Optional.empty();
}
/**
* The unique code attached to the diagnostic being reported.
*
* <p>NOTE: To avoid breaking compatibility we provide a default to account for older Scala
* versions that do not have codes.
*/
default Optional<DiagnosticCode> diagnosticCode() {
return Optional.empty();
}
/**
* The possible releated information for the diagnostic being reported.
*
* <p>NOTE: To avoid breaking compatibility we provide a default to account for older Scala
* versions that do not have the concept of "related information".
*/
default List<DiagnosticRelatedInformation> diagnosticRelatedInforamation() {
return Collections.emptyList();
}
}

View File

@ -83,7 +83,7 @@ object GlobalLogging {
): GlobalLogging = {
val loggerName = generateName
val log = LoggerContext.globalContext.logger(loggerName, None, None)
val appender = ConsoleAppender(ConsoleAppender.generateName, console)
val appender = ConsoleAppender(ConsoleAppender.generateName(), console)
LoggerContext.globalContext.addAppender(loggerName, appender -> Level.Info)
GlobalLogging(log, console, appender, GlobalLogBacking(newBackingFile), newAppender)
}

View File

@ -67,15 +67,15 @@ object MainAppender {
)
def defaultScreen(console: ConsoleOut): Appender =
ConsoleAppender(ConsoleAppender.generateName, console)
ConsoleAppender(ConsoleAppender.generateName(), console)
def defaultScreen(
console: ConsoleOut,
suppressedMessage: SuppressedTraceContext => Option[String]
): Appender = {
ConsoleAppender(
ConsoleAppender.generateName,
Terminal.get,
ConsoleAppender.generateName(),
console,
suppressedMessage = suppressedMessage
)
}
@ -99,7 +99,7 @@ object MainAppender {
def defaultBacked(loggerName: String, useFormat: Boolean): PrintWriter => Appender =
to => {
ConsoleAppender(
ConsoleAppender.generateName,
ConsoleAppender.generateName(),
ConsoleOut.printWriterOut(to),
useFormat = useFormat
)

View File

@ -50,13 +50,6 @@ class ManagedLogger(
}
}
@deprecated("Use macro-powered StringTypeTag.fast instead", "1.4.0")
def registerStringCodec[A](
s: ShowLines[A],
tt: scala.reflect.runtime.universe.TypeTag[A]
): Unit = {
LogExchange.registerStringCodec[A](s, tt)
}
def registerStringCodec[A: ShowLines: StringTypeTag]: Unit = {
LogExchange.registerStringCodec[A]
}

View File

@ -99,8 +99,8 @@ private[sbt] final class ProgressState(
addBytes(terminal, bytes)
val toWrite = new ArrayBuffer[Byte]
terminal.prompt match {
case a: Prompt.AskUser if a.render.nonEmpty && canClearPrompt => toWrite ++= cleanPrompt
case _ =>
case a: Prompt.AskUser if a.render().nonEmpty && canClearPrompt => toWrite ++= cleanPrompt
case _ =>
}
val endsWithNewLine = bytes.endsWith(lineSeparatorBytes)
if (endsWithNewLine || bytes.containsSlice(lineSeparatorBytes)) {

View File

@ -308,7 +308,7 @@ object Terminal {
}
private[sbt] lazy val isAnsiSupported: Boolean = logFormatEnabled.getOrElse(useColorDefault)
private[this] val isDumb = "dumb" == System.getenv("TERM")
private[this] val isDumb = Some("dumb") == sys.env.get("TERM")
private[this] def isDumbTerminal = isDumb || System.getProperty("jline.terminal", "") == "none"
private[this] val hasConsole = Option(java.lang.System.console).isDefined
private[this] def useColorDefault: Boolean = {
@ -736,22 +736,20 @@ object Terminal {
val supershell: Boolean
)
private[sbt] val TERMINAL_PROPS = "SBT_TERMINAL_PROPS"
private val props = System.getenv(TERMINAL_PROPS) match {
case null => None
case p =>
p.split(",") match {
case Array(width, height, ansi, color, supershell) =>
Try(
new Props(
width.toInt,
height.toInt,
ansi.toBoolean,
color.toBoolean,
supershell.toBoolean
)
).toOption
case _ => None
}
private val props = sys.env.get(TERMINAL_PROPS) flatMap { p =>
p.split(",") match {
case Array(width, height, ansi, color, supershell) =>
Try(
new Props(
width.toInt,
height.toInt,
ansi.toBoolean,
color.toBoolean,
supershell.toBoolean
)
).toOption
case _ => None
}
}
private[sbt] def startedByRemoteClient = props.isDefined
@ -905,7 +903,7 @@ object Terminal {
new AtomicReference[((Int, Int), Deadline)](((1, 1), Deadline.now - 1.day))
private[this] def setSize() = size.set((Try(getSizeImpl).getOrElse((1, 1)), Deadline.now))
private[this] def getSize = size.get match {
case (s, d) if (d + sizeRefreshPeriod).isOverdue =>
case (s, d) if (d + sizeRefreshPeriod).isOverdue() =>
setSize()
size.get._1
case (s, _) => s

View File

@ -56,7 +56,7 @@ private[util] class WindowsInputStream(term: org.jline.terminal.Terminal, in: In
private val SHIFT_PRESSED = 0x0010;
private def getCapability(cap: Capability): String = term.getStringCapability(cap) match {
case null => null
case c => c.replaceAllLiterally("\\E", "\u001B")
case c => c.replace("\\E", "\u001B")
}
/*
* This function is a hybrid of jline 2 WindowsTerminal.readConsoleInput

View File

@ -7,15 +7,14 @@
package sbt.util
import java.util.concurrent.ConcurrentHashMap
import org.apache.logging.log4j.{ LogManager => XLogManager, Level => XLevel }
import org.apache.logging.log4j.core.{ Appender => XAppender, LoggerContext => XLoggerContext }
import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig }
import org.apache.logging.log4j.core.config.LoggerConfig
import org.apache.logging.log4j.core.layout.PatternLayout
import org.apache.logging.log4j.core.{ LoggerContext => XLoggerContext }
import org.apache.logging.log4j.{ LogManager => XLogManager }
import sbt.internal.util._
import java.util.concurrent.ConcurrentHashMap
import scala.collection.concurrent
import sjsonnew.JsonFormat
import org.apache.logging.log4j.core.appender.AsyncAppender
// http://logging.apache.org/log4j/2.x/manual/customconfig.html
// https://logging.apache.org/log4j/2.x/log4j-core/apidocs/index.html
@ -29,54 +28,18 @@ sealed abstract class LogExchange {
Util.ignoreResult(configs.putIfAbsent(name, config))
private[util] def removeConfig(name: String): Option[LoggerConfig] = Option(configs.remove(name))
@deprecated("Use LoggerContext to create loggers", "1.4.0")
def logger(name: String): ManagedLogger = logger(name, None, None)
@deprecated("Use LoggerContext to create loggers", "1.4.0")
def logger(name: String, channelName: Option[String], execId: Option[String]): ManagedLogger =
LoggerContext.globalContext.logger(name, channelName, execId)
@deprecated("Use LoggerContext to unbind appenders", "1.4.0")
def unbindLoggerAppenders(loggerName: String): Unit = {
LoggerContext.globalContext.clearAppenders(loggerName)
}
@deprecated("Use LoggerContext to bind appenders", "1.4.0")
def bindLoggerAppenders(
loggerName: String,
appenders: List[(XAppender, Level.Value)]
): Unit = {
appenders.foreach {
case (a, l) =>
LoggerContext.globalContext
.addAppender(loggerName, new ConsoleAppenderFromLog4J(loggerName, a) -> l)
}
}
@deprecated("Use LoggerContext to bind appenders", "1.4.0")
def bindLoggerAppenders(
loggerName: String,
appenders: Seq[(Appender, Level.Value)]
): Unit = bindLoggerAppenders(loggerName, appenders.map { case (a, l) => a.toLog4J -> l }.toList)
@deprecated("unused", "1.4.0")
def loggerConfig(loggerName: String): LoggerConfig = configs.get(loggerName)
@deprecated("unused", "1.4.0")
lazy val asyncStdout = buildAsyncStdout
@deprecated("unused", "1.4.0")
private[sbt] def buildAsyncStdout: AsyncAppender = {
val ctx = XLogManager.getContext(false) match { case x: XLoggerContext => x }
val config = ctx.getConfiguration
val appender = ConsoleAppender("Stdout").toLog4J
// CustomConsoleAppender.createAppender("Stdout", layout, null, null)
appender.start
config.addAppender(appender)
val asyncAppender: AsyncAppender = AsyncAppender
.newBuilder()
.setName("AsyncStdout")
.setAppenderRefs(Array(AppenderRef.createAppenderRef("Stdout", XLevel.DEBUG, null)))
.setBlocking(false)
.setConfiguration(config)
.build
asyncAppender.start
config.addAppender(asyncAppender)
asyncAppender
): Unit = {
appenders.map(LoggerContext.globalContext.addAppender(loggerName, _))
()
}
// Construct these StringTypeTags manually, because they're used at the very startup of sbt
@ -87,9 +50,9 @@ sealed abstract class LogExchange {
lazy val stringTypeTagSuccessEvent = StringTypeTag[SuccessEvent]("sbt.internal.util.SuccessEvent")
private[sbt] def initStringCodecs(): Unit = {
import sbt.internal.util.codec.SuccessEventShowLines._
import sbt.internal.util.codec.ThrowableShowLines._
import sbt.internal.util.codec.TraceEventShowLines._
import sbt.internal.util.codec.SuccessEventShowLines._
registerStringCodecByStringTypeTag(stringTypeTagThrowable)
registerStringCodecByStringTypeTag(stringTypeTagTraceEvent)
@ -111,15 +74,6 @@ sealed abstract class LogExchange {
lo
}
@deprecated("It is now necessary to provide a json format instance", "1.4.0")
def jsonCodec[A](tag: String): Option[JsonFormat[A]] = None
@deprecated("Always returns false", "1.4.0")
def hasJsonCodec(tag: String): Boolean = false
@deprecated("This is a no-op", "1.4.0")
def getOrElseUpdateJsonCodec[A](tag: String, v: JsonFormat[A]): JsonFormat[A] = v
@deprecated("The log manager no longer caches jsonCodecs", "1.4.0")
def jsonCodecs(): concurrent.Map[String, JsonFormat[_]] = concurrent.TrieMap.empty
def stringCodec[A](tag: String): Option[ShowLines[A]] =
stringCodecs.get(tag) map { _.asInstanceOf[ShowLines[A]] }
def hasStringCodec(tag: String): Boolean =
@ -127,13 +81,6 @@ sealed abstract class LogExchange {
def getOrElseUpdateStringCodec[A](tag: String, v: ShowLines[A]): ShowLines[A] =
stringCodecs.getOrElseUpdate(tag, v).asInstanceOf[ShowLines[A]]
@deprecated("Prefer macro based registerStringCodec", "1.4.0")
def registerStringCodec[A](
st: ShowLines[A],
tt: scala.reflect.runtime.universe.TypeTag[A]
): Unit = {
registerStringCodecByStringTypeTag(StringTypeTag.apply[A](tt))(st)
}
private[sbt] def registerStringCodec[A: ShowLines: StringTypeTag]: Unit = {
registerStringCodecByStringTypeTag(implicitly[StringTypeTag[A]])
}
@ -144,8 +91,8 @@ sealed abstract class LogExchange {
}
private[sbt] def init(): XLoggerContext = {
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory
import org.apache.logging.log4j.core.config.Configurator
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory
val builder = ConfigurationBuilderFactory.newConfigurationBuilder
builder.setConfigurationName("sbt.util.logging")
val ctx = Configurator.initialize(builder.build())

View File

@ -7,15 +7,11 @@
package sbt.util
import sbt.internal.util._
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
import org.apache.logging.log4j.{ Level => XLevel }
import org.apache.logging.log4j.core.{ Appender => XAppender, LoggerContext => XLoggerContext }
import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig }
import sbt.internal.util._
import scala.collection.JavaConverters._
import org.apache.logging.log4j.core.config.AbstractConfiguration
import org.apache.logging.log4j.message.ObjectMessage
/**
* Provides a context for generating loggers during task evaluation. The logger context
@ -35,83 +31,8 @@ sealed trait LoggerContext extends AutoCloseable {
def remove(name: String): Unit
}
object LoggerContext {
private[this] val useLog4J = System.getProperty("sbt.log.uselog4j", "false") == "true"
private[this] lazy val global = new LoggerContext.LoggerContextImpl
private[this] lazy val globalLog4J = new LoggerContext.Log4JLoggerContext(LogExchange.context)
private[sbt] lazy val globalContext = if (useLog4J) globalLog4J else global
private[util] class Log4JLoggerContext(val xlc: XLoggerContext) extends LoggerContext {
private val config = xlc.getConfiguration match {
case a: AbstractConfiguration => a
case _ => throw new IllegalStateException("")
}
val loggers = new java.util.Vector[String]
private[this] val closed = new AtomicBoolean(false)
override def logger(
name: String,
channelName: Option[String],
execId: Option[String]
): ManagedLogger = {
if (closed.get) {
throw new IllegalStateException("Tried to create logger for closed LoggerContext")
}
val loggerConfig = LoggerConfig.createLogger(
false,
XLevel.DEBUG,
name,
// disable the calculation of caller location as it is very expensive
// https://issues.apache.org/jira/browse/LOG4J2-153
"false",
Array[AppenderRef](),
null,
config,
null
)
config.addLogger(name, loggerConfig)
val logger = xlc.getLogger(name)
LogExchange.addConfig(name, loggerConfig)
loggers.add(name)
val xlogger = new MiniLogger {
def log(level: Level.Value, message: => String): Unit =
logger.log(
ConsoleAppender.toXLevel(level),
new ObjectMessage(StringEvent(level.toString, message, channelName, execId))
)
def log[T](level: Level.Value, message: ObjectEvent[T]): Unit =
logger.log(ConsoleAppender.toXLevel(level), new ObjectMessage(message))
}
new ManagedLogger(name, channelName, execId, xlogger, Some(Terminal.get), this)
}
override def clearAppenders(loggerName: String): Unit = {
val lc = config.getLoggerConfig(loggerName)
lc.getAppenders.asScala foreach {
case (name, a) =>
a.stop()
lc.removeAppender(name)
}
}
override def addAppender(
loggerName: String,
appender: (Appender, Level.Value)
): Unit = {
val lc = config.getLoggerConfig(loggerName)
appender match {
case (x: XAppender, lv) => lc.addAppender(x, ConsoleAppender.toXLevel(lv), null)
case (x, lv) => lc.addAppender(x.toLog4J, ConsoleAppender.toXLevel(lv), null)
}
}
override def appenders(loggerName: String): Seq[Appender] = {
val lc = config.getLoggerConfig(loggerName)
lc.getAppenders.asScala.collect { case (name, ca: ConsoleAppender) => ca }.toVector
}
override def remove(name: String): Unit = {
val lc = config.getLoggerConfig(name)
config.removeLogger(name)
}
def close(): Unit = if (closed.compareAndSet(false, true)) {
loggers.forEach(l => remove(l))
loggers.clear()
}
}
private[sbt] lazy val globalContext: LoggerContext = new LoggerContext.LoggerContextImpl
private[util] class LoggerContextImpl extends LoggerContext {
private class Log extends MiniLogger {
private val consoleAppenders: java.util.Vector[(Appender, Level.Value)] =
@ -186,6 +107,5 @@ object LoggerContext {
loggers.clear()
}
}
private[sbt] def apply(useLog4J: Boolean) =
if (useLog4J) new Log4JLoggerContext(LogExchange.context) else new LoggerContextImpl
private[sbt] def apply() = new LoggerContextImpl
}

View File

@ -96,7 +96,7 @@ object Escapes extends Properties("Escapes") {
)
}
assert(isEscapeTerminator(terminator))
def makeString: String = ESC + content + terminator
def makeString: String = s"$ESC$content$terminator"
override def toString =
if (content.isEmpty) s"ESC (${terminator.toInt})"

View File

@ -9,9 +9,10 @@ package sbt.util
import sbt.internal.util._
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class LogExchangeSpec extends FlatSpec with Matchers {
class LogExchangeSpec extends AnyFlatSpec with Matchers {
import LogExchange._
checkTypeTag("stringTypeTagThrowable", stringTypeTagThrowable, StringTypeTag.fast[Throwable])

View File

@ -7,16 +7,18 @@
package sbt.internal.util
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import sbt.util._
import java.io.{ File, PrintWriter }
import sbt.io.Using
import scala.annotation.nowarn
class ManagedLoggerSpec extends FlatSpec with Matchers {
val context = LoggerContext(useLog4J = true)
class ManagedLoggerSpec extends AnyFlatSpec with Matchers {
val context = LoggerContext()
@nowarn
val asyncStdout = new ConsoleAppenderFromLog4J("asyncStdout", LogExchange.asyncStdout)
//TODO create a new appender for testing purposes - 3/12/21
val asyncStdout = ConsoleAppender("asyncStdout")
def newLogger(name: String): ManagedLogger = context.logger(name, None, None)
"ManagedLogger" should "log to console" in {
val log = newLogger("foo")

View File

@ -7,9 +7,9 @@
package sbt.internal.util
import org.scalatest.FlatSpec
import org.scalatest.flatspec.AnyFlatSpec
class CleanStringSpec extends FlatSpec {
class CleanStringSpec extends AnyFlatSpec {
"EscHelpers" should "not modify normal strings" in {
val cleanString = s"1234"
assert(EscHelpers.stripColorsAndMoves(cleanString) == cleanString)

View File

@ -9,12 +9,13 @@ package sbt.internal.util
import java.io.{ File, PrintStream }
import org.scalatest.{ BeforeAndAfterAll, FlatSpec }
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.BeforeAndAfterAll
import sbt.internal.util.Terminal.SimpleTerminal
import scala.io.Source
class ProgressStateSpec extends FlatSpec with BeforeAndAfterAll {
class ProgressStateSpec extends AnyFlatSpec with BeforeAndAfterAll {
private lazy val fileIn = new File("/tmp/tmp.txt")
private lazy val fileOut = Source.fromFile("/tmp/tmp.txt")

View File

@ -9,10 +9,10 @@ package sbt.internal.util
import java.io.InputStream
import java.nio.charset.Charset
import org.scalatest.FlatSpec
import org.scalatest.flatspec.AnyFlatSpec
import java.util.concurrent.LinkedBlockingQueue
class UTF8DecoderSpec extends FlatSpec {
class UTF8DecoderSpec extends AnyFlatSpec {
val decoder = Charset.forName("UTF-8").newDecoder
"ascii characters" should "not be modified" in {
val inputStream = new InputStream {

View File

@ -0,0 +1,53 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal.util
import scala.language.experimental.macros
import scala.annotation.tailrec
import scala.reflect.macros.blackbox
import scala.reflect.internal.util.UndefinedPosition
abstract class SourcePositionImpl {
/** Creates a SourcePosition by using the enclosing position of the invocation of this method.
* @return SourcePosition
*/
def fromEnclosing(): SourcePosition = macro SourcePositionMacro.fromEnclosingImpl
}
final class SourcePositionMacro(val c: blackbox.Context) {
import c.universe.{ NoPosition => _, _ }
def fromEnclosingImpl(): Expr[SourcePosition] = {
val pos = c.enclosingPosition
if (!pos.isInstanceOf[UndefinedPosition] && pos.line >= 0 && pos.source != null) {
val f = pos.source.file
val name = constant[String](ownerSource(f.path, f.name))
val line = constant[Int](pos.line)
reify { LinePosition(name.splice, line.splice) }
} else
reify { NoPosition }
}
private[this] def ownerSource(path: String, name: String): String = {
@tailrec def inEmptyPackage(s: Symbol): Boolean =
s != NoSymbol && (
s.owner == c.mirror.EmptyPackage
|| s.owner == c.mirror.EmptyPackageClass
|| inEmptyPackage(s.owner)
)
c.internal.enclosingOwner match {
case ec if !ec.isStatic => name
case ec if inEmptyPackage(ec) => path
case ec => s"(${ec.fullName}) $name"
}
}
private[this] def constant[T: WeakTypeTag](t: T): Expr[T] = c.Expr[T](Literal(Constant(t)))
}

View File

@ -0,0 +1,34 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal.util
import scala.quoted.{ Expr, Quotes, quotes }
abstract class SourcePositionImpl {
/** Creates a SourcePosition by using the enclosing position of the invocation of this method.
*
* @return SourcePosition
*/
inline def fromEnclosing(): SourcePosition =
${ SourcePositionImpl.fromEnclosingImpl }
}
object SourcePositionImpl {
def fromEnclosingImpl(using Quotes): Expr[SourcePosition] = {
val x = quotes.reflect.Position.ofMacroExpansion
'{
LinePosition(
path = ${Expr(x.sourceFile.name)},
startLine = ${Expr(x.startLine + 1)}
)
}
}
}

View File

@ -7,8 +7,6 @@
package sbt.internal.util
import scala.language.experimental.macros
sealed trait SourcePosition
sealed trait FilePosition extends SourcePosition {
@ -28,47 +26,4 @@ final case class RangePosition(path: String, range: LineRange) extends FilePosit
def startLine = range.start
}
object SourcePosition {
/** Creates a SourcePosition by using the enclosing position of the invocation of this method.
* @return SourcePosition
*/
def fromEnclosing(): SourcePosition = macro SourcePositionMacro.fromEnclosingImpl
}
import scala.annotation.tailrec
import scala.reflect.macros.blackbox
import scala.reflect.internal.util.UndefinedPosition
final class SourcePositionMacro(val c: blackbox.Context) {
import c.universe.{ NoPosition => _, _ }
def fromEnclosingImpl(): Expr[SourcePosition] = {
val pos = c.enclosingPosition
if (!pos.isInstanceOf[UndefinedPosition] && pos.line >= 0 && pos.source != null) {
val f = pos.source.file
val name = constant[String](ownerSource(f.path, f.name))
val line = constant[Int](pos.line)
reify { LinePosition(name.splice, line.splice) }
} else
reify { NoPosition }
}
private[this] def ownerSource(path: String, name: String): String = {
@tailrec def inEmptyPackage(s: Symbol): Boolean =
s != NoSymbol && (
s.owner == c.mirror.EmptyPackage
|| s.owner == c.mirror.EmptyPackageClass
|| inEmptyPackage(s.owner)
)
c.internal.enclosingOwner match {
case ec if !ec.isStatic => name
case ec if inEmptyPackage(ec) => path
case ec => s"(${ec.fullName}) $name"
}
}
private[this] def constant[T: WeakTypeTag](t: T): Expr[T] = c.Expr[T](Literal(Constant(t)))
}
object SourcePosition extends SourcePositionImpl

View File

@ -7,9 +7,9 @@
package sbt.internal.util
import org.scalatest._
import org.scalatest.flatspec.AnyFlatSpec
class SourcePositionSpec extends FlatSpec {
class SourcePositionSpec extends AnyFlatSpec {
"SourcePosition()" should "return a sane SourcePosition" in {
val filename = "SourcePositionSpec.scala"
val lineNumber = 16

View File

@ -214,5 +214,5 @@ private final class MRelation[A, B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]])
override def hashCode = fwd.filterNot(_._2.isEmpty).hashCode()
override def toString =
all.map { case (a, b) => a + " -> " + b }.mkString("Relation [", ", ", "]")
all.map { case (a, b) => s"$a -> $b" }.mkString("Relation [", ", ", "]")
}

View File

@ -13,7 +13,6 @@ import java.io.File
import sbt.io.{ IO, Path }
import sbt.io.syntax._
import Path._
import sbt.io.IO
class FileCommands(baseDirectory: File) extends BasicStatementHandler {
lazy val commands = commandMap
@ -25,7 +24,7 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler {
"mkdir" nonEmpty makeDirectories _,
"absent" nonEmpty absent _,
// "sync" twoArg("Two directory paths", sync _),
"newer" twoArg ("Two paths", newer _),
"newer".twoArg("Two paths", newer _),
"pause" noArg {
println("Pausing in " + baseDirectory)
/*readLine("Press enter to continue. ") */
@ -33,11 +32,11 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler {
System.console.readLine
println()
},
"sleep" oneArg ("Time in milliseconds", time => Thread.sleep(time.toLong)),
"sleep".oneArg("Time in milliseconds", time => Thread.sleep(time.toLong)),
"exec" nonEmpty (execute _),
"copy" copy (to => rebase(baseDirectory, to)),
"copy-file" twoArg ("Two paths", copyFile _),
"must-mirror" twoArg ("Two paths", diffFiles _),
"copy-file".twoArg("Two paths", copyFile _),
"must-mirror".twoArg("Two paths", diffFiles _),
"copy-flat" copy flat
)

View File

@ -25,8 +25,7 @@ object ScriptedRunnerImpl {
tests: Array[String],
handlersProvider: HandlersProvider
): Unit = {
val context =
LoggerContext(useLog4J = System.getProperty("sbt.log.uselog4j", "false") == "true")
val context = LoggerContext()
val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, handlersProvider)
val logger = newLogger(context)
val allTests = get(tests, resourceBaseDirectory, logger) flatMap {
@ -103,7 +102,7 @@ final class ScriptedTests(
log: ManagedLogger,
context: LoggerContext,
): Seq[() => Option[String]] = {
for (groupDir <- (resourceBaseDirectory * group).get; nme <- (groupDir * name).get) yield {
for (groupDir <- (resourceBaseDirectory * group).get(); nme <- (groupDir * name).get()) yield {
val g = groupDir.getName
val n = nme.getName
val str = s"$g / $n"

View File

@ -191,7 +191,7 @@ val root = (project in file(".")).
},
// Used to have "openjdk-8-jdk" but that doesn't work on Ubuntu 14.04 https://github.com/sbt/sbt/issues/3105
// before that we had java6-runtime-headless" and that was pulling in JDK9 on Ubuntu 16.04 https://github.com/sbt/sbt/issues/2931
debianPackageDependencies in Debian ++= Seq("bash (>= 3.2)"),
debianPackageDependencies in Debian ++= Seq("bash (>= 3.2)", "curl | wget"),
debianPackageRecommends in Debian += "git",
linuxPackageMappings in Debian += {
val bd = sourceDirectory.value
@ -273,7 +273,7 @@ val root = (project in file(".")).
case (k, BinSbt) =>
import java.nio.file.{Files, FileSystems}
val x = IO.read(k)
IO.write(t / "sbt", x.replaceAllLiterally(
IO.write(t / "sbt", x.replace(
"declare init_sbt_version=_to_be_replaced",
s"declare init_sbt_version=$sbtVersionToRelease"))

View File

@ -4,7 +4,8 @@ import minitest._
import java.io.File
object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
lazy val isWindows: Boolean = sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
lazy val isWindows: Boolean =
sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows")
lazy val sbtScript =
if (isWindows) new File("target/universal/stage/bin/sbt.bat")
else new File("target/universal/stage/bin/sbt")
@ -12,12 +13,13 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
private val javaBinDir = new File("integration-test", "bin").getAbsolutePath
private def makeTest(
name: String,
javaOpts: String = "",
sbtOpts: String = "",
name: String,
javaOpts: String = "",
sbtOpts: String = "",
)(args: String*)(f: List[String] => Any) = {
test(name) {
val out = sbtProcessWithOpts(args: _*)(javaOpts = javaOpts, sbtOpts = sbtOpts).!!.linesIterator.toList
val out =
sbtProcessWithOpts(args: _*)(javaOpts = javaOpts, sbtOpts = sbtOpts).!!.linesIterator.toList
f(out)
()
}
@ -26,12 +28,14 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
def sbtProcess(args: String*) = sbtProcessWithOpts(args: _*)("", "")
def sbtProcessWithOpts(args: String*)(javaOpts: String, sbtOpts: String) = {
val path = sys.env("PATH")
sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, new File("citest"),
sbt.internal.Process(
Seq(sbtScript.getAbsolutePath) ++ args,
new File("citest"),
"JAVA_OPTS" -> javaOpts,
"SBT_OPTS" -> sbtOpts,
if (isWindows)
"JAVACMD" -> new File(javaBinDir, "java.cmd").getAbsolutePath()
else
else
"PATH" -> (javaBinDir + File.pathSeparator + path)
)
}
@ -48,9 +52,14 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
assert(out.contains[String]("-Dsbt.color=false"))
}
makeTest("sbt --no-colors in SBT_OPTS", sbtOpts = "--no-colors")("compile", "-v") { out: List[String] =>
if (isWindows) cancel("Test not supported on windows")
assert(out.contains[String]("-Dsbt.log.noformat=true"))
makeTest("sbt --no-colors in SBT_OPTS", sbtOpts = "--no-colors")("compile", "-v") {
out: List[String] =>
if (isWindows) cancel("Test not supported on windows")
assert(out.contains[String]("-Dsbt.log.noformat=true"))
}
makeTest("sbt --no-server")("compile", "--no-server", "-v") { out: List[String] =>
assert(out.contains[String]("-Dsbt.server.autostart=false"))
}
makeTest("sbt --debug-inc")("compile", "--debug-inc", "-v") { out: List[String] =>
@ -77,33 +86,43 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
assert(out.contains[String]("-Xmx503m"))
}
makeTest("sbt with -mem 503, -Xmx in JAVA_OPTS", javaOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
makeTest("sbt with -mem 503, -Xmx in JAVA_OPTS", javaOpts = "-Xmx1024m")("-mem", "503", "-v") {
out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
}
makeTest("sbt with -mem 503, -Xmx in SBT_OPTS", sbtOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
makeTest("sbt with -mem 503, -Xmx in SBT_OPTS", sbtOpts = "-Xmx1024m")("-mem", "503", "-v") {
out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xmx1024m"))
}
makeTest("sbt with -mem 503, -Xss in JAVA_OPTS", javaOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
makeTest("sbt with -mem 503, -Xss in JAVA_OPTS", javaOpts = "-Xss6m")("-mem", "503", "-v") {
out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
}
makeTest("sbt with -mem 503, -Xss in SBT_OPTS", sbtOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
makeTest("sbt with -mem 503, -Xss in SBT_OPTS", sbtOpts = "-Xss6m")("-mem", "503", "-v") {
out: List[String] =>
assert(out.contains[String]("-Xmx503m"))
assert(!out.contains[String]("-Xss6m"))
}
makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in JAVA_OPTS", javaOpts = "-Xms2048M -Xmx2048M -Xss6M")("-v") { out: List[String] =>
makeTest(
"sbt with -Xms2048M -Xmx2048M -Xss6M in JAVA_OPTS",
javaOpts = "-Xms2048M -Xmx2048M -Xss6M"
)("-v") { out: List[String] =>
assert(out.contains[String]("-Xms2048M"))
assert(out.contains[String]("-Xmx2048M"))
assert(out.contains[String]("-Xss6M"))
}
makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in SBT_OPTS", sbtOpts = "-Xms2048M -Xmx2048M -Xss6M")( "-v") { out: List[String] =>
makeTest(
"sbt with -Xms2048M -Xmx2048M -Xss6M in SBT_OPTS",
sbtOpts = "-Xms2048M -Xmx2048M -Xss6M"
)("-v") { out: List[String] =>
assert(out.contains[String]("-Xms2048M"))
assert(out.contains[String]("-Xmx2048M"))
assert(out.contains[String]("-Xss6M"))
@ -125,13 +144,18 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
assert(out.contains[String]("-XX:PermSize=128M"))
}
makeTest("sbt with -XX:+UseG1GC -XX:+PrintGC in JAVA_OPTS", javaOpts = "-XX:+UseG1GC -XX:+PrintGC")("-v") { out: List[String] =>
makeTest(
"sbt with -XX:+UseG1GC -XX:+PrintGC in JAVA_OPTS",
javaOpts = "-XX:+UseG1GC -XX:+PrintGC"
)("-v") { out: List[String] =>
assert(out.contains[String]("-XX:+UseG1GC"))
assert(out.contains[String]("-XX:+PrintGC"))
assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC"))
}
makeTest("sbt with -XX:-UseG1GC -XX:-PrintGC in SBT_OPTS", sbtOpts = "-XX:+UseG1GC -XX:+PrintGC")( "-v") { out: List[String] =>
makeTest("sbt with -XX:-UseG1GC -XX:-PrintGC in SBT_OPTS", sbtOpts = "-XX:+UseG1GC -XX:+PrintGC")(
"-v"
) { out: List[String] =>
assert(out.contains[String]("-XX:+UseG1GC"))
assert(out.contains[String]("-XX:+PrintGC"))
assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC"))
@ -140,7 +164,8 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
test("sbt with -debug in SBT_OPTS appears in sbt commands") {
if (isWindows) cancel("Test not supported on windows")
val out: List[String] = sbtProcessWithOpts("compile", "-v")(javaOpts = "", sbtOpts = "-debug").!!.linesIterator.toList
val out: List[String] =
sbtProcessWithOpts("compile", "-v")(javaOpts = "", sbtOpts = "-debug").!!.linesIterator.toList
// Debug argument must appear in the 'commands' section (after the sbt-launch.jar argument) to work
val sbtLaunchMatcher = """^.+sbt-launch.jar["]{0,1}$""".r
val locationOfSbtLaunchJarArg = out.zipWithIndex.collectFirst {
@ -155,7 +180,9 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
}
makeTest("sbt --jvm-debug <port>")("--jvm-debug", "12345", "-v") { out: List[String] =>
assert(out.contains[String]("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12345"))
assert(
out.contains[String]("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12345")
)
}
makeTest("sbt --no-share adds three system properties")("--no-share") { out: List[String] =>
@ -171,7 +198,7 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions {
test("sbt --script-version should print sbtVersion") {
val out = sbtProcess("--script-version").!!.trim
val expectedVersion = "^"+SbtRunnerTest.versionRegEx+"$"
val expectedVersion = "^" + SbtRunnerTest.versionRegEx + "$"
assert(out.matches(expectedVersion))
()
}

View File

@ -25,6 +25,7 @@ set default_java_opts=-Dfile.encoding=UTF-8
set sbt_jar=
set build_props_sbt_version=
set run_native_client=
set shutdownall=
set sbt_args_print_version=
set sbt_args_print_sbt_version=
@ -49,6 +50,7 @@ set sbt_args_sbt_dir=
set sbt_args_sbt_version=
set sbt_args_mem=
set sbt_args_client=
set sbt_args_no_server=
rem users can set SBT_OPTS via .sbtopts
if exist .sbtopts for /F %%A in (.sbtopts) do (
@ -204,6 +206,15 @@ if defined _no_colors_arg (
goto args_loop
)
if "%~0" == "-no-server" set _no_server_arg=true
if "%~0" == "--no-server" set _no_server_arg=true
if defined _no_server_arg (
set _no_server_arg=
set sbt_args_no_server=1
goto args_loop
)
if "%~0" == "-no-global" set _no_global_arg=true
if "%~0" == "--no-global" set _no_global_arg=true
@ -399,6 +410,11 @@ if defined _timings_arg (
goto args_loop
)
if "%~0" == "shutdownall" (
set shutdownall=1
goto args_loop
)
if "%~0" == "--script-version" (
set sbt_args_print_sbt_script_version=1
goto args_loop
@ -508,7 +524,7 @@ goto args_loop
rem Confirm a user's intent if the current directory does not look like an sbt
rem top-level directory and the "new" command was not given.
if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not exist build.sbt (
if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not defined shutdownall if not exist build.sbt (
if not exist project\ (
if not defined sbt_new (
echo [warn] Neither build.sbt nor a 'project' directory in the current directory: "%CD%"
@ -535,6 +551,16 @@ call :process
rem avoid bootstrapping/java version check for script version
if !shutdownall! equ 1 (
set count=0
for /f "tokens=1" %%i in ('jps -lv ^| findstr "xsbt.boot.Boot"') do (
taskkill /F /PID %%i
set /a count=!count!+1
)
echo shutdown !count! sbt processes
goto :eof
)
if !sbt_args_print_sbt_script_version! equ 1 (
echo !init_sbt_version!
goto :eof
@ -630,6 +656,10 @@ if defined sbt_args_traces (
set _SBT_OPTS=-Dsbt.traces=true !_SBT_OPTS!
)
if defined sbt_args_no_server (
set _SBT_OPTS=-Dsbt.io.virtual=false -Dsbt.server.autostart=false !_SBT_OPTS!
)
rem TODO: _SBT_OPTS needs to be processed as args and diffed against SBT_ARGS
if !sbt_args_print_sbt_version! equ 1 (

View File

@ -36,3 +36,4 @@ else
# Use Jansi to intercept ANSI sequences
"$JAVA_CMD" -Dsbt.log.format=true $JAVA_OPTS $SBT_OPTS -cp "$WDIR/sbt-launch.jar" xsbt.boot.Boot "$@"
fi

View File

@ -18,7 +18,7 @@ import sbt.util.Logger
import sbt.ConcurrentRestrictions.Tag
import sbt.protocol.testing._
import sbt.internal.util.Util.{ AnyOps, none }
import sbt.internal.util.{ RunningProcesses, Terminal => UTerminal }
import sbt.internal.util.{ Terminal => UTerminal }
private[sbt] object ForkTests {
def apply(
@ -158,13 +158,7 @@ private[sbt] object ForkTests {
classOf[ForkMain].getCanonicalName,
server.getLocalPort.toString
)
val p = Fork.java.fork(fork, options)
RunningProcesses.add(p)
val ec = try p.exitValue()
finally {
if (p.isAlive) p.destroy()
RunningProcesses.remove(p)
}
val ec = Fork.java(fork, options)
val result =
if (ec != 0)
TestOutput(
@ -223,7 +217,7 @@ private final class React(
listeners.foreach(_ testEvent event)
val suiteResult = SuiteResult(tEvents)
results += group -> suiteResult
listeners.foreach(_ endGroup (group, suiteResult.result))
listeners.foreach(_.endGroup(group, suiteResult.result))
react()
}
}

View File

@ -88,7 +88,7 @@ object Package {
for ((key, value) <- mergeManifest.getEntries.asScala) {
entryMap.get(key) match {
case Some(attributes) => mergeAttributes(attributes, value); ()
case None => entryMap put (key, value); ()
case None => entryMap.put(key, value); ()
}
}
}

View File

@ -65,7 +65,7 @@ object RawCompileLike {
log.debug("Uptodate: " + outputDirectory.getAbsolutePath)
}
}
cachedComp(inputs)(exists(outputDirectory.allPaths.get.toSet))
cachedComp(inputs)(exists(outputDirectory.allPaths.get().toSet))
}
def prepare(description: String, doCompile: Gen): Gen =

View File

@ -265,7 +265,7 @@ final class Eval(
if (phase == null || phase == phase.next || evalReporter.hasErrors)
()
else {
enteringPhase(phase) { phase.run }
enteringPhase(phase) { phase.run() }
compile(phase.next)
}
}

View File

@ -85,7 +85,7 @@ class CacheIvyTest extends Properties("CacheIvy") {
for {
o <- Gen.identifier
n <- Gen.identifier
r <- for { n <- Gen.numChar; ns <- Gen.numStr } yield n + ns
r <- for { n <- Gen.numChar; ns <- Gen.numStr } yield s"$n$ns"
cs <- arbitrary[Option[String]]
branch <- arbitrary[Option[String]]
isChanging <- arbitrary[Boolean]

View File

@ -284,10 +284,11 @@ public class BootServerSocket implements AutoCloseable {
public BootServerSocket(final AppConfiguration configuration)
throws ServerAlreadyBootingException, IOException {
final Path base = configuration.baseDirectory().toPath().toRealPath();
final Path target = base.resolve("project").resolve("target");
if (!isWindows) {
final String actualSocketLocation = socketLocation(base);
final Path target = Paths.get(actualSocketLocation).getParent();
if (!Files.isDirectory(target)) Files.createDirectories(target);
socketFile = Paths.get(socketLocation(base));
socketFile = Paths.get(actualSocketLocation);
} else {
socketFile = null;
}
@ -301,13 +302,20 @@ public class BootServerSocket implements AutoCloseable {
}
}
public static String socketLocation(final Path base) throws UnsupportedEncodingException {
public static String socketLocation(final Path base)
throws UnsupportedEncodingException, IOException {
final Path target = base.resolve("project").resolve("target");
long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8"));
if (isWindows) {
long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8"));
return "sbt-load" + hash;
} else {
return base.relativize(target.resolve("sbt-load.sock")).toString();
final String alternativeSocketLocation =
System.getenv().getOrDefault("XDG_RUNTIME_DIR", "/tmp");
final Path alternativeSocketLocationRoot =
Paths.get(alternativeSocketLocation).resolve(".sbt");
final Path locationForSocket = alternativeSocketLocationRoot.resolve("sbt-socket" + hash);
final Path pathForSocket = locationForSocket.resolve("sbt-load.sock");
return pathForSocket.toString();
}
}

View File

@ -153,7 +153,7 @@ object BasicCommands {
private[this] def completionsParser: Parser[String] = {
val notQuoted = (NotQuoted ~ any.*) map { case (nq, s) => nq + s }
val quotedOrUnquotedSingleArgument = Space ~> (StringVerbatim | StringEscapable | notQuoted)
token(quotedOrUnquotedSingleArgument ?? "" examples ("", " "))
token((quotedOrUnquotedSingleArgument ?? "").examples("", " "))
}
def runCompletions(state: State)(input: String): State = {
@ -199,7 +199,7 @@ object BasicCommands {
val it = s.iterator
var fail = false
while (it.hasNext && !fail) {
it.next match {
it.next() match {
case "" => fail = it.hasNext; ()
case next => result += next; ()
}
@ -406,7 +406,7 @@ object BasicCommands {
case Some(line) =>
val newState = s
.copy(
onFailure = Some(Exec(Shell, None)),
onFailure = Some(Exec(OldShell, None)),
remainingCommands = Exec(line, s.source) +: Exec(OldShell, None) +: s.remainingCommands
)
.setInteractive(true)

View File

@ -88,10 +88,10 @@ object CommandUtil {
}
def layoutDetails(details: Map[String, String]): String =
details.map { case (k, v) => k + "\n\n " + v } mkString ("\n", "\n\n", "\n")
details.map { case (k, v) => k + "\n\n " + v }.mkString("\n", "\n\n", "\n")
final val HelpPatternFlags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE
private[sbt] def isSbtBuild(baseDir: File) =
(baseDir / "project").exists() || (baseDir * "*.sbt").get.nonEmpty
(baseDir / "project").exists() || (baseDir * "*.sbt").get().nonEmpty
}

View File

@ -44,7 +44,7 @@ private[sbt] object LegacyWatched {
(ClearOnFailure :: next :: FailureWall :: repeat :: s)
.put(ContinuousEventMonitor, monitor: EventMonitor)
case Some(eventMonitor) =>
Watched.printIfDefined(watched watchingMessage eventMonitor.state)
Watched.printIfDefined(watched watchingMessage eventMonitor.state())
@tailrec def impl(): State = {
val triggered = try eventMonitor.awaitEvent()
catch {
@ -56,7 +56,7 @@ private[sbt] object LegacyWatched {
false
}
if (triggered) {
Watched.printIfDefined(watched triggeredMessage eventMonitor.state)
Watched.printIfDefined(watched triggeredMessage eventMonitor.state())
ClearOnFailure :: next :: FailureWall :: repeat :: s
} else if (shouldTerminate) {
while (System.in.available() > 0) System.in.read()

View File

@ -67,7 +67,7 @@ trait ConsoleInterface {
}
/**
* A NetworkClient connects to a running an sbt instance or starts a
* A NetworkClient connects to a running sbt instance or starts a
* new instance if there isn't already one running. Once connected,
* it can send commands for sbt to run, it can send completions to sbt
* and print the completions to stdout so that a shell can consume
@ -78,15 +78,15 @@ trait ConsoleInterface {
* needs to start it. It also contains the sbt command
* arguments to send to the server if any are present.
* @param console a logging instance. This can use a ConsoleAppender or
* just simply print to a PrintSream.
* just simply print to a PrintStream.
* @param inputStream the InputStream from which the client reads bytes. It
* is not hardcoded to System.in so that a NetworkClient
* can be remotely controlled by a java process, which
* is useful in test.
* is useful in testing.
* @param errorStream the sink for messages that we always want to be printed.
* It is usually System.err but could be overridden in tests
* or set to a null OutputStream if the NetworkClient needs
* to be silent
* to be silent.
* @param printStream the sink for standard out messages. It is typically
* System.out but in the case of completions, the bytes written
* to System.out are usually treated as completion results
@ -139,7 +139,7 @@ class NetworkClient(
private val rebooting = new AtomicBoolean(false)
private lazy val noTab = arguments.completionArguments.contains("--no-tab")
private lazy val noStdErr = arguments.completionArguments.contains("--no-stderr") &&
System.getenv("SBTC_AUTO_COMPLETE") == null
!sys.env.contains("SBTN_AUTO_COMPLETE") && !sys.env.contains("SBTC_AUTO_COMPLETE")
private def mkSocket(file: File): (Socket, Option[String]) = ClientSocket.socket(file, useJNI)
@ -380,13 +380,13 @@ class NetworkClient(
}
if (!startServer) {
val deadline = 5.seconds.fromNow
while (socket.isEmpty && !deadline.isOverdue) {
while (socket.isEmpty && !deadline.isOverdue()) {
socket = Try(ClientSocket.localSocket(bootSocketName, useJNI)).toOption
if (socket.isEmpty) Thread.sleep(20)
}
}
val hook = new Thread(() => Option(sbtProcess.get).foreach(_.destroyForcibly()))
Runtime.getRuntime.addShutdownHook(hook)
val shutdown = new Thread(() => Option(sbtProcess.get).foreach(_.destroyForcibly()))
Runtime.getRuntime.addShutdownHook(shutdown)
var gotInputBack = false
val readThreadAlive = new AtomicBoolean(true)
/*
@ -406,10 +406,13 @@ class NetworkClient(
socket.foreach { s =>
try {
s.getInputStream.read match {
case -1 | 0 => readThreadAlive.set(false)
case 2 => gotInputBack = true
case 5 => term.enterRawMode(); startInputThread()
case 3 if gotInputBack => readThreadAlive.set(false)
case -1 | 0 => readThreadAlive.set(false)
case 2 => // STX: start of text
gotInputBack = true
case 5 => // ENQ: enquiry
term.enterRawMode(); startInputThread()
case 3 if gotInputBack => // ETX: end of text
readThreadAlive.set(false)
case i if gotInputBack => stdinBytes.offer(i)
case i => printStream.write(i)
}
@ -441,8 +444,13 @@ class NetworkClient(
while (!gotInputBack && !stdinBytes.isEmpty && socket.isDefined) {
val out = s.getOutputStream
val b = stdinBytes.poll
out.write(b)
out.flush()
if (b == -1) {
// server waits for user input but stinBytes has ended
shutdown.run()
} else {
out.write(b)
out.flush()
}
}
}
process.foreach { p =>
@ -483,7 +491,7 @@ class NetworkClient(
try blockUntilStart()
catch { case t: Throwable => t.printStackTrace() } finally {
sbtProcess.set(null)
Util.ignoreResult(Runtime.getRuntime.removeShutdownHook(hook))
Util.ignoreResult(Runtime.getRuntime.removeShutdownHook(shutdown))
}
if (!portfile.exists()) throw new ServerFailedException
if (attached.get && !stdinBytes.isEmpty) Option(inputThread.get).foreach(_.drain())
@ -828,12 +836,12 @@ class NetworkClient(
case -1 => (query, query, None, None) // shouldn't happen
case i =>
val rawPrefix = query.substring(0, i)
val prefix = rawPrefix.replaceAllLiterally("\"", "").replaceAllLiterally("\\;", ";")
val rawSuffix = query.substring(i).replaceAllLiterally("\\;", ";")
val prefix = rawPrefix.replace("\"", "").replace("\\;", ";")
val rawSuffix = query.substring(i).replace("\\;", ";")
val suffix = if (rawSuffix.length > 1) rawSuffix.substring(1) else ""
(rawPrefix, prefix, Some(rawSuffix), Some(suffix))
}
} else (query, query.replaceAllLiterally("\\;", ";"), None, None)
} else (query, query.replace("\\;", ";"), None, None)
val tailSpace = query.endsWith(" ") || query.endsWith("\"")
val sanitizedQuery = suffix.foldLeft(prefix) { _ + _ }
def getCompletions(query: String, sendCommand: Boolean): Seq[String] = {
@ -877,7 +885,7 @@ class NetworkClient(
}
getCompletions(sanitizedQuery, true) collect {
case c if inQuote => c
case c if tailSpace && c.contains(" ") => c.replaceAllLiterally(prefix, "")
case c if tailSpace && c.contains(" ") => c.replace(prefix, "")
case c if !tailSpace => c.split(" ").last
}
}
@ -1098,10 +1106,10 @@ object NetworkClient {
launchJar = a
.split("--sbt-launch-jar=")
.lastOption
.map(_.replaceAllLiterally("%20", " "))
.map(_.replace("%20", " "))
case "--sbt-launch-jar" if i + 1 < sanitized.length =>
i += 1
launchJar = Option(sanitized(i).replaceAllLiterally("%20", " "))
launchJar = Option(sanitized(i).replace("%20", " "))
case "-bsp" | "--bsp" => bsp = true
case a if !a.startsWith("-") => commandArgs += a
case a @ SysProp(key, value) =>
@ -1123,7 +1131,7 @@ object NetworkClient {
sbtArguments.toSeq,
commandArgs.toSeq,
completionArguments.toSeq,
sbtScript.getOrElse(defaultSbtScript).replaceAllLiterally("%20", " "),
sbtScript.getOrElse(defaultSbtScript).replace("%20", " "),
bsp,
launchJar
)

View File

@ -79,7 +79,7 @@ abstract class ServerConnection(connection: Socket) {
if (a.nonEmpty) {
out.write(a)
}
writeEndLine
writeEndLine()
} catch {
case e: IOException =>
shutdown()
@ -100,7 +100,7 @@ abstract class ServerConnection(connection: Socket) {
out.close()
connection.close()
} catch { case e: IOException => e.printStackTrace() }
onShutdown
onShutdown()
}
}

View File

@ -75,7 +75,7 @@ private[sbt] object UITask {
this.synchronized(this.wait())
Right("") // should be unreachable
// JLine returns null on ctrl+d when there is no other input. This interprets
// ctrl+d with no imput as an exit
// ctrl+d with no input as an exit
case None => Left(TerminateAction)
case Some(s: String) =>
s.trim() match {

View File

@ -20,7 +20,7 @@ object JoinThread {
t.interrupt()
t.join(10)
} catch { case e: InterruptedException => }
if (t.isAlive && !deadline.isOverdue) impl()
if (t.isAlive && !deadline.isOverdue()) impl()
}
impl()
if (t.isAlive) {

View File

@ -8,7 +8,7 @@
package sbt
import scala.concurrent.duration._
import org.scalatest.FlatSpec
import org.scalatest.flatspec.AnyFlatSpec
import sbt.internal.util.complete.Parser
object MultiParserSpec {
@ -22,7 +22,7 @@ object MultiParserSpec {
}
}
import sbt.MultiParserSpec._
class MultiParserSpec extends FlatSpec {
class MultiParserSpec extends AnyFlatSpec {
"parsing" should "parse single commands" in {
assert(";foo".parse == Seq("foo"))
assert("; foo".parse == Seq("foo"))

View File

@ -10,7 +10,8 @@ package sbt.internal
import java.io.File
import java.nio.file.Files
import org.scalatest.{ FlatSpec, Matchers }
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import sbt.internal.classpath.ClassLoaderCache
import sbt.io.IO
@ -19,7 +20,7 @@ object ClassLoaderCacheTest {
def get(classpath: Seq[File]): ClassLoader = c(classpath.toList)
}
}
class ClassLoaderCacheTest extends FlatSpec with Matchers {
class ClassLoaderCacheTest extends AnyFlatSpec with Matchers {
import ClassLoaderCacheTest._
private def withCache[R](f: ClassLoaderCache => R): R = {
val cache = new ClassLoaderCache(ClassLoader.getSystemClassLoader)

View File

@ -252,7 +252,7 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits {
)(l: Def.Initialize[Task[A => C]])(r: Def.Initialize[Task[B => C]]): Def.Initialize[Task[C]] = {
val lhs = {
val innerLhs: Def.Initialize[Task[Either[A, Either[B, C]]]] =
x.map((fab: Either[A, B]) => fab.right.map(Left(_)))
x.map((fab: Either[A, B]) => fab.map(Left(_)))
val innerRhs: Def.Initialize[Task[A => Either[B, C]]] =
l.map((fn: A => C) => fn.andThen(Right(_)))
selectITask(innerLhs, innerRhs)

View File

@ -34,4 +34,14 @@ object Remove {
def removeValue(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==)
def removeValues(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==)
}
implicit def removeSet[T, V <: T]: Sequence[Set[T], Set[V], V] =
new Sequence[Set[T], Set[V], V] {
def removeValue(a: Set[T], b: V): Set[T] = a - b
def removeValues(a: Set[T], b: Set[V]): Set[T] = a diff (b.toSeq: Seq[T]).toSet
}
implicit def removeMap[A, B, X <: A]: Sequence[Map[A, B], Seq[X], X] =
new Sequence[Map[A, B], Seq[X], X] {
def removeValue(a: Map[A, B], b: X): Map[A, B] = a - b
def removeValues(a: Map[A, B], b: Seq[X]): Map[A, B] = a -- b
}
}

View File

@ -7,12 +7,12 @@
package sbt
import org.scalatest.FlatSpec
import org.scalatest.flatspec.AnyFlatSpec
import sbt.internal.util.{ AttributeKey, AttributeMap }
import sbt.io.syntax.file
import scala.annotation.nowarn
class ScopeDisplaySpec extends FlatSpec {
class ScopeDisplaySpec extends AnyFlatSpec {
val project = ProjectRef(file("foo/bar"), "bar")
val mangledName = "bar_slash_blah_blah_blah"

View File

@ -7,12 +7,12 @@
package sbt.std
import org.scalatest.{ TestData, fixture }
import org.scalatest.{ TestData, fixture, funsuite }
import sbt.std.TestUtil._
import scala.tools.reflect.{ FrontEnd, ToolBoxError }
class TaskConfigSpec extends fixture.FunSuite with fixture.TestDataFixture {
class TaskConfigSpec extends funsuite.FixtureAnyFunSuite with fixture.TestDataFixture {
private def expectError(
errorSnippet: String,
compileOptions: String = "",

View File

@ -69,7 +69,7 @@ object Assign {
val is = Seq(
mk := 3,
name := "asdf",
tk := (math.random * 1000).toInt,
tk := (math.random() * 1000).toInt,
isk := dummys.value.parsed // should not compile: cannot use a task to define the parser
// ik := { if( tsk.parsed.value == "blue") tk.value else mk.value }
)

View File

@ -8,11 +8,11 @@
package sbt.std.neg
import scala.tools.reflect.ToolBoxError
import org.scalatest.{ TestData, fixture }
import org.scalatest.{ TestData, fixture, funsuite }
import sbt.std.{ TaskLinterDSLFeedback, TestUtil }
import sbt.std.TestUtil._
class TaskNegSpec extends fixture.FunSuite with fixture.TestDataFixture {
class TaskNegSpec extends funsuite.FixtureAnyFunSuite with fixture.TestDataFixture {
def expectError(
errorSnippet: String,
compileOptions: String = "",

View File

@ -44,7 +44,7 @@ abstract class BackgroundJobService extends Closeable {
start(logger, file)._2.apply()
}
/** Same as shutown. */
/** Same as shutdown. */
def close(): Unit
/** Shuts down all background jobs. */

View File

@ -116,7 +116,8 @@ object BuildPaths {
private[this] def defaultGlobalZinc(globalBase: File) = globalBase / "zinc"
def configurationSources(base: File): Seq[File] =
(base * (GlobFilter("*.sbt") - ".sbt")).get
(base * (GlobFilter("*.sbt") - ".sbt"))
.get()
.sortBy(_.getName.toLowerCase(Locale.ENGLISH))
def pluginDirectory(definitionBase: File) = definitionBase / PluginsDirectoryName

View File

@ -8,7 +8,7 @@
package sbt
import java.io.File
import java.util.regex.Pattern
import sbt.Def.{ ScopedKey, Setting }
import sbt.Keys._
import sbt.SlashSyntax0._
@ -284,8 +284,8 @@ object Cross {
}
def logSwitchInfo(
included: Seq[(ProjectRef, Seq[ScalaVersion])],
excluded: Seq[(ProjectRef, Seq[ScalaVersion])]
included: Seq[(ResolvedReference, ScalaVersion, Seq[ScalaVersion])],
excluded: Seq[(ResolvedReference, Seq[ScalaVersion])]
) = {
instance.foreach {
@ -304,56 +304,96 @@ object Cross {
def detailedLog(msg: => String) =
if (switch.verbose) state.log.info(msg) else state.log.debug(msg)
def logProject: (ProjectRef, Seq[ScalaVersion]) => Unit = (proj, scalaVersions) => {
val current = if (proj == currentRef) "*" else " "
detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}")
def logProject: (ResolvedReference, Seq[ScalaVersion]) => Unit = (ref, scalaVersions) => {
val current = if (ref == currentRef) "*" else " "
ref match {
case proj: ProjectRef =>
detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}")
case _ => // don't log BuildRefs
}
}
detailedLog("Switching Scala version on:")
included.foreach(logProject.tupled)
included.foreach { case (project, _, versions) => logProject(project, versions) }
detailedLog("Excluding projects:")
excluded.foreach(logProject.tupled)
}
val projects: Seq[(ResolvedReference, Seq[ScalaVersion])] = {
val projects: Seq[(ResolvedReference, Option[ScalaVersion], Seq[ScalaVersion])] = {
val projectScalaVersions =
structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj))
if (switch.version.force) {
logSwitchInfo(projectScalaVersions, Nil)
projectScalaVersions ++ structure.units.keys
projectScalaVersions.map {
case (ref, options) => (ref, Some(version), options)
} ++ structure.units.keys
.map(BuildRef.apply)
.map(proj => proj -> crossVersions(extracted, proj))
.map(proj => (proj, Some(version), crossVersions(extracted, proj)))
} else if (version.contains('*')) {
projectScalaVersions.map {
case (project, scalaVersions) =>
globFilter(version, scalaVersions) match {
case Nil => (project, None, scalaVersions)
case Seq(version) => (project, Some(version), scalaVersions)
case multiple =>
sys.error(
s"Multiple crossScalaVersions matched query '$version': ${multiple.mkString(", ")}"
)
}
}
} else {
val binaryVersion = CrossVersion.binaryScalaVersion(version)
val (included, excluded) = projectScalaVersions.partition {
case (_, scalaVersions) =>
scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion)
projectScalaVersions.map {
case (project, scalaVersions) =>
if (scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion))
(project, Some(version), scalaVersions)
else
(project, None, scalaVersions)
}
if (included.isEmpty) {
sys.error(
s"""Switch failed: no subprojects list "$version" (or compatible version) in crossScalaVersions setting.
|If you want to force it regardless, call ++ $version!""".stripMargin
)
}
logSwitchInfo(included, excluded)
included
}
}
(setScalaVersionForProjects(version, instance, projects, state, extracted), projects.map(_._1))
val included = projects.collect {
case (project, Some(version), scalaVersions) => (project, version, scalaVersions)
}
val excluded = projects.collect {
case (project, None, scalaVersions) => (project, scalaVersions)
}
if (included.isEmpty) {
sys.error(
s"""Switch failed: no subprojects list "$version" (or compatible version) in crossScalaVersions setting.
|If you want to force it regardless, call ++ $version!""".stripMargin
)
}
logSwitchInfo(included, excluded)
(setScalaVersionsForProjects(instance, included, state, extracted), included.map(_._1))
}
private def setScalaVersionForProjects(
version: String,
def globFilter(pattern: String, candidates: Seq[String]): Seq[String] = {
def createGlobRegex(remainingPattern: String): String =
remainingPattern.indexOf("*") match {
case -1 => Pattern.quote(remainingPattern)
case n =>
val chunk = Pattern.quote(remainingPattern.substring(0, n)) + ".*"
if (remainingPattern.length > n)
chunk + createGlobRegex(remainingPattern.substring(n + 1))
else chunk
}
val compiledPattern = Pattern.compile(createGlobRegex(pattern))
candidates.filter(compiledPattern.matcher(_).matches())
}
private def setScalaVersionsForProjects(
instance: Option[(File, ScalaInstance)],
projects: Seq[(ResolvedReference, Seq[String])],
projects: Seq[(ResolvedReference, String, Seq[String])],
state: State,
extracted: Extracted
): State = {
import extracted._
val newSettings = projects.flatMap {
case (project, scalaVersions) =>
case (project, version, scalaVersions) =>
val scope = Scope(Select(project), Zero, Zero, Zero)
instance match {

View File

@ -43,7 +43,7 @@ import sbt.internal.librarymanagement.mavenint.{
PomExtraDependencyAttributes,
SbtPomExtraProperties
}
import sbt.internal.librarymanagement.{ CustomHttp => _, _ }
import sbt.internal.librarymanagement._
import sbt.internal.nio.{ CheckBuildSources, Globs }
import sbt.internal.server.{
BspCompileProgress,
@ -148,6 +148,7 @@ object Defaults extends BuildCommon {
val m = (for (a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an)).toMap
m.get _
}
private[sbt] def globalDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] =
Def.defaultSettings(inScope(GlobalScope)(ss))
@ -229,7 +230,7 @@ object Defaults extends BuildCommon {
private[sbt] lazy val globalIvyCore: Seq[Setting[_]] =
Seq(
internalConfigurationMap :== Configurations.internalMap _,
credentials :== Nil,
credentials :== SysProp.sbtCredentialsEnv.toList,
exportJars :== false,
trackInternalDependencies :== TrackLevel.TrackAlways,
exportToInternal :== TrackLevel.TrackAlways,
@ -257,8 +258,6 @@ object Defaults extends BuildCommon {
artifactClassifier :== None,
checksums := Classpaths.bootChecksums(appConfiguration.value),
conflictManager := ConflictManager.default,
CustomHttp.okhttpClientBuilder :== CustomHttp.defaultHttpClientBuilder,
CustomHttp.okhttpClient := CustomHttp.okhttpClientBuilder.value.build,
pomExtra :== NodeSeq.Empty,
pomPostProcess :== idFun,
pomAllRepositories :== false,
@ -1394,11 +1393,10 @@ object Defaults extends BuildCommon {
val x = {
import analysis.{ apis, relations => rel }
rel.internalClassDeps(c).map(intlStamp(_, analysis, s + c)) ++
rel.externalDeps(c).map(stamp) +
(apis.internal.get(c) match {
case Some(x) => x.compilationTimestamp
case _ => Long.MinValue
})
rel.externalDeps(c).map(stamp) ++
rel.productClassName.reverse(c).flatMap { pc =>
apis.internal.get(pc).map(_.compilationTimestamp)
} + Long.MinValue
}.max
if (x != Long.MinValue) {
stamps(c) = x
@ -2341,7 +2339,7 @@ object Defaults extends BuildCommon {
s: TaskStreams,
ci: Inputs,
promise: PromiseWrap[Boolean],
reporter: BuildServerReporter
reporter: BuildServerReporter,
): CompileResult = {
lazy val x = s.text(ExportStream)
def onArgs(cs: Compilers) = {
@ -2634,7 +2632,7 @@ object Defaults extends BuildCommon {
def dependencyResolutionTask: Def.Initialize[Task[DependencyResolution]] =
Def.taskIf {
if (useCoursier.value) CoursierDependencyResolution(csrConfiguration.value)
else IvyDependencyResolution(ivyConfiguration.value, CustomHttp.okhttpClient.value)
else IvyDependencyResolution(ivyConfiguration.value)
}
}
@ -3058,7 +3056,7 @@ object Classpaths {
else None
},
dependencyResolution := dependencyResolutionTask.value,
publisher := IvyPublisher(ivyConfiguration.value, CustomHttp.okhttpClient.value),
publisher := IvyPublisher(ivyConfiguration.value),
ivyConfiguration := mkIvyConfiguration.value,
ivyConfigurations := {
val confs = thisProject.value.configurations
@ -3197,8 +3195,8 @@ object Classpaths {
update / unresolvedWarningConfiguration := UnresolvedWarningConfiguration(
dependencyPositions.value
),
updateFull := (updateTask tag (Tags.Update, Tags.Network)).value,
update := (updateWithoutDetails("update") tag (Tags.Update, Tags.Network)).value,
updateFull := (updateTask.tag(Tags.Update, Tags.Network)).value,
update := (updateWithoutDetails("update").tag(Tags.Update, Tags.Network)).value,
update := {
val report = update.value
val log = streams.value.log
@ -3209,7 +3207,7 @@ object Classpaths {
evicted / evictionWarningOptions := EvictionWarningOptions.full,
evicted := {
import ShowLines._
val report = (updateTask tag (Tags.Update, Tags.Network)).value
val report = (updateTask.tag(Tags.Update, Tags.Network)).value
val log = streams.value.log
val ew =
EvictionWarning(ivyModule.value, (evicted / evictionWarningOptions).value, report)
@ -3361,7 +3359,7 @@ object Classpaths {
private[sbt] def ivySbt0: Initialize[Task[IvySbt]] =
Def.task {
Credentials.register(credentials.value, streams.value.log)
new IvySbt(ivyConfiguration.value, CustomHttp.okhttpClient.value)
new IvySbt(ivyConfiguration.value)
}
def moduleSettings0: Initialize[Task[ModuleSettings]] = Def.task {
val deps = allDependencies.value.toVector
@ -3701,7 +3699,7 @@ object Classpaths {
try {
val extracted = (Project extract st)
val sk = (projRef / Zero / Zero / libraryDependencies).scopedKey
val empty = extracted.structure.data set (sk.scope, sk.key, Nil)
val empty = extracted.structure.data.set(sk.scope, sk.key, Nil)
val settings = extracted.structure.settings filter { s: Setting[_] =>
(s.key.key == libraryDependencies.key) &&
(s.key.scope.project == Select(projRef))
@ -4318,7 +4316,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
/** Constructs a setting that declares a new artifact `a` that is generated by `taskDef`. */
def addArtifact(a: Artifact, taskDef: TaskKey[File]): SettingsDefinition = {
val pkgd = packagedArtifacts := packagedArtifacts.value updated (a, taskDef.value)
val pkgd = packagedArtifacts := packagedArtifacts.value.updated(a, taskDef.value)
Seq(artifacts += a, pkgd)
}
@ -4330,7 +4328,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
val artLocal = SettingKey.local[Artifact]
val taskLocal = TaskKey.local[File]
val art = artifacts := artLocal.value +: artifacts.value
val pkgd = packagedArtifacts := packagedArtifacts.value updated (artLocal.value, taskLocal.value)
val pkgd = packagedArtifacts := packagedArtifacts.value.updated(artLocal.value, taskLocal.value)
Seq(artLocal := artifact.value, taskLocal := taskDef.value, art, pkgd)
}
@ -4380,7 +4378,7 @@ trait BuildExtra extends BuildCommon with DefExtra {
}
@deprecated(
"externalIvyFile is not supported by Couriser, and will be removed in the future",
"externalIvyFile is not supported by Coursier, and will be removed in the future",
since = "1.5.0"
)
def externalIvyFile(

View File

@ -396,6 +396,7 @@ object Keys {
val usePipelining = settingKey[Boolean]("Use subproject pipelining for compilation.").withRank(BSetting)
val exportPipelining = settingKey[Boolean]("Product early output so downstream subprojects can do pipelining.").withRank(BSetting)
// BSP keys
val bspConfig = taskKey[Unit]("Create or update the BSP connection files").withRank(DSetting)
val bspEnabled = SettingKey[Boolean](BasicKeys.bspEnabled)
val bspSbtEnabled = settingKey[Boolean]("Should BSP export meta-targets for the SBT build itself?")
@ -418,8 +419,13 @@ object Keys {
val bspBuildTargetCleanCache = inputKey[Unit]("Corresponds to buildTarget/cleanCache request").withRank(DTask)
val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask)
val bspBuildTargetJVMRunEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmRunEnvironment request").withRank(DTask)
val bspBuildTargetJVMTestEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmTestEnvironment request").withRank(DTask)
val bspBuildTargetJvmEnvironmentItem = taskKey[JvmEnvironmentItem]("Computes JVM environment item").withRank(DTask)
val bspScalaTestClasses = inputKey[Unit]("Corresponds to buildTarget/scalaTestClasses request").withRank(DTask)
val bspScalaTestClassesItem = taskKey[ScalaTestClassesItem]("").withRank(DTask)
val bspScalaTestClassesItem = taskKey[Seq[ScalaTestClassesItem]]("").withRank(DTask)
val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask)
val bspScalaMainClassesItem = taskKey[ScalaMainClassesItem]("").withRank(DTask)
val bspReporter = taskKey[BuildServerReporter]("").withRank(DTask)

View File

@ -329,7 +329,6 @@ object BuiltinCommands {
startServer,
eval,
last,
oldLastGrep,
lastGrep,
export,
boot,
@ -626,12 +625,6 @@ object BuiltinCommands {
s
}
@deprecated("Use `lastGrep` instead.", "1.2.0")
def oldLastGrep: Command =
lastGrepCommand(OldLastGrepCommand, oldLastGrepBrief, oldLastGrepDetailed, { s =>
lastGrepParser(s)
})
def lastGrep: Command =
lastGrepCommand(LastGrepCommand, lastGrepBrief, lastGrepDetailed, lastGrepParser)
@ -643,9 +636,6 @@ object BuiltinCommands {
): Command =
Command(name, briefHelp, detail)(parser) { (s: State, sks: (String, Option[AnyKeys])) =>
{
if (name == OldLastGrepCommand)
s.log.warn(deprecationWarningText(OldLastGrepCommand, LastGrepCommand))
(s, sks) match {
case (s, (pattern, Some(sks))) =>
val (str, _, display) = extractLast(s)

View File

@ -7,26 +7,22 @@
package sbt
import java.io.PrintWriter
import java.util.concurrent.RejectedExecutionException
import java.util.Properties
import sbt.BasicCommandStrings.{ StashOnFailure, networkExecPrefix }
import sbt.internal.ShutdownHooks
import sbt.internal.langserver.ErrorCodes
import sbt.internal.protocol.JsonRpcResponseError
import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey
import sbt.internal.protocol.JsonRpcResponseError
import sbt.internal.util.{ ErrorHandling, GlobalLogBacking, Prompt, Terminal => ITerminal }
import sbt.internal.{ ShutdownHooks, TaskProgress }
import sbt.internal.{ FastTrackCommands, ShutdownHooks, SysProp, TaskProgress }
import sbt.io.{ IO, Using }
import sbt.protocol._
import sbt.util.{ Logger, LoggerContext }
import java.io.PrintWriter
import java.util.Properties
import java.util.concurrent.RejectedExecutionException
import scala.annotation.tailrec
import scala.concurrent.duration._
import scala.util.control.NonFatal
import sbt.internal.FastTrackCommands
import sbt.internal.SysProp
object MainLoop {
@ -148,7 +144,7 @@ object MainLoop {
}
def next(state: State): State = {
val context = LoggerContext(useLog4J = state.get(Keys.useLog4J.key).getOrElse(false))
val context = LoggerContext()
val superShellSleep =
state.get(Keys.superShellSleep.key).getOrElse(SysProp.supershellSleep.millis)
val superShellThreshold =

View File

@ -41,8 +41,14 @@ object Opts {
}
object resolver {
import sbt.io.syntax._
@deprecated("Use sonatypeOssReleases instead", "1.7.0")
val sonatypeReleases = Resolver.sonatypeRepo("releases")
val sonatypeOssReleases = Resolver.sonatypeOssRepos("releases")
@deprecated("Use sonatypeOssSnapshots instead", "1.7.0")
val sonatypeSnapshots = Resolver.sonatypeRepo("snapshots")
val sonatypeOssSnapshots = Resolver.sonatypeOssRepos("snapshots")
val sonatypeStaging = MavenRepository(
"sonatype-staging",
"https://oss.sonatype.org/service/local/staging/deploy/maven2"

View File

@ -99,7 +99,7 @@ private[sbt] object PluginCross {
VersionNumber(sv) match {
case VersionNumber(Seq(0, 12, _*), _, _) => "2.9.2"
case VersionNumber(Seq(0, 13, _*), _, _) => "2.10.7"
case VersionNumber(Seq(1, 0, _*), _, _) => "2.12.15"
case VersionNumber(Seq(1, 0, _*), _, _) => "2.12.16"
case _ => sys.error(s"Unsupported sbt binary version: $sv")
}
}

View File

@ -8,7 +8,6 @@
package sbt
import java.io.File
import java.lang.reflect.Method
import sbt.Def._
import sbt.Keys._
@ -47,7 +46,7 @@ object ScriptedPlugin extends AutoPlugin {
val scriptedParallelInstances = settingKey[Int](
"Configures the number of scripted instances for parallel testing, only used in batch mode."
)
val scriptedRun = taskKey[Method]("")
val scriptedRun = taskKey[ScriptedRun]("")
val scriptedLaunchOpts =
settingKey[Seq[String]]("options to pass to jvm launching scripted tasks")
val scriptedDependencies = taskKey[Unit]("")
@ -114,21 +113,8 @@ object ScriptedPlugin extends AutoPlugin {
}
}
private[sbt] def scriptedRunTask: Initialize[Task[Method]] = Def.taskDyn {
val fCls = classOf[File]
val bCls = classOf[Boolean]
val asCls = classOf[Array[String]]
val lfCls = classOf[java.util.List[File]]
val iCls = classOf[Int]
val clazz = scriptedTests.value.getClass
val method =
if (scriptedBatchExecution.value)
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls)
else
clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls)
Def.task(method)
private[sbt] def scriptedRunTask: Initialize[Task[ScriptedRun]] = Def.task {
ScriptedRun.of(scriptedTests.value, scriptedBatchExecution.value)
}
private[sbt] final case class ScriptedTestPage(page: Int, total: Int)
@ -191,21 +177,16 @@ object ScriptedPlugin extends AutoPlugin {
private[sbt] def scriptedTask: Initialize[InputTask[Unit]] = Def.inputTask {
val args = scriptedParser(sbtTestDirectory.value).parsed
Def.unit(scriptedDependencies.value)
try {
val method = scriptedRun.value
val scriptedInstance = scriptedTests.value
val dir = sbtTestDirectory.value
val log = Boolean box scriptedBufferLog.value
val launcher = sbtLauncher.value
val opts = scriptedLaunchOpts.value.toArray
val empty = new java.util.ArrayList[File]()
val instances = Int box scriptedParallelInstances.value
if (scriptedBatchExecution.value)
method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty, instances)
else method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty)
()
} catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause }
scriptedRun.value.run(
sbtTestDirectory.value,
scriptedBufferLog.value,
args,
sbtLauncher.value,
Fork.javaCommand((scripted / javaHome).value, "java").getAbsolutePath,
scriptedLaunchOpts.value,
new java.util.ArrayList[File](),
scriptedParallelInstances.value
)
}
private[this] def getJars(config: Configuration): Initialize[Task[PathFinder]] = Def.task {

View File

@ -0,0 +1,179 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
import java.io.File
import java.lang.reflect.Method
import scala.annotation.unused
sealed trait ScriptedRun {
final def run(
resourceBaseDirectory: File,
bufferLog: Boolean,
tests: Seq[String],
launcherJar: File,
javaCommand: String,
launchOpts: Seq[String],
prescripted: java.util.List[File],
instances: Int,
): Unit = {
try {
invoke(
resourceBaseDirectory,
bufferLog,
tests.toArray,
launcherJar,
javaCommand,
launchOpts.toArray,
prescripted,
instances,
)
()
} catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause }
}
protected def invoke(
resourceBaseDirectory: File,
bufferLog: java.lang.Boolean,
tests: Array[String],
launcherJar: File,
javaCommand: String,
launchOpts: Array[String],
prescripted: java.util.List[File],
instances: java.lang.Integer,
): AnyRef
}
object ScriptedRun {
def of(scriptedTests: AnyRef, batchExecution: Boolean): ScriptedRun = {
val fCls = classOf[File]
val bCls = classOf[Boolean]
val asCls = classOf[Array[String]]
val sCls = classOf[String]
val lfCls = classOf[java.util.List[File]]
val iCls = classOf[Int]
val clazz = scriptedTests.getClass
if (batchExecution)
try new RunInParallelV2(
scriptedTests,
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, sCls, asCls, lfCls, iCls)
)
catch {
case _: NoSuchMethodException =>
new RunInParallelV1(
scriptedTests,
clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls)
)
}
else
try new RunV2(
scriptedTests,
clazz.getMethod("run", fCls, bCls, asCls, fCls, sCls, asCls, lfCls)
)
catch {
case _: NoSuchMethodException =>
new RunV1(scriptedTests, clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls))
}
}
private class RunV1(scriptedTests: AnyRef, run: Method) extends ScriptedRun {
override protected def invoke(
resourceBaseDirectory: File,
bufferLog: java.lang.Boolean,
tests: Array[String],
launcherJar: File,
@unused javaCommand: String,
launchOpts: Array[String],
prescripted: java.util.List[File],
@unused instances: java.lang.Integer,
): AnyRef =
run.invoke(
scriptedTests,
resourceBaseDirectory,
bufferLog,
tests,
launcherJar,
launchOpts,
prescripted,
)
}
private class RunInParallelV1(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun {
override protected def invoke(
resourceBaseDirectory: File,
bufferLog: java.lang.Boolean,
tests: Array[String],
launcherJar: File,
@unused javaCommand: String,
launchOpts: Array[String],
prescripted: java.util.List[File],
instances: Integer,
): AnyRef =
runInParallel.invoke(
scriptedTests,
resourceBaseDirectory,
bufferLog,
tests,
launcherJar,
launchOpts,
prescripted,
instances,
)
}
private class RunV2(scriptedTests: AnyRef, run: Method) extends ScriptedRun {
override protected def invoke(
resourceBaseDirectory: File,
bufferLog: java.lang.Boolean,
tests: Array[String],
launcherJar: File,
javaCommand: String,
launchOpts: Array[String],
prescripted: java.util.List[File],
@unused instances: java.lang.Integer,
): AnyRef =
run.invoke(
scriptedTests,
resourceBaseDirectory,
bufferLog,
tests,
launcherJar,
javaCommand,
launchOpts,
prescripted,
)
}
private class RunInParallelV2(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun {
override protected def invoke(
resourceBaseDirectory: File,
bufferLog: java.lang.Boolean,
tests: Array[String],
launcherJar: File,
javaCommand: String,
launchOpts: Array[String],
prescripted: java.util.List[File],
instances: Integer,
): AnyRef =
runInParallel.invoke(
scriptedTests,
resourceBaseDirectory,
bufferLog,
tests,
launcherJar,
javaCommand,
launchOpts,
prescripted,
instances,
)
}
}

View File

@ -18,12 +18,12 @@ trait UpperStateOps extends Any {
/**
* ProjectRef to the current project of the state session that can be change using
* `project` commmand.
* `project` command.
*/
def currentRef: ProjectRef
/**
* Current project of the state session that can be change using `project` commmand.
* Current project of the state session that can be change using `project` command.
*/
def currentProject: ResolvedProject

View File

@ -57,16 +57,7 @@ object CoursierRepositoriesTasks {
private final val keepPreloaded = false // coursierKeepPreloaded.value
def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task {
val bootResOpt = bootResolvers.value
val overrideFlag = overrideBuildResolvers.value
val result0 = bootResOpt.filter(_ => overrideFlag) match {
case Some(r) => r
case None =>
val extRes = externalResolvers.value
val isSbtPlugin = sbtPlugin.value
if (isSbtPlugin) sbtResolvers.value ++ extRes
else extRes
}
val result0 = fullResolvers.value.filterNot(_ == projectResolver.value)
val reorderResolvers = true // coursierReorderResolvers.value
val paths = ivyPaths.value
@ -80,10 +71,10 @@ object CoursierRepositoriesTasks {
result1 map {
case r: FileRepository =>
val ivyPatterns = r.patterns.ivyPatterns map {
_.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri)
_.replace("$" + "{ivy.home}", ivyHomeUri)
}
val artifactPatterns = r.patterns.artifactPatterns map {
_.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri)
_.replace("$" + "{ivy.home}", ivyHomeUri)
}
val p =
r.patterns.withIvyPatterns(ivyPatterns).withArtifactPatterns(artifactPatterns)

View File

@ -304,7 +304,12 @@ object Act {
case Some(ProjectRef(uri, _)) => index.keys(Some(BuildRef(uri)), conf, task)
case _ => Set()
}
val keys: Set[String] = index.keys(proj, conf, task) ++ buildKeys
val globalKeys: Set[String] =
proj match {
case Some(_) => index.keys(None, conf, task)
case _ => Set()
}
val keys: Set[String] = index.keys(proj, conf, task) ++ buildKeys ++ globalKeys
keyParser(keys)
}

View File

@ -10,6 +10,15 @@ package sbt.internal
private[sbt] object Banner {
def apply(version: String): Option[String] =
version match {
case v if v.startsWith("1.6.0") =>
Some(s"""
|Here are some highlights of this release:
| - Improved JDK 17 support
| - Improved Build Server Protocol (BSP) support
| - Tab completion of global keys
|See https://eed3si9n.com/sbt-1.6.0 for full release notes.
|Hide the banner for this release by running `skipBanner`.
|""".stripMargin.linesIterator.mkString("\n"))
case v if v.startsWith("1.4.0") =>
Some(s"""
|Here are some highlights of this release:

View File

@ -263,7 +263,8 @@ final class BuildUnit(
val plugins: LoadedPlugins
) {
override def toString =
if (uri.getScheme == "file") localBase.toString else (uri + " (locally: " + localBase + ")")
if (uri.getScheme == "file") localBase.toString
else (uri.toString + " (locally: " + localBase + ")")
}
final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit]) {

View File

@ -70,23 +70,10 @@ $PrintCommand <task>
def pluginsDetailed = pluginsBrief // TODO: expand
val LastCommand = "last"
val OldLastGrepCommand = "last-grep"
val LastGrepCommand = "lastGrep"
val ExportCommand = "export"
val ExportStream = "export"
val oldLastGrepBrief =
(OldLastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.")
val oldLastGrepDetailed =
s"""$OldLastGrepCommand <pattern>
Displays lines from the logging of previous commands that match `pattern`.
$OldLastGrepCommand <pattern> [key]
Displays lines from logging associated with `key` that match `pattern`. The key typically refers to a task (for example, test:compile). The logging that is displayed is restricted to the logging for that particular task.
<pattern> is a regular expression interpreted by java.util.Pattern. Matching text is highlighted (when highlighting is supported and enabled).
See also '$LastCommand'."""
val lastGrepBrief =
(LastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.")
val lastGrepDetailed =

View File

@ -1128,7 +1128,28 @@ private[sbt] object Continuous extends DeprecatedContinuous {
val callbacks: Callbacks,
val dynamicInputs: mutable.Set[DynamicInput],
val pending: Boolean,
var failAction: Option[Watch.Action],
) {
def this(
count: Int,
commands: Seq[String],
beforeCommandImpl: (State, mutable.Set[DynamicInput]) => State,
afterCommand: State => State,
afterWatch: State => State,
callbacks: Callbacks,
dynamicInputs: mutable.Set[DynamicInput],
pending: Boolean,
) = this(
count,
commands,
beforeCommandImpl,
afterCommand,
afterWatch,
callbacks,
dynamicInputs,
pending,
None
)
def beforeCommand(state: State): State = beforeCommandImpl(state, dynamicInputs)
def incremented: ContinuousState = withCount(count + 1)
def withPending(p: Boolean) =
@ -1208,7 +1229,7 @@ private[sbt] object ContinuousCommands {
.channelForName(channelName)
.getOrElse(throw new IllegalStateException(s"No channel with name $channelName"))
val dynamicInputs = mutable.Set.empty[DynamicInput]
val context = LoggerContext(useLog4J = state.get(Keys.useLog4J.key).getOrElse(false))
val context = LoggerContext()
def cb: Continuous.Callbacks =
Continuous.getCallbacks(state, channel, commands, cache, dynamicInputs, context)
@ -1323,7 +1344,8 @@ private[sbt] object ContinuousCommands {
case Watch.Prompt => stop.map(_ :: s"$PromptChannel ${channel.name}" :: Nil mkString ";")
case Watch.Run(commands) =>
stop.map(_ +: commands.map(_.commandLine).filter(_.nonEmpty) mkString "; ")
case Watch.HandleError(_) =>
case a @ Watch.HandleError(_) =>
cs.failAction = Some(a)
stop.map(_ :: s"$failWatch ${channel.name}" :: Nil mkString "; ")
case _ => stop
}
@ -1353,27 +1375,31 @@ private[sbt] object ContinuousCommands {
}
cs.afterCommand(postState)
}
private[sbt] val stopWatchCommand = watchCommand(stopWatch) { (channel, state) =>
state.get(watchStates).flatMap(_.get(channel)) match {
case Some(cs) =>
val afterWatchState = cs.afterWatch(state)
cs.callbacks.onExit()
StandardMain.exchange
.channelForName(channel)
.foreach { c =>
c.terminal.setPrompt(Prompt.Pending)
c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel))))
private[this] val exitWatchShared = (error: Boolean) =>
(channel: String, state: State) =>
state.get(watchStates).flatMap(_.get(channel)) match {
case Some(cs) =>
val afterWatchState = cs.afterWatch(state)
cs.callbacks.onExit()
StandardMain.exchange
.channelForName(channel)
.foreach { c =>
c.terminal.setPrompt(Prompt.Pending)
c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel))))
}
val newState = afterWatchState.get(watchStates) match {
case None => afterWatchState
case Some(w) => afterWatchState.put(watchStates, w - channel)
}
afterWatchState.get(watchStates) match {
case None => afterWatchState
case Some(w) => afterWatchState.put(watchStates, w - channel)
}
case _ => state
}
}
private[sbt] val failWatchCommand = watchCommand(failWatch) { (channel, state) =>
state.fail
}
val commands = cs.commands.mkString("; ")
val count = cs.count
val action = cs.failAction.getOrElse(Watch.CancelWatch)
val st = cs.callbacks.onTermination(action, commands, count, newState)
if (error) st.fail else st
case _ => if (error) state.fail else state
}
private[sbt] val stopWatchCommand = watchCommand(stopWatch)(exitWatchShared(false))
private[sbt] val failWatchCommand = watchCommand(failWatch)(exitWatchShared(true))
/*
* Creates a FileTreeRepository where it is safe to call close without inadvertently cancelling
* still active watches.

View File

@ -12,7 +12,7 @@ import java.io.File
import scala.collection.immutable.ListMap
import scala.annotation.tailrec
import scala.util.{ Try, Success, Failure }
import sbt.io.Path
import sbt.io.{ IO, Path }
import sbt.io.syntax._
import sbt.Cross._
import sbt.Def.{ ScopedKey, Setting }
@ -389,7 +389,7 @@ private[sbt] object CrossJava {
object JavaDiscoverConfig {
object JavaHomeDir {
private val regex = """(\w+-)?(java-|(?:adoptopen)?jdk-?)(bin-)?(1\.)?([0-9]+).*""".r
private val regex = """(\w+-)??(java-|(?:adoptopen)?jdk-?)?(bin-)?(1\.)?([0-9]+).*""".r
def unapply(s: CharSequence): Option[String] = {
s match {
case regex(vendor, _, _, m, n) => Some(JavaVersion(nullBlank(m) + n).toString)
@ -447,15 +447,21 @@ private[sbt] object CrossJava {
}.flatten
}
class WindowsDiscoverConfig(base: File) extends JavaDiscoverConf {
class WindowsDiscoverConfig(base: File, vendors: Seq[String] = Seq.empty)
extends JavaDiscoverConf {
def candidates() = wrapNull(base.list())
def javaHomes: Vector[(String, File)] =
candidates()
.collect {
case dir @ JavaHomeDir(version) =>
version -> (base / dir)
case dir @ JavaHomeDir(version) => version -> base / dir
}
.flatMap {
case x if vendors.isEmpty => Vector(x)
case (version, home) =>
val jv = JavaVersion(version)
vendors.map(jv.withVendor(_).toString -> home)
}
}
@ -482,10 +488,24 @@ private[sbt] object CrossJava {
new LinuxDiscoverConfig(file("/usr") / "java"),
new LinuxDiscoverConfig(file("/usr") / "lib" / "jvm"),
new MacOsDiscoverConfig,
new WindowsDiscoverConfig(file("C://Program Files/Java")),
new WindowsDiscoverConfig(file("C://Program Files (x86)/Java")),
new JavaHomeDiscoverConfig,
)
) ++ {
if (IO.isWindows) {
def discover(dir: String, vendors: String*) = new WindowsDiscoverConfig(file(dir), vendors)
Vector(
discover("C://Program Files/Java", "openjdk"),
discover("C://Program Files/Eclipse Foundation", "temurin", "adopt"),
discover("C://Program Files/Semeru", "semeru", "adopt-openj9"),
discover("C://Program Files/Microsoft", "microsoft"),
discover("C://Program Files/Amazon Corretto", "amazon-corretto"),
discover("C://Program Files/Zulu", "zulu"),
discover("C://Program Files/BellSoft", "liberica"),
discover("C://Program Files (x86)/Java", "openjdk"),
discover("C://Program Files (x86)/Eclipse Foundation", "temurin", "adopt"),
discover("C://Program Files (x86)/Semeru", "semeru", "adopt-openj9"),
)
} else Vector.empty
}
}
def nullBlank(s: String): String =

View File

@ -1,25 +0,0 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal
import sbt.internal.librarymanagement.{ CustomHttp => LMCustomHttp }
import okhttp3._
import sbt.BuildSyntax._
import sbt.KeyRanks._
object CustomHttp {
val okhttpClientBuilder =
settingKey[OkHttpClient.Builder]("Builder for the HTTP client.").withRank(CSetting)
val okhttpClient =
settingKey[OkHttpClient]("HTTP client used for library management.").withRank(CSetting)
def defaultHttpClientBuilder: OkHttpClient.Builder = {
LMCustomHttp.defaultHttpClientBuilder
}
}

View File

@ -90,7 +90,7 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
// hooks for sending start/stop events
protected def onAddJob(@deprecated("unused", "") job: JobHandle): Unit = ()
protected def onRemoveJob(@deprecated("unused", "") job: JobHandle): Unit = ()
private val context = LoggerContext(useLog4J)
private val context = LoggerContext()
// this mutable state could conceptually go on State except
// that then every task that runs a background job would have

View File

@ -25,7 +25,7 @@ private[sbt] object InstallSbtn {
Def.inputKey[Unit]("install sbtn and tab completions").withRank(KeyRanks.BTask)
private[sbt] def installSbtnImpl: Def.Initialize[InputTask[Unit]] = Def.inputTask {
val inputVersion = Def.spaceDelimited("version").parsed.headOption
val version = inputVersion.getOrElse(sbtVersion.value.replaceAllLiterally("-SNAPSHOT", ""))
val version = inputVersion.getOrElse(sbtVersion.value.replace("-SNAPSHOT", ""))
val term = terminal.value
term.setMode(canonical = false, echo = false)
val baseDirectory = BuildPaths.getGlobalBase(state.value).toPath

View File

@ -8,16 +8,15 @@
package sbt
package internal
import java.io.PrintWriter
import sbt.Def.ScopedKey
import sbt.Keys._
import sbt.Scope.Global
import sbt.SlashSyntax0._
import sbt.internal.util.MainAppender._
import sbt.internal.util.{ Terminal => ITerminal, _ }
import sbt.util.{ Level, LogExchange, Logger, LoggerContext }
import org.apache.logging.log4j.core.{ Appender => XAppender }
import sbt.util.{ Level, Logger, LoggerContext }
import java.io.PrintWriter
import scala.annotation.nowarn
sealed abstract class LogManager {
@ -88,12 +87,6 @@ object LogManager {
def defaultManager(console: ConsoleOut): LogManager =
withLoggers((_, _) => defaultScreen(console))
@deprecated(
"use defaults that takes AppenderSupplier instead of ScopedKey[_] => Seq[Appender]",
"1.4.0"
)
def defaults(extra: ScopedKey[_] => Seq[XAppender], console: ConsoleOut): LogManager =
defaults((sk: ScopedKey[_]) => extra(sk).map(new ConsoleAppenderFromLog4J("extra", _)), console)
// This is called by Defaults.
def defaults(extra: AppenderSupplier, console: ConsoleOut): LogManager =
withLoggers(
@ -298,14 +291,6 @@ object LogManager {
s1
}
@deprecated("No longer used.", "1.4.0")
private[sbt] def progressLogger(appender: ConsoleAppender): ManagedLogger = {
val log = LogExchange.logger("progress", None, None)
LoggerContext.globalContext.clearAppenders("progress")
LoggerContext.globalContext.addAppender("progress", appender -> Level.Info)
log
}
// This is the default implementation for the relay appender
val defaultRelay: Unit => ConsoleAppender = _ => defaultRelayImpl

View File

@ -139,7 +139,7 @@ object RemoteCache {
ivySbt := {
Credentials.register(credentials.value, streams.value.log)
val config0 = ivyConfiguration.value
new IvySbt(config0, sbt.internal.CustomHttp.okhttpClient.value)
new IvySbt(config0)
},
)
) ++ inTask(pullRemoteCache)(
@ -303,7 +303,8 @@ object RemoteCache {
}
found = true
case Left(e) =>
log.info(s"remote cache not found for ${v}")
val classifier = seqa.map(_.classifier).mkString(" ")
log.info(s"remote cache artifact not found for $p $classifier")
log.debug(e.getMessage)
}
}

View File

@ -12,7 +12,6 @@ import sbt.util.Show
import java.io.File
import Def.{ ScopedKey, compiled, flattenLocals }
import sbt.internal.util.Terminal
import Predef.{ any2stringadd => _, _ }
import sbt.io.IO
@ -123,10 +122,4 @@ object Graph {
toAsciiLines(top, 0, Set.empty).mkString("\n")
}
def defaultColumnSize: Int = {
val termWidth = Terminal.console.getWidth
if (termWidth > 20) termWidth - 8
else 80 // ignore termWidth
}
}

View File

@ -15,8 +15,9 @@ import scala.util.control.NonFatal
import scala.concurrent.duration._
import sbt.internal.util.{ Terminal => ITerminal, Util }
import sbt.internal.util.complete.SizeParser
import sbt.nio.Keys._
import sbt.io.syntax._
import sbt.librarymanagement.ivy.{ Credentials, FileCredentials }
import sbt.nio.Keys._
// See also BuildPaths.scala
// See also LineReader.scala
@ -216,4 +217,7 @@ object SysProp {
.getOrElse(linuxCache)
baseCache.getAbsoluteFile / "v1"
}
lazy val sbtCredentialsEnv: Option[Credentials] =
sys.env.get("SBT_CREDENTIALS").map(raw => new FileCredentials(new File(raw)))
}

View File

@ -70,8 +70,9 @@ private[sbt] class TaskProgress(
pending.clear()
scheduler.shutdownNow()
executor.shutdownNow()
if (!executor.awaitTermination(1, TimeUnit.SECONDS) ||
!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
if (!executor.awaitTermination(30, TimeUnit.SECONDS) ||
!scheduler.awaitTermination(30, TimeUnit.SECONDS)) {
scala.Console.err.println("timed out closing the executor of supershell")
throw new TimeoutException
}
}

View File

@ -13,7 +13,7 @@ package rendering
import sbt.internal.util.Terminal.red
object AsciiTree {
def asciiTree(graph: ModuleGraph): String = {
def asciiTree(graph: ModuleGraph, graphWidth: Int): String = {
val deps = graph.dependencyMap
// there should only be one root node (the project itself)
@ -25,7 +25,7 @@ object AsciiTree {
root,
node => deps.getOrElse(node.id, Seq.empty[Module]),
displayModule,
Graph.defaultColumnSize
graphWidth
)
}
.mkString("\n")
@ -36,7 +36,7 @@ object AsciiTree {
module.id.idString +
module.extraInfo +
module.error.map(" (error: " + _ + ")").getOrElse("") +
module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""),
module.evictedByVersion.map(v => s" (evicted by: $v)").getOrElse(""),
module.hadError
)
}

View File

@ -25,7 +25,7 @@ object DagreHTML {
val graphString =
URLEncoder
.encode(dotGraph, "utf8")
.replaceAllLiterally("+", "%20")
.replace("+", "%20")
IO.write(
new File(targetDirectory, "dependencies.dot.js"),

View File

@ -20,7 +20,7 @@ object LicenseInfo {
.map {
case (license, modules) =>
license.getOrElse("No license specified") + "\n" +
modules.map(_.id.idString formatted "\t %s").mkString("\n")
modules.map(m => s"\t ${m.id.idString}").mkString("\n")
}
.mkString("\n\n")
}

View File

@ -10,21 +10,20 @@ package internal
package graph
package rendering
import java.io.{ OutputStream, InputStream, FileOutputStream, File }
import java.net.URI
import graph.{ Module, ModuleGraph }
import sbt.internal.graph.codec.JsonProtocol.ModuleModelFormat
import sbt.io.IO
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
import java.io.{ File, FileOutputStream, InputStream, OutputStream }
import java.net.URI
import scala.annotation.{ nowarn, tailrec }
import scala.util.parsing.json.{ JSONArray, JSONObject }
@nowarn object TreeView {
def createJson(graph: ModuleGraph): String = {
val trees = graph.roots
val moduleModels = graph.roots
.map(module => processSubtree(graph, module))
.toList
JSONArray(trees).toString
val js = moduleModels.map(Converter.toJsonUnsafe(_))
js.map(CompactPrinter).mkString("[", ",", "]")
}
def createLink(graphJson: String, targetDirectory: File): URI = {
@ -36,19 +35,30 @@ import scala.util.parsing.json.{ JSONArray, JSONObject }
new URI(graphHTML.toURI.toString)
}
private def processSubtree(graph: ModuleGraph, module: Module): JSONObject = {
val children = graph.dependencyMap
.getOrElse(module.id, List())
.map(module => processSubtree(graph, module))
.toList
moduleAsJson(module, children)
private[rendering] def processSubtree(
graph: ModuleGraph,
module: Module,
parents: Set[GraphModuleId] = Set()
): ModuleModel = {
val cycle = parents.contains(module.id)
val dependencies = if (cycle) List() else graph.dependencyMap.getOrElse(module.id, List())
val children =
dependencies
.map(dependency => processSubtree(graph, dependency, parents + module.id))
.toVector
moduleAsModuleAgain(module, cycle, children)
}
private def moduleAsJson(module: Module, children: List[JSONObject]): JSONObject = {
private def moduleAsModuleAgain(
module: Module,
isCycle: Boolean,
children: Vector[ModuleModel]
): ModuleModel = {
val eviction = module.evictedByVersion.map(version => s" (evicted by $version)").getOrElse("")
val cycle = if (isCycle) " (cycle)" else ""
val error = module.error.map(err => s" (errors: $err)").getOrElse("")
val text = module.id.idString + eviction + error
JSONObject(Map("text" -> text, "children" -> JSONArray(children)))
val text = module.id.idString + eviction + error + cycle
ModuleModel(text, children)
}
def saveResource(resourcePath: String, to: File): Unit = {

View File

@ -32,13 +32,16 @@ import sjsonnew.shaded.scalajson.ast.unsafe.{ JNull, JValue }
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter, Parser => JsonParser }
import xsbti.CompileFailed
import java.nio.file.Path
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean
import scala.collection.mutable
// import scala.annotation.nowarn
import scala.util.control.NonFatal
import scala.util.{ Failure, Success, Try }
import scala.annotation.nowarn
import sbt.testing.Framework
object BuildServerProtocol {
import sbt.internal.bsp.codec.JsonProtocol._
@ -49,7 +52,9 @@ object BuildServerProtocol {
RunProvider(BuildServerConnection.languages),
dependencySourcesProvider = true,
resourcesProvider = true,
canReload = true
canReload = true,
jvmRunEnvironmentProvider = true,
jvmTestEnvironmentProvider = true,
)
private val bspReload = "bspReload"
@ -103,11 +108,7 @@ object BuildServerProtocol {
}
}.value,
// https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
bspBuildTargetSources := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspBuildTargetSources := bspInputTask { (state, _, workspace, filter) =>
// run the worker task concurrently
Def.task {
val items = bspBuildTargetSourcesItem.result.all(filter).value
@ -116,82 +117,63 @@ object BuildServerProtocol {
val base = loadedBuildUnit.localBase
val sbtFiles = configurationSources(base)
val pluginData = loadedBuildUnit.unit.plugins.pluginData
val all = Vector.newBuilder[SourceItem]
def add(fs: Seq[File], sourceItemKind: Int, generated: Boolean): Unit = {
fs.foreach(f => all += (SourceItem(f.toURI, sourceItemKind, generated = generated)))
}
all += (SourceItem(
loadedBuildUnit.unit.plugins.base.toURI,
SourceItemKind.Directory,
generated = false
))
add(pluginData.unmanagedSourceDirectories, SourceItemKind.Directory, generated = false)
add(pluginData.unmanagedSources, SourceItemKind.File, generated = false)
add(pluginData.managedSourceDirectories, SourceItemKind.Directory, generated = true)
add(pluginData.managedSources, SourceItemKind.File, generated = true)
add(sbtFiles, SourceItemKind.File, generated = false)
Value(SourcesItem(id, all.result()))
val dirs = pluginData.unmanagedSourceDirectories
val sourceFiles = getStandaloneSourceFiles(pluginData.unmanagedSources, dirs)
val managedDirs = pluginData.managedSourceDirectories
val managedSourceFiles =
getStandaloneSourceFiles(pluginData.managedSources, managedDirs)
val items =
dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++
sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++
managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++
managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true)) ++
sbtFiles.map(toSourceItem(SourceItemKind.File, generated = false))
Value(SourcesItem(id, items.toVector))
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = SourcesResult(successfulItems.toVector)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspBuildTargetSources / aggregate := false,
bspBuildTargetResources := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
workspace.warnIfBuildsNonEmpty(Method.Resources, s.log)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspBuildTargetResources := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.Resources, state.log)
// run the worker task concurrently
Def.task {
val items = bspBuildTargetResourcesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = ResourcesResult(successfulItems.toVector)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspBuildTargetResources / aggregate := false,
bspBuildTargetDependencySources := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspBuildTargetDependencySources := bspInputTask { (state, _, workspace, filter) =>
// run the worker task concurrently
Def.task {
import sbt.internal.bsp.codec.JsonProtocol._
val items = bspBuildTargetDependencySourcesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = DependencySourcesResult(successfulItems.toVector)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspBuildTargetDependencySources / aggregate := false,
bspBuildTargetCompile := Def.inputTaskDyn {
val s: State = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
workspace.warnIfBuildsNonEmpty(Method.Compile, s.log)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspBuildTargetCompile := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.Compile, state.log)
Def.task {
val statusCodes = Keys.bspBuildTargetCompileItem.result.all(filter).value
val aggregatedStatusCode = allOrThrow(statusCodes) match {
case Seq() => StatusCode.Success
case codes => codes.max
}
s.respondEvent(BspCompileResult(None, aggregatedStatusCode))
state.respondEvent(BspCompileResult(None, aggregatedStatusCode))
}
}.evaluated,
bspBuildTargetCompile / aggregate := false,
bspBuildTargetTest := bspTestTask.evaluated,
bspBuildTargetTest / aggregate := false,
bspBuildTargetCleanCache := Def.inputTaskDyn {
val s: State = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
workspace.warnIfBuildsNonEmpty(Method.CleanCache, s.log)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspBuildTargetCleanCache := bspInputTask { (state, targets, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.CleanCache, state.log)
Def.task {
val results = Keys.clean.result.all(filter).value
val successes = anyOrThrow(results).size
@ -201,18 +183,12 @@ object BuildServerProtocol {
// checking that the executed results plus this entry is equal to the total number of targets.
// When rebuilding a single module, the root build isn't sent, just the requested targets.
val cleaned = successes + workspace.builds.size == targets.size
s.respondEvent(CleanCacheResult(None, cleaned))
state.respondEvent(CleanCacheResult(None, cleaned))
}
}.evaluated,
bspBuildTargetCleanCache / aggregate := false,
bspBuildTargetScalacOptions := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
bspBuildTargetScalacOptions := bspInputTask { (state, _, workspace, filter) =>
val builds = workspace.builds
val filter = ScopeFilter.in(workspace.scopes.values.toList)
Def.task {
val items = bspBuildTargetScalacOptionsItem.result.all(filter).value
val appProvider = appConfiguration.value.provider()
@ -233,34 +209,26 @@ object BuildServerProtocol {
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = ScalacOptionsResult(successfulItems.toVector)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspBuildTargetScalacOptions / aggregate := false,
bspScalaTestClasses := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, s.log)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log)
Def.task {
val items = bspScalaTestClassesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val successfulItems = anyOrThrow(items).flatten.toVector
val result = ScalaTestClassesResult(successfulItems.toVector, None)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspScalaMainClasses := Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace = bspFullWorkspace.value.filter(targets)
workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, s.log)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
bspScalaMainClasses := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, state.log)
Def.task {
val items = bspScalaMainClassesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val result = ScalaMainClassesResult(successfulItems.toVector, None)
s.respondEvent(result)
state.respondEvent(result)
}
}.evaluated,
bspScalaMainClasses / aggregate := false
@ -277,14 +245,14 @@ object BuildServerProtocol {
bspBuildTargetSourcesItem := {
val id = bspTargetIdentifier.value
val dirs = unmanagedSourceDirectories.value
val managed = managedSources.value
val items = (dirs.toVector map { dir =>
SourceItem(dir.toURI, SourceItemKind.Directory, generated = false)
}) ++
(managed.toVector map { x =>
SourceItem(x.toURI, SourceItemKind.File, generated = true)
})
SourcesItem(id, items)
val sourceFiles = getStandaloneSourceFiles(unmanagedSources.value, dirs)
val managedDirs = managedSourceDirectories.value
val managedSourceFiles = getStandaloneSourceFiles(managedSources.value, managedDirs)
val items = dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++
sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++
managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++
managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true))
SourcesItem(id, items.toVector)
},
bspBuildTargetResourcesItem := {
val id = bspTargetIdentifier.value
@ -302,17 +270,42 @@ object BuildServerProtocol {
bspBuildTargetCompileItem := bspCompileTask.value,
bspBuildTargetRun := bspRunTask.evaluated,
bspBuildTargetScalacOptionsItem := scalacOptionsTask.value,
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)
}
}.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)
}
}.evaluated,
bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value,
bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value,
bspScalaTestClassesItem := scalaTestClassesTask.value,
bspScalaMainClassesItem := scalaMainClassesTask.value,
Keys.compile / bspReporter := {
val targetId = bspTargetIdentifier.value
val bspCompileStateInstance = bspCompileState.value
val converter = fileConverter.value
val underlying = (Keys.compile / compilerReporter).value
val logger = streams.value.log
val meta = isMetaBuild.value
if (bspEnabled.value) {
new BuildServerReporterImpl(targetId, converter, meta, logger, underlying)
new BuildServerReporterImpl(
targetId,
bspCompileStateInstance,
converter,
meta,
logger,
underlying
)
} else {
new BuildServerForwarder(meta, logger, underlying)
}
@ -331,6 +324,8 @@ object BuildServerProtocol {
final val Run = "buildTarget/run"
final val CleanCache = "buildTarget/cleanCache"
final val ScalacOptions = "buildTarget/scalacOptions"
final val JvmRunEnvironment = "buildTarget/jvmRunEnvironment"
final val JvmTestEnvironment = "buildTarget/jvmTestEnvironment"
final val ScalaTestClasses = "buildTarget/scalaTestClasses"
final val ScalaMainClasses = "buildTarget/scalaMainClasses"
final val Exit = "build/exit"
@ -429,6 +424,18 @@ object BuildServerProtocol {
val command = Keys.bspBuildTargetScalacOptions.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.JvmRunEnvironment =>
val param = Converter.fromJson[JvmRunEnvironmentParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
val command = Keys.bspBuildTargetJVMRunEnvironment.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.JvmTestEnvironment =>
val param = Converter.fromJson[JvmTestEnvironmentParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
val command = Keys.bspBuildTargetJVMTestEnvironment.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.ScalaTestClasses =>
val param = Converter.fromJson[ScalaTestClassesParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
@ -456,6 +463,18 @@ object BuildServerProtocol {
}
}
private def getStandaloneSourceFiles(
sourceFiles: Seq[File],
sourceDirs: Seq[File]
): Seq[File] = {
sourceFiles.filterNot { f =>
sourceDirs.exists(dir => f.toPath.startsWith(dir.toPath))
}
}
private def toSourceItem(itemKind: Int, generated: Boolean)(file: File): SourceItem =
SourceItem(file.toURI, itemKind, generated)
private def checkMetalsCompatibility(
semanticdbEnabled: Boolean,
semanticdbVersion: String,
@ -622,6 +641,38 @@ object BuildServerProtocol {
)
}
private def bspInputTask[T](
taskImpl: (
State,
Seq[BuildTargetIdentifier],
BspFullWorkspace,
ScopeFilter
) => Def.Initialize[Task[T]]
): Def.Initialize[InputTask[T]] =
Def.inputTaskDyn {
val s = state.value
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
val workspace: BspFullWorkspace = bspFullWorkspace.value.filter(targets)
val filter = ScopeFilter.in(workspace.scopes.values.toList)
taskImpl(s, targets, workspace, filter)
}
private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.task {
val target = Keys.bspTargetIdentifier.value
val classpath = Keys.fullClasspath.value.map(_.data.toURI).toVector
val jvmOptions = Keys.javaOptions.value.toVector
val baseDir = Keys.baseDirectory.value.toURI().toString()
val env = envVars.value
JvmEnvironmentItem(
target,
classpath,
jvmOptions,
baseDir,
env
)
}
private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn {
val target = Keys.bspTargetIdentifier.value
val scalacOptions = Keys.scalacOptions.value
@ -657,6 +708,10 @@ object BuildServerProtocol {
DependencySourcesItem(targetId, sources.toVector.distinct)
}
private def bspCompileState: Initialize[BuildServerProtocol.BspCompileState] = Def.setting {
new BuildServerProtocol.BspCompileState()
}
private def bspCompileTask: Def.Initialize[Task[Int]] = Def.task {
Keys.compile.result.value match {
case Value(_) => StatusCode.Success
@ -831,15 +886,25 @@ object BuildServerProtocol {
}
}
private def scalaTestClassesTask: Initialize[Task[ScalaTestClassesItem]] = Def.task {
val testClasses = Keys.definedTests.?.value
.getOrElse(Seq.empty)
.map(_.name)
.toVector
ScalaTestClassesItem(
bspTargetIdentifier.value,
testClasses
)
private def scalaTestClassesTask: Initialize[Task[Seq[ScalaTestClassesItem]]] = Def.task {
Keys.definedTests.?.value match {
case None => Vector.empty
case Some(definitions) =>
val frameworks: Seq[Framework] = Keys.loadedTestFrameworks.?.value
.map(_.values.toSeq)
.getOrElse(Seq.empty)
val grouped = TestFramework.testMap(frameworks, definitions)
grouped.map {
case (framework, definitions) =>
ScalaTestClassesItem(
bspTargetIdentifier.value,
definitions.map(_.name).toVector,
framework.name()
)
}.toSeq
}
}
private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task {
@ -933,4 +998,20 @@ object BuildServerProtocol {
)
}
}
/**
* Additional information about compilation status for given build target.
*
* @param hasAnyProblems keeps track of problems in given file so BSP reporter
* can omit unnecessary diagnostics updates.
* @param compiledAtLeastOnce keeps track of those projects that were compiled at
* least once so that we can decide to enable fresh reporting for projects that
* are compiled for the first time.
* see: https://github.com/scalacenter/bloop/issues/726
*/
private[server] final class BspCompileState {
val hasAnyProblems: java.util.Set[Path] =
java.util.concurrent.ConcurrentHashMap.newKeySet[Path]
val compiledAtLeastOnce: AtomicBoolean = new AtomicBoolean(false)
}
}

Some files were not shown because too many files have changed in this diff Show More