From 89ff2440ef1f90e4de8bd2511ba4138d8a080d84 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 15 Mar 2025 21:08:12 -0400 Subject: [PATCH 01/12] fix: Avoid creating target on sbt -V **Problem** sbt -V tries to show both the sbt version and the runner version, and ends up creating target directory even on a non-sbt directory. **Solution** If the current directory doesn't have a build, just display the runner version. --- .../src/test/scala/RunnerTest.scala | 27 ++++++++++++++----- launcher-package/src/universal/bin/sbt.bat | 23 ++++++++++++---- sbt | 19 ++++++++++--- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/launcher-package/integration-test/src/test/scala/RunnerTest.scala b/launcher-package/integration-test/src/test/scala/RunnerTest.scala index 382b259d7..4ea58563b 100755 --- a/launcher-package/integration-test/src/test/scala/RunnerTest.scala +++ b/launcher-package/integration-test/src/test/scala/RunnerTest.scala @@ -33,19 +33,32 @@ object SbtRunnerTest extends SimpleTestSuite with PowerAssertions { () } + def testVersion(lines: List[String]): Unit = { + assert(lines.size >= 2) + val expected0 = s"(?m)^sbt version in this project: $versionRegEx(\\r)?" + assert(lines(0).matches(expected0)) + val expected1 = s"sbt runner version: $versionRegEx$$" + assert(lines(1).matches(expected1)) + } + test("sbt -V|-version|--version should print sbtVersion") { val out = sbtProcess("-version").!!.trim - val expectedVersion = - s"""|(?m)^sbt version in this project: $versionRegEx(\\r)? - |sbt script version: $versionRegEx$$ - |""".stripMargin.trim.replace("\n", "\\n") - assert(out.matches(expectedVersion)) + testVersion(out.linesIterator.toList) val out2 = sbtProcess("--version").!!.trim - assert(out2.matches(expectedVersion)) + testVersion(out2.linesIterator.toList) val out3 = sbtProcess("-V").!!.trim - assert(out3.matches(expectedVersion)) + testVersion(out3.linesIterator.toList) + } + + test("sbt -V in empty directory") { + IO.withTemporaryDirectory { tmp => + val out = sbtProcessInDir(tmp)("-V").!!.trim + val expectedVersion = "^"+versionRegEx+"$" + val targetDir = new File(tmp, "target") + assert(!targetDir.exists, "expected target directory to not exist, but existed") + } () } diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index 3de1fbd88..983b618a7 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -51,6 +51,7 @@ set sbt_args_sbt_version= set sbt_args_mem= set sbt_args_client= set sbt_args_no_server= +set is_this_dir_sbt=0 rem users can set SBT_OPTS via .sbtopts if exist .sbtopts for /F %%A in (.sbtopts) do ( @@ -532,11 +533,18 @@ set SBT_ARGS=!SBT_ARGS! %0 goto args_loop :args_end +if exist build.sbt ( + set is_this_dir_sbt=1 +) +if exist project\build.properties ( + set is_this_dir_sbt=1 +) + 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_allow_empty 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_args_allow_empty 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 !is_this_dir_sbt! equ 1 ( if not defined sbt_new ( echo [error] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" echo [error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'. @@ -667,9 +675,14 @@ if !sbt_args_print_sbt_version! equ 1 ( ) if !sbt_args_print_version! equ 1 ( - call :set_sbt_version - echo sbt version in this project: !sbt_version! - echo sbt script version: !init_sbt_version! + if !is_this_dir_sbt! equ 1 ( + call :set_sbt_version + echo sbt version in this project: !sbt_version! + ) + echo sbt runner version: !init_sbt_version! + echo. + echo [info] sbt runner ^(sbt-the-batch-script^) is a runner to run any declared version of sbt. + echo [info] Actual version of the sbt is declared using project\build.properties for each build. goto :eof ) diff --git a/sbt b/sbt index c8176a38f..6427f287d 100755 --- a/sbt +++ b/sbt @@ -26,6 +26,7 @@ declare no_server= declare sbtn_command="$SBTN_CMD" declare sbtn_version="1.10.8" declare use_colors=1 +declare is_this_dir_sbt="" ### ------------------------------- ### ### Helper methods for BASH scripts ### @@ -494,11 +495,17 @@ copyRt() { fi } +detect_working_directory() { + if [[ -f ./build.sbt || -f ./project/build.properties ]]; then + is_this_dir_sbt=1 + fi +} + # Confirm a user's intent if the current directory does not look like an sbt # top-level directory and neither the --allow-empty option nor the "new" command was given. checkWorkingDirectory() { if [[ ! -n "$allow_empty" ]]; then - [[ -f ./build.sbt || -d ./project || -n "$sbt_new" ]] || { + [[ -n "$is_this_dir_sbt" || -n "$sbt_new" ]] || { echoerr_error "Neither build.sbt nor a 'project' directory in the current directory: $(pwd)" echoerr_error "run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'." echoerr_error "" @@ -531,13 +538,19 @@ run() { addJava "-Dsbt.cygwin=true" fi + detect_working_directory if [[ $print_sbt_version ]]; then execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]//g' elif [[ $print_sbt_script_version ]]; then echo "$init_sbt_version" elif [[ $print_version ]]; then - execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]/sbt version in this project:/g' - echo "sbt script version: $init_sbt_version" + if [[ -n "$is_this_dir_sbt" ]]; then + execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]/sbt version in this project:/g' + fi + echo "sbt runner version: $init_sbt_version" + echoerr "" + echoerr "[info] sbt runner (sbt-the-shell-script) is a runner to run any declared version of sbt." + echoerr "[info] Actual version of the sbt is declared using project/build.properties for each build." elif [[ $shutdownall ]]; then local sbt_processes=( $(jps -v | grep sbt-launch | cut -f1 -d ' ') ) for procId in "${sbt_processes[@]}"; do From bd7bf73de5611aadd2ba727e54150b5e48130133 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 16 Mar 2025 14:58:23 -0400 Subject: [PATCH 02/12] fix: Fix SIP-51 message **Problem** The error message uses name, which may not match the actual project id that the user can type into the shell. **Solution** Use displayBuildRelative to calculate the proper subproject id. --- main/src/main/scala/sbt/Defaults.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 0b54ba2e5..dbbbe84b1 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1213,7 +1213,7 @@ object Defaults extends BuildCommon { for (lib <- scalaDeps.take(1)) { val libVer = lib.module.revision val libName = lib.module.name - val n = name.value + val proj = Def.displayBuildRelative(thisProjectRef.value.build, thisProjectRef.value) if (VersionNumber(sv).matchesSemVer(SemanticSelector(s"<$libVer"))) { val err = !allowUnsafeScalaLibUpgrade.value val fix = @@ -1227,13 +1227,13 @@ object Defaults extends BuildCommon { |Compilation (macro expansion) or using the Scala REPL in sbt may fail with a LinkageError.""".stripMargin val msg = - s"""Expected `$n/scalaVersion` to be $libVer or later, but found $sv. + s"""Expected `$proj scalaVersion` to be $libVer or later, but found $sv. |To support backwards-only binary compatibility (SIP-51), the Scala 2.13 compiler |should not be older than $libName on the dependency classpath. | |$fix | - |See `$n/evicted` to know why $libName $libVer is getting pulled in. + |See `$proj evicted` to know why $libName $libVer is getting pulled in. |""".stripMargin if (err) sys.error(msg) else s.log.warn(msg) From 0e1088145a7daa27ff28688dd66515c8742e1ad4 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 16 Mar 2025 19:53:50 -0400 Subject: [PATCH 03/12] Update lm-coursier-shaded to 2.1.8 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8e040b7e5..8831a5d4c 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -77,7 +77,7 @@ object Dependencies { def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompile", zincCompile) def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCore", zincCompileCore) - val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.1.7" + val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.1.8" def sjsonNew(n: String) = Def.setting("com.eed3si9n" %% n % "0.10.1") // contrabandSjsonNewVersion.value From 12d2cc8ef1f3dc11899baac70f4bc918e925edc3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 16 Mar 2025 21:43:01 -0400 Subject: [PATCH 04/12] fix: Use Retry.io for compilation **Problem** sbt 1.10.10 still has retry problem with compilation. **Solution** Revert the retry logic back to the time when we only retried IOExceptions. --- main/src/main/scala/sbt/internal/server/BspCompileTask.scala | 3 +-- project/Dependencies.scala | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BspCompileTask.scala b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala index ed784f244..b2aed4e55 100644 --- a/main/src/main/scala/sbt/internal/server/BspCompileTask.scala +++ b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala @@ -16,7 +16,6 @@ import sbt.internal.server.BspCompileTask.exchange import sbt.librarymanagement.Configuration import sbt.util.InterfaceUtil import sjsonnew.support.scalajson.unsafe.Converter -import xsbti.CompileCancelled import xsbti.CompileFailed import xsbti.Problem import xsbti.Severity @@ -39,7 +38,7 @@ object BspCompileTask { val task = BspCompileTask(targetId, project, config, ci) try { task.notifyStart() - val result = Retry(compile(task), classOf[CompileCancelled], classOf[CompileFailed]) + val result = Retry.io(compile(task)) task.notifySuccess(result) result } catch { diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8831a5d4c..f3ef989a2 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,7 +12,7 @@ object Dependencies { sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version") // sbt modules - private val ioVersion = nightlyVersion.getOrElse("1.10.4") + private val ioVersion = nightlyVersion.getOrElse("1.10.5") private val lmVersion = sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.10.4") val zincVersion = nightlyVersion.getOrElse("1.10.8") From ff4825ccffa237a575ab3c9d7afe59b245b4d4e0 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 16 Mar 2025 22:33:53 -0400 Subject: [PATCH 05/12] fix: Fix sbt --client on Windows **Problem** sbt --client doens't work on Windows because the runner script passes itself to the server, but it's unable to launch Bash script. **Solution** Pass in the bat version instead on Windows. --- .github/workflows/ci.yml | 6 +++++- sbt | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbc83f1d7..88c47b39e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,7 +161,8 @@ jobs: # test building sbtn on Linux sbt "-Dsbt.io.virtual=false" nativeImage # smoke test native Image - ./client/target/bin/sbtn shutdown + ./client/target/bin/sbtn --sbt-script=$(pwd)/sbt about + ./client/target/bin/sbtn --sbt-script=$(pwd)/sbt shutdown # test launcher script echo build using JDK 8 test using JDK 8 and JDK 11 cd launcher-package @@ -189,6 +190,9 @@ jobs: run: | # test building sbtn on Windows sbt "-Dsbt.io.virtual=false" nativeImage + # smoke test native Image + ./client/target/bin/sbtn --sbt-script=$(pwd)/launcher-package/src/universal/bin/sbt.bat about + ./client/target/bin/sbtn --sbt-script=$(pwd)/launcher-package/src/universal/bin/sbt.bat shutdown # test launcher script echo build using JDK 8, test using JDK 8, on Windows cd launcher-package diff --git a/sbt b/sbt index 6427f287d..5eff91e6d 100755 --- a/sbt +++ b/sbt @@ -805,7 +805,12 @@ runNativeClient() { unset 'original_args[i]' fi done - sbt_script=$0 + + if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then + sbt_script="$0.bat" + else + sbt_script="$0" + fi sbt_script=${sbt_script/ /%20} execRunner "$sbtn_command" "--sbt-script=$sbt_script" "${original_args[@]}" } From 898d9f66d38d3ec7eb6d7568ea7eab2a163b47f5 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 17 Mar 2025 01:26:22 -0400 Subject: [PATCH 06/12] sbt 1.10.11 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index 5eff91e6d..217be39ec 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.10.10" +declare builtin_sbt_version="1.10.11" declare -a residual_args declare -a java_args declare -a scalac_args From af714b8318c75112de006bae6279ac9806772f29 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 25 Mar 2025 00:33:42 -0400 Subject: [PATCH 07/12] fix: Avoid printing to stdout **Problem** The runner script prints out "copying runtime jar" etc to stdout. **Solution** This removes the log, and moves other logs to stderr. --- launcher-package/src/universal/bin/sbt.bat | 28 ++++++++--------- sbt | 35 +++++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index 983b618a7..fc4986e0b 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -546,8 +546,8 @@ rem top-level directory and the "new" command was not given. if not defined sbt_args_allow_empty 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 !is_this_dir_sbt! equ 1 ( if not defined sbt_new ( - echo [error] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" - echo [error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'. + >&2 echo [error] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" + >&2 echo [error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'. goto error ) ) @@ -563,7 +563,7 @@ if !shutdownall! equ 1 ( taskkill /F /PID %%i set /a count=!count!+1 ) - echo shutdown !count! sbt processes + >&2 echo shutdown !count! sbt processes goto :eof ) @@ -680,9 +680,9 @@ if !sbt_args_print_version! equ 1 ( echo sbt version in this project: !sbt_version! ) echo sbt runner version: !init_sbt_version! - echo. - echo [info] sbt runner ^(sbt-the-batch-script^) is a runner to run any declared version of sbt. - echo [info] Actual version of the sbt is declared using project\build.properties for each build. + >&2 echo. + >&2 echo [info] sbt runner ^(sbt-the-batch-script^) is a runner to run any declared version of sbt. + >&2 echo [info] Actual version of the sbt is declared using project\build.properties for each build. goto :eof ) @@ -923,14 +923,14 @@ set /a required_version=8 if /I !JAVA_VERSION! GEQ !required_version! ( exit /B 0 ) -echo. -echo The Java Development Kit ^(JDK^) installation you have is not up to date. -echo sbt requires at least version !required_version!+, you have -echo version "!JAVA_VERSION!" -echo. -echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download -echo a valid JDK and install before running sbt. -echo. +>&2 echo. +>&2 echo The Java Development Kit ^(JDK^) installation you have is not up to date. +>&2 echo sbt requires at least version !required_version!+, you have +>&2 echo version "!JAVA_VERSION!" +>&2 echo. +>&2 echo Go to https://adoptium.net/ etc and download +>&2 echo a valid JDK and install before running sbt. +>&2 echo. exit /B 1 :copyrt diff --git a/sbt b/sbt index 217be39ec..d5312ce35 100755 --- a/sbt +++ b/sbt @@ -161,7 +161,7 @@ acquire_sbt_jar () { sbt_jar="$download_jar" else sbt_url=$(jar_url "$launcher_sv") - echoerr "downloading sbt launcher $launcher_sv" + dlog "downloading sbt launcher $launcher_sv" download_url "$sbt_url" "${download_jar}.temp" download_url "${sbt_url}.sha1" "${download_jar}.sha1" if command -v shasum > /dev/null; then @@ -197,7 +197,7 @@ acquire_sbtn () { archive_target="$p/sbtn-${arch}-pc-linux-${sbtn_v}.tar.gz" url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-${arch}-pc-linux-${sbtn_v}.tar.gz" else - echoerr "sbtn is not supported on $arch" + echoerr_error "sbtn is not supported on $arch" exit 2 fi elif [[ "$OSTYPE" == "darwin"* ]]; then @@ -209,14 +209,14 @@ acquire_sbtn () { archive_target="$p/sbtn-x86_64-pc-win32-${sbtn_v}.zip" url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-x86_64-pc-win32-${sbtn_v}.zip" else - echoerr "sbtn is not supported on $OSTYPE" + echoerr_error "sbtn is not supported on $OSTYPE" exit 2 fi if [[ -f "$target" ]]; then sbtn_command="$target" else - echoerr "downloading sbtn ${sbtn_v} for ${arch}" + dlog "downloading sbtn ${sbtn_v} for ${arch}" download_url "$url" "$archive_target" if [[ "$OSTYPE" == "linux-gnu"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then tar zxf "$archive_target" --directory "$p" @@ -351,7 +351,7 @@ require_arg () { local opt="$2" local arg="$3" if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - echo "$opt requires <$type> argument" + echoerr "$opt requires <$type> argument" exit 1 fi } @@ -455,19 +455,19 @@ checkJava() { # Now check to see if it's a good enough version local good_enough="$(expr $java_version ">=" $required_version)" if [[ "$java_version" == "" ]]; then - echo - echo "No Java Development Kit (JDK) installation was detected." - echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download. - echo + echoerr + echoerr "No Java Development Kit (JDK) installation was detected." + echoerr Go to https://adoptium.net/ etc and download. + echoerr exit 1 elif [[ "$good_enough" != "1" ]]; then - echo - echo "The Java Development Kit (JDK) installation you have is not up to date." - echo $script_name requires at least version $required_version+, you have - echo version $java_version - echo - echo Please go to http://www.oracle.com/technetwork/java/javase/downloads/ and download - echo a valid JDK and install before running $script_name. + echoerr + echoerr "The Java Development Kit (JDK) installation you have is not up to date." + echoerr $script_name requires at least version $required_version+, you have + echoerr version $java_version + echoerr + echoerr Go to https://adoptium.net/ etc and download + echoerr a valid JDK and install before running $script_name. echo exit 1 fi @@ -482,7 +482,6 @@ copyRt() { java9_rt=$(echo "$java9_ext/rt.jar") vlog "[copyRt] java9_rt = '$java9_rt'" if [[ ! -f "$java9_rt" ]]; then - echo copying runtime jar... mkdir -p "$java9_ext" "$java_cmd" \ "${sbt_options[@]}" \ @@ -556,7 +555,7 @@ run() { for procId in "${sbt_processes[@]}"; do kill -9 $procId done - echo "shutdown ${#sbt_processes[@]} sbt processes" + echoerr "shutdown ${#sbt_processes[@]} sbt processes" else checkWorkingDirectory # run sbt From 4d583fa19ea0679db6c2c2a6ac9201440d3fa7fd Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 23 Mar 2025 22:21:06 -0400 Subject: [PATCH 08/12] Split test-quick test into two [merge-skip] --- .../tests/incremental-object-sources/build.sbt | 10 ++++++++++ .../changed/MathFunction.scala | 0 .../src/main/scala/MathFunction.scala | 0 .../src/test/scala/MathFunctionSpec.scala | 0 .../src/sbt-test/tests/incremental-object-sources/test | 8 ++++++++ .../tests/{test-quick => incremental}/build.sbt | 0 .../tests/{test-quick => incremental}/changed/A.scala | 0 .../tests/{test-quick => incremental}/changed/B.scala | 0 .../{test-quick => incremental}/changed/Base.scala | 0 .../{test-quick => incremental}/src/main/scala/A.scala | 0 .../{test-quick => incremental}/src/main/scala/B.scala | 0 .../src/test/scala/Base.scala | 0 .../src/test/scala/Create.scala | 0 .../src/test/scala/Delete.scala | 0 .../sbt-test/tests/{test-quick => incremental}/test | 8 +------- 15 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-sources/build.sbt rename sbt-app/src/sbt-test/tests/{test-quick => incremental-object-sources}/changed/MathFunction.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental-object-sources}/src/main/scala/MathFunction.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental-object-sources}/src/test/scala/MathFunctionSpec.scala (100%) create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-sources/test rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/build.sbt (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/changed/A.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/changed/B.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/changed/Base.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/src/main/scala/A.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/src/main/scala/B.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/src/test/scala/Base.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/src/test/scala/Create.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/src/test/scala/Delete.scala (100%) rename sbt-app/src/sbt-test/tests/{test-quick => incremental}/test (80%) diff --git a/sbt-app/src/sbt-test/tests/incremental-object-sources/build.sbt b/sbt-app/src/sbt-test/tests/incremental-object-sources/build.sbt new file mode 100644 index 000000000..5d582f237 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-sources/build.sbt @@ -0,0 +1,10 @@ +// Global / cacheStores := Seq.empty + +val scalatest = "org.scalatest" %% "scalatest" % "3.0.5" +scalaVersion := "2.12.20" + +lazy val root = (project in file(".")) + .settings( + libraryDependencies += scalatest % Test, + Test / parallelExecution := false + ) diff --git a/sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala b/sbt-app/src/sbt-test/tests/incremental-object-sources/changed/MathFunction.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala rename to sbt-app/src/sbt-test/tests/incremental-object-sources/changed/MathFunction.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala b/sbt-app/src/sbt-test/tests/incremental-object-sources/src/main/scala/MathFunction.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala rename to sbt-app/src/sbt-test/tests/incremental-object-sources/src/main/scala/MathFunction.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala b/sbt-app/src/sbt-test/tests/incremental-object-sources/src/test/scala/MathFunctionSpec.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala rename to sbt-app/src/sbt-test/tests/incremental-object-sources/src/test/scala/MathFunctionSpec.scala diff --git a/sbt-app/src/sbt-test/tests/incremental-object-sources/test b/sbt-app/src/sbt-test/tests/incremental-object-sources/test new file mode 100644 index 000000000..b6c0cee18 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-sources/test @@ -0,0 +1,8 @@ +> testQuick + +# https://github.com/sbt/sbt/issues/5504 +$ copy-file changed/MathFunction.scala src/test/scala/MathFunction.scala +> compile +$ sleep 2000 +> debug +-> testQuick MathFunctionTest diff --git a/sbt-app/src/sbt-test/tests/test-quick/build.sbt b/sbt-app/src/sbt-test/tests/incremental/build.sbt similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/build.sbt rename to sbt-app/src/sbt-test/tests/incremental/build.sbt diff --git a/sbt-app/src/sbt-test/tests/test-quick/changed/A.scala b/sbt-app/src/sbt-test/tests/incremental/changed/A.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/changed/A.scala rename to sbt-app/src/sbt-test/tests/incremental/changed/A.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/changed/B.scala b/sbt-app/src/sbt-test/tests/incremental/changed/B.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/changed/B.scala rename to sbt-app/src/sbt-test/tests/incremental/changed/B.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/changed/Base.scala b/sbt-app/src/sbt-test/tests/incremental/changed/Base.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/changed/Base.scala rename to sbt-app/src/sbt-test/tests/incremental/changed/Base.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/A.scala b/sbt-app/src/sbt-test/tests/incremental/src/main/scala/A.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/main/scala/A.scala rename to sbt-app/src/sbt-test/tests/incremental/src/main/scala/A.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/B.scala b/sbt-app/src/sbt-test/tests/incremental/src/main/scala/B.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/main/scala/B.scala rename to sbt-app/src/sbt-test/tests/incremental/src/main/scala/B.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Base.scala b/sbt-app/src/sbt-test/tests/incremental/src/test/scala/Base.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Base.scala rename to sbt-app/src/sbt-test/tests/incremental/src/test/scala/Base.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala b/sbt-app/src/sbt-test/tests/incremental/src/test/scala/Create.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala rename to sbt-app/src/sbt-test/tests/incremental/src/test/scala/Create.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala b/sbt-app/src/sbt-test/tests/incremental/src/test/scala/Delete.scala similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala rename to sbt-app/src/sbt-test/tests/incremental/src/test/scala/Delete.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/test b/sbt-app/src/sbt-test/tests/incremental/test similarity index 80% rename from sbt-app/src/sbt-test/tests/test-quick/test rename to sbt-app/src/sbt-test/tests/incremental/test index c86f0276f..72891032f 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/test +++ b/sbt-app/src/sbt-test/tests/incremental/test @@ -27,14 +27,8 @@ $ sleep 2000 # src/test compilation group change. $ copy-file changed/Base.scala src/test/scala/Base.scala -> test:compile +> Test/compile $ sleep 2000 -> testQuick Create > testQuick Delete > testQuick Create - -# https://github.com/sbt/sbt/issues/5504 -$ copy-file changed/MathFunction.scala src/test/scala/MathFunction.scala -> compile -$ sleep 2000 --> testQuick MathFunctionTest From baa9a919ba2c37c050a37a20318739b8572b365f Mon Sep 17 00:00:00 2001 From: OlegYch Date: Sun, 23 Mar 2025 22:22:02 -0400 Subject: [PATCH 09/12] Reproduce testQuick + object deps bug [merge-skip] testQuick after code change doesn't rerun the test. This was adopted from https://github.com/OlegYch/sbt-testQuick-bug --- .../src/sbt-test/tests/incremental-object-deps/build.sbt | 3 +++ .../sbt-test/tests/incremental-object-deps/changes/B.scala | 4 ++++ .../incremental-object-deps/src/main/scala/example/A.scala | 4 ++++ .../incremental-object-deps/src/main/scala/example/B.scala | 4 ++++ .../src/test/scala/example/ATest.scala | 7 +++++++ sbt-app/src/sbt-test/tests/incremental-object-deps/test | 6 ++++++ 6 files changed, 28 insertions(+) create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/build.sbt create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/changes/B.scala create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/A.scala create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/B.scala create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/src/test/scala/example/ATest.scala create mode 100644 sbt-app/src/sbt-test/tests/incremental-object-deps/test diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/build.sbt b/sbt-app/src/sbt-test/tests/incremental-object-deps/build.sbt new file mode 100644 index 000000000..d37f0123e --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/build.sbt @@ -0,0 +1,3 @@ +scalaVersion := "3.6.4" +libraryDependencies += "com.eed3si9n.verify" %% "verify" % "1.0.0" % Test +testFrameworks += new TestFramework("verify.runner.Framework") diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/changes/B.scala b/sbt-app/src/sbt-test/tests/incremental-object-deps/changes/B.scala new file mode 100644 index 000000000..6d58d7cda --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/changes/B.scala @@ -0,0 +1,4 @@ +package example + +object B: + def bbb: String = "3" diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/A.scala b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/A.scala new file mode 100644 index 000000000..e935ad4e3 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/A.scala @@ -0,0 +1,4 @@ +package example + +object A: + def aaa: String = B.bbb diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/B.scala b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/B.scala new file mode 100644 index 000000000..778ef9fdd --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/main/scala/example/B.scala @@ -0,0 +1,4 @@ +package example + +object B: + def bbb: String = "2" diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/src/test/scala/example/ATest.scala b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/test/scala/example/ATest.scala new file mode 100644 index 000000000..585244155 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/src/test/scala/example/ATest.scala @@ -0,0 +1,7 @@ +package example + +object ATest extends verify.BasicTestSuite: + test("aaa ") { + assert(A.aaa == "2") + } +end ATest diff --git a/sbt-app/src/sbt-test/tests/incremental-object-deps/test b/sbt-app/src/sbt-test/tests/incremental-object-deps/test new file mode 100644 index 000000000..1938dc321 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/incremental-object-deps/test @@ -0,0 +1,6 @@ +> debug +> testQuick +$ sleep 2000 +$ copy-file changes/B.scala src/main/scala/example/B.scala + +-> testQuick From 1415b2efa45df914db82494e8d00f3c8da8bd3be Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 31 Mar 2025 22:22:27 -0400 Subject: [PATCH 10/12] fix: Fix incremental test with companion objects [merge-skip] **Problem** Incremental test (aka testQuick) has a bug when companion objects depends on others since at some point it's failing to look up relationship from Zinc analysis. **Solution** This fixes the lookup. --- main/src/main/scala/sbt/Defaults.scala | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index dbbbe84b1..9ee85e286 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1485,26 +1485,34 @@ object Defaults extends BuildCommon { if (stamps.isEmpty) Long.MinValue else stamps.max } - def intlStamp(c: String, analysis: Analysis, s: Set[String]): Long = { - if (s contains c) Long.MinValue + def intlStamp0(javaClassName: String, analysis: Analysis, alreadySeen: Set[String])( + className: String + ): Set[Long] = { + import analysis.{ apis, relations } + relations + .internalClassDeps(className) + .map(intlStamp(_, analysis, alreadySeen + javaClassName)) ++ + relations.externalDeps(className).map(stamp) ++ + apis.internal.get(javaClassName).toSeq.map(_.compilationTimestamp) ++ + apis.internal.get(className).toSeq.map(_.compilationTimestamp) + } + def intlStamp(javaClassName: String, analysis: Analysis, alreadySeen: Set[String]): Long = + if (alreadySeen contains javaClassName) Long.MinValue else stamps.getOrElse( - c, { - val x = { - import analysis.{ apis, relations => rel } - rel.internalClassDeps(c).map(intlStamp(_, analysis, s + c)) ++ - rel.externalDeps(c).map(stamp) ++ - rel.productClassName.reverse(c).flatMap { pc => - apis.internal.get(pc).map(_.compilationTimestamp) - } + Long.MinValue + javaClassName, { + val x: Long = { + val classNames = analysis.relations.productClassName.reverse(javaClassName).toSeq + classNames.flatMap(intlStamp0(javaClassName, analysis, alreadySeen)) ++ Seq( + Long.MinValue + ) }.max if (x != Long.MinValue) { - stamps(c) = x + stamps(javaClassName) = x } x } ) - } def noSuccessYet(test: String) = succeeded.get(test) match { case None => true case Some(ts) => stamps.synchronized(stamp(test)) > ts From 5d81f2c3d136d166376293237b19f179b5f7695b Mon Sep 17 00:00:00 2001 From: Alec Theriault Date: Wed, 7 May 2025 06:10:34 -0400 Subject: [PATCH 11/12] fix: BSP error status code in more cases Ensures that `buildTarget/compile` returns a `StatusCode.Error` instead of a JSON-RPC error even when the compile error is buried deeper in the `Incomplete` causes. Fixes #8104 --- .../internal/server/BuildServerProtocol.scala | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 9bb371a78..d2c812167 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -789,11 +789,19 @@ object BuildServerProtocol { Keys.compile.result.value match { case Value(_) => StatusCode.Success case Inc(cause) => - cause.getCause match { - case _: CompileFailed => StatusCode.Error - case _: InterruptedException => StatusCode.Cancelled - case err => throw cause + var statusCodeOpt: Option[Int] + def updateCode(code: Int): Unit = + statusCodeOpt = Some(statusCodeOpt match { + case None => code + case Some(oldCode) => oldCode.max(code) + }) + + Incomplete.visitAll(cause.getCause) { + case _: CompileFailed => updateCode(StatusCode.Error) + case _: InterruptedException => updateCode(StatusCode.Cancelled) } + + statusCodeOpt.getOrElse(throw cause) } } From 1d7871233bc54e8766d4014ccd769b62cb6c4c2a Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Sun, 11 May 2025 12:59:15 +0900 Subject: [PATCH 12/12] Revert "fix: BSP error status code in more cases" --- .../internal/server/BuildServerProtocol.scala | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index d2c812167..9bb371a78 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -789,19 +789,11 @@ object BuildServerProtocol { Keys.compile.result.value match { case Value(_) => StatusCode.Success case Inc(cause) => - var statusCodeOpt: Option[Int] - def updateCode(code: Int): Unit = - statusCodeOpt = Some(statusCodeOpt match { - case None => code - case Some(oldCode) => oldCode.max(code) - }) - - Incomplete.visitAll(cause.getCause) { - case _: CompileFailed => updateCode(StatusCode.Error) - case _: InterruptedException => updateCode(StatusCode.Cancelled) + cause.getCause match { + case _: CompileFailed => StatusCode.Error + case _: InterruptedException => StatusCode.Cancelled + case err => throw cause } - - statusCodeOpt.getOrElse(throw cause) } }