From 51aa789346dd515d589c12ec00fcc0b1f1821484 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 28 Sep 2025 04:06:37 -0400 Subject: [PATCH 01/17] Suppress JDK 25 warnings --- .github/workflows/client-test.yml | 6 ++++-- launcher-package/src/universal/bin/sbt.bat | 16 +++++++++++++++ sbt | 23 ++++++++++++++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/.github/workflows/client-test.yml b/.github/workflows/client-test.yml index 9526d612a..8959c7861 100644 --- a/.github/workflows/client-test.yml +++ b/.github/workflows/client-test.yml @@ -33,7 +33,9 @@ jobs: uses: actions/setup-java@v5 with: distribution: "zulu" - java-version: "8" + java-version: | + 25 + 8 cache: sbt - uses: sbt/setup-sbt@v1 with: @@ -60,7 +62,6 @@ jobs: sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin sbt -Dsbt.build.version=$TEST_SBT_VER integrationTest/test cd citest && ./test.sh - $HOME/bin/jabba install $JDK11 && exec $HOME/bin/jabba which --home $JDK11 java -Xmx32m -version ./test.sh - name: Client test (macOS) @@ -91,4 +92,5 @@ jobs: sbt -Dsbt.build.version=$TEST_SBT_VER integrationTest/test cd citest ./test.bat + java -Xmx32m -version test3/test3.bat diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index 781b8b9ba..a8414490b 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -39,6 +39,7 @@ set sbt_args_color= set sbt_args_no_colors= set sbt_args_no_global= set sbt_args_no_share= +set sbt_args_no_hide_jdk_warnings= set sbt_args_sbt_jar= set sbt_args_ivy= set sbt_args_supershell= @@ -231,6 +232,14 @@ if defined _no_server_arg ( goto args_loop ) +if "%~0" == "--no-hide-jdk-warnings" set _no_hide_jdk_warnings=true + +if defined _no_hide_jdk_warnings ( + set _no_hide_jdk_warnings= + set sbt_args_no_hide_jdk_warnings=1 + goto args_loop +) + if "%~0" == "-no-global" set _no_global_arg=true if "%~0" == "--no-global" set _no_global_arg=true @@ -677,6 +686,13 @@ if defined sbt_args_no_server ( set _SBT_OPTS=-Dsbt.io.virtual=false -Dsbt.server.autostart=false !_SBT_OPTS! ) +if not defined sbt_args_no_hide_jdk_warnings ( + if /I !JAVA_VERSION! EQU 25 ( + call :addJava --sun-misc-unsafe-memory-access=allow + call :addJava --enable-native-access=ALL-UNNAMED + ) +) + rem TODO: _SBT_OPTS needs to be processed as args and diffed against SBT_ARGS if !sbt_args_print_sbt_version! equ 1 ( diff --git a/sbt b/sbt index ea6860fe6..7f03aa622 100755 --- a/sbt +++ b/sbt @@ -28,6 +28,7 @@ declare sbtn_command="$SBTN_CMD" declare sbtn_version="1.11.6" declare use_colors=1 declare is_this_dir_sbt="" +declare hide_jdk_warnings=1 ### ------------------------------- ### ### Helper methods for BASH scripts ### @@ -85,7 +86,7 @@ CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi) # windows style paths. cygwinpath() { local file="$1" - if [[ "$CYGWIN_FLAG" == "true" ]]; then #" + if [[ "$CYGWIN_FLAG" == "true" ]]; then echo $(cygpath -w $file) else echo $file @@ -114,7 +115,7 @@ echoerr_error () { echoerr -e "[${RED}error${NC}] $@" else echoerr "[error] $@" - fi + fi #" } vlog () { [[ $sbt_verbose || $sbt_debug ]] && echoerr "$@" @@ -347,6 +348,18 @@ addSbtScriptProperty () { fi } +addJdkWorkaround () { + local is_25="$(expr $java_version "=" 25)" + if [[ "$hide_jdk_warnings" == "0" ]]; then + : + else + if [[ "$is_25" == "1" ]]; then + addJava "--sun-misc-unsafe-memory-access=allow" + addJava "--enable-native-access=ALL-UNNAMED" + fi + fi +} + require_arg () { local type="$1" local opt="$2" @@ -532,7 +545,7 @@ run() { copyRt # If we're in cygwin, we should use the windows config, and terminal hacks - if [[ "$CYGWIN_FLAG" == "true" ]]; then #" + if [[ "$CYGWIN_FLAG" == "true" ]]; then stty -icanon min 1 -echo > /dev/null 2>&1 addJava "-Djline.terminal=jline.UnixTerminal" addJava "-Dsbt.cygwin=true" @@ -572,7 +585,7 @@ run() { exit_code=$? # Clean up the terminal from cygwin hacks. - if [[ "$CYGWIN_FLAG" == "true" ]]; then #" + if [[ "$CYGWIN_FLAG" == "true" ]]; then stty icanon echo > /dev/null 2>&1 fi exit $exit_code @@ -705,6 +718,7 @@ process_args () { -client|--client) use_sbtn=1 && shift ;; --server) use_sbtn=0 && shift ;; --jvm-client) use_sbtn=0 && use_jvm_client=1 && addSbt "--client" && shift ;; + --no-hide-jdk-warnings) hide_jdk_warnings=0 && shift ;; -mem|--mem) require_arg integer "$1" "$2" && addMemory "$2" && shift 2 ;; -jvm-debug|--jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;; @@ -867,6 +881,7 @@ else vlog "[process_args] java_version = '$java_version'" addDefaultMemory addSbtScriptProperty + addJdkWorkaround set -- "${residual_args[@]}" argumentCount=$# run From bd460ae5363b5fe6545576184633ff88cf9cc2f0 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 28 Sep 2025 04:27:17 -0400 Subject: [PATCH 02/17] Test using JDK 25 --- .github/workflows/client-test.yml | 7 ++++--- launcher-package/citest/test3/.jvmopts | 2 +- launcher-package/citest/test3/build.sbt | 6 +++--- launcher-package/citest/test3/test3.bat | 10 ++++++---- launcher-package/src/universal/bin/sbt.bat | 3 +-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/client-test.yml b/.github/workflows/client-test.yml index 8959c7861..df0ef6ab4 100644 --- a/.github/workflows/client-test.yml +++ b/.github/workflows/client-test.yml @@ -57,11 +57,13 @@ jobs: ./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 + echo build using JDK 8 test using JDK 8 and JDK 25 cd launcher-package sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin sbt -Dsbt.build.version=$TEST_SBT_VER integrationTest/test cd citest && ./test.sh + JAVA_HOME="$JAVA_HOME_25_X64" + PATH="$JAVA_HOME_25_X64/bin:$PATH" java -Xmx32m -version ./test.sh - name: Client test (macOS) @@ -86,11 +88,10 @@ jobs: ./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 + echo build using JDK 8 test using JDK 8 and JDK 25 cd launcher-package bin/coursier.bat resolve sbt -Dsbt.build.version=$TEST_SBT_VER integrationTest/test cd citest ./test.bat - java -Xmx32m -version test3/test3.bat diff --git a/launcher-package/citest/test3/.jvmopts b/launcher-package/citest/test3/.jvmopts index ecacefc9a..a18306841 100644 --- a/launcher-package/citest/test3/.jvmopts +++ b/launcher-package/citest/test3/.jvmopts @@ -1,3 +1,3 @@ --XX:+CMSClassUnloadingEnabled +#-XX:+CMSClassUnloadingEnabled #-XX:ReservedCodeCacheSize=192m #-Duser.timezone=GMT \ No newline at end of file diff --git a/launcher-package/citest/test3/build.sbt b/launcher-package/citest/test3/build.sbt index 6cba9926c..dbe7fe7f9 100755 --- a/launcher-package/citest/test3/build.sbt +++ b/launcher-package/citest/test3/build.sbt @@ -27,19 +27,19 @@ lazy val root = (project in file(".")) assert(ys.size == 1, s"ys has more than one item: $ys") assert(ys(0) startsWith "Java HotSpot(TM) 64-Bit Server VM warning") }, - checkNumericVersion = { + checkNumericVersion := { val xs = IO.readLines(file("numericVersion.txt")).toVector val expectedVersion = "^"+versionRegEx+"$" assert(xs(0).matches(expectedVersion)) }, - checkScriptVersion = { + checkScriptVersion := { val xs = IO.readLines(file("scriptVersion.txt")).toVector val expectedVersion = "^"+versionRegEx+"$" assert(xs(0).matches(expectedVersion)) }, - checkVersion = { + checkVersion := { val out = IO.readLines(file("version.txt")).toVector.mkString("\n") val expectedVersion = diff --git a/launcher-package/citest/test3/test3.bat b/launcher-package/citest/test3/test3.bat index 38b1bde4f..52f489a0f 100644 --- a/launcher-package/citest/test3/test3.bat +++ b/launcher-package/citest/test3/test3.bat @@ -2,16 +2,18 @@ SETLOCAL -SET JAVA_HOME=C:\jdk11 -SET PATH=C:\jdk11\bin;%PATH% +SET JAVA_HOME=%JAVA_HOME_25_X64% +SET PATH=%JAVA_HOME_25_X64%\bin;%PATH% SET SBT_OPTS=-Xmx4g -Dfile.encoding=UTF8 SET BASE_DIR=%CD% SET SCRIPT_DIR=%~dp0 CD %SCRIPT_DIR% -"%BASE_DIR%freshly-baked\sbt\bin\sbt" about 1> output.txt 2> err.txt -"%BASE_DIR%freshly-baked\sbt\bin\sbt" check +"%BASE_DIR%\freshly-baked\sbt\bin\sbt" about 1> output.txt 2> err.txt +"%BASE_DIR%\freshly-baked\sbt\bin\sbt" check CD %BASE_DIR% ENDLOCAL + +IF %errorlevel% NEQ 0 EXIT /b %errorlevel% diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index a8414490b..3c3468e2f 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -688,8 +688,7 @@ if defined sbt_args_no_server ( if not defined sbt_args_no_hide_jdk_warnings ( if /I !JAVA_VERSION! EQU 25 ( - call :addJava --sun-misc-unsafe-memory-access=allow - call :addJava --enable-native-access=ALL-UNNAMED + set _SBT_OPTS=--sun-misc-unsafe-memory-access=allow --enable-native-access=ALL-UNNAMED !_SBT_OPTS! ) ) From 246e060e537bd69830d0a883dcba179529a98119 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Mon, 29 Sep 2025 07:37:05 +0900 Subject: [PATCH 03/17] update sbt-giter8-resolver version --- main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala b/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala index 4aedac6aa..d976909c7 100644 --- a/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala +++ b/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala @@ -27,7 +27,7 @@ object Giter8TemplatePlugin extends AutoPlugin { ModuleID( "org.scala-sbt.sbt-giter8-resolver", "sbt-giter8-resolver", - "0.17.0" + "0.18.0" ) cross CrossVersion.binary, "sbtgiter8resolver.Giter8TemplateResolver" ) From ded814f572c473f939d8719545d5d7bf011a9b5d Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Fri, 3 Oct 2025 09:21:52 +0900 Subject: [PATCH 04/17] update dependencies --- project/Dependencies.scala | 10 +++++----- project/build.properties | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8127eb1b8..17e157653 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -91,9 +91,9 @@ object Dependencies { val jline3Native = "org.jline" % "jline-native" % jline3Version val jline3Reader = "org.jline" % "jline-reader" % jline3Version val jline3Builtins = "org.jline" % "jline-builtins" % jline3Version - val scalatest = "org.scalatest" %% "scalatest" % "3.2.10" - val scalacheck = "org.scalacheck" %% "scalacheck" % "1.15.4" - val junit = "junit" % "junit" % "4.13.1" + val scalatest = "org.scalatest" %% "scalatest" % "3.2.19" + val scalacheck = "org.scalacheck" %% "scalacheck" % "1.19.0" + val junit = "junit" % "junit" % "4.13.2" val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0" val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1" @@ -129,8 +129,8 @@ object Dependencies { val caffeine = "com.github.ben-manes.caffeine" % "caffeine" % "2.8.5" - val hedgehog = "qa.hedgehog" %% "hedgehog-sbt" % "0.7.0" + val hedgehog = "qa.hedgehog" %% "hedgehog-sbt" % "0.13.0" val disruptor = "com.lmax" % "disruptor" % "3.4.2" - val kindProjector = ("org.typelevel" % "kind-projector" % "0.13.3").cross(CrossVersion.full) + val kindProjector = ("org.typelevel" % "kind-projector" % "0.13.4").cross(CrossVersion.full) val gigahorseOkHttp = "com.eed3si9n" %% "gigahorse-apache-http" % "0.9.3" } diff --git a/project/build.properties b/project/build.properties index 489e0a72d..5e6884d37 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.11.4 +sbt.version=1.11.6 From 3b662f39688b54e6c43a6fc5f821a7749c806902 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Fri, 3 Oct 2025 09:39:10 +0900 Subject: [PATCH 05/17] fix fallback-dependencies-inter-project test --- .../fallback-dependencies-inter-project/build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt-app/src/sbt-test/dependency-management/fallback-dependencies-inter-project/build.sbt b/sbt-app/src/sbt-test/dependency-management/fallback-dependencies-inter-project/build.sbt index 98731216b..280188f55 100644 --- a/sbt-app/src/sbt-test/dependency-management/fallback-dependencies-inter-project/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/fallback-dependencies-inter-project/build.sbt @@ -2,7 +2,7 @@ ThisBuild / scalaVersion := "2.11.12" lazy val a = project .settings( - libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.234" from "https://oss.sonatype.org/content/repositories/releases/com/chuusai/shapeless_2.11/2.3.1/shapeless_2.11-2.3.1.jar" + libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.234" from "https://repo1.maven.org/maven2/com/chuusai/shapeless_2.11/2.3.1/shapeless_2.11-2.3.1.jar" ) lazy val b = project From 2a7e70ab6a7af9a8047eb184d28ada068e9f86c4 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Fri, 3 Oct 2025 14:49:28 +0900 Subject: [PATCH 06/17] fix run/daemon-exit test --- sbt-app/src/sbt-test/run/daemon-exit/build.sbt | 1 + 1 file changed, 1 insertion(+) create mode 100644 sbt-app/src/sbt-test/run/daemon-exit/build.sbt diff --git a/sbt-app/src/sbt-test/run/daemon-exit/build.sbt b/sbt-app/src/sbt-test/run/daemon-exit/build.sbt new file mode 100644 index 000000000..6dbf94cfe --- /dev/null +++ b/sbt-app/src/sbt-test/run/daemon-exit/build.sbt @@ -0,0 +1 @@ +run / fork := true From 152fe61cedb6b915e9563e013fd7f0c17ecdae97 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Fri, 3 Oct 2025 07:24:53 +0900 Subject: [PATCH 07/17] fix runMain task. support JEP-512 --- run/src/main/scala/sbt/Run.scala | 29 +++++++-- .../src/sbt-test/run/jep-512/{ => a1}/A.scala | 0 sbt-app/src/sbt-test/run/jep-512/a2/A.java | 7 +++ sbt-app/src/sbt-test/run/jep-512/a3/A.java | 7 +++ sbt-app/src/sbt-test/run/jep-512/a4/A.java | 7 +++ sbt-app/src/sbt-test/run/jep-512/a5/A.java | 7 +++ sbt-app/src/sbt-test/run/jep-512/a6/A.java | 3 + sbt-app/src/sbt-test/run/jep-512/build.sbt | 59 ++++++++++++++++--- sbt-app/src/sbt-test/run/jep-512/test | 7 ++- 9 files changed, 113 insertions(+), 13 deletions(-) rename sbt-app/src/sbt-test/run/jep-512/{ => a1}/A.scala (100%) create mode 100644 sbt-app/src/sbt-test/run/jep-512/a2/A.java create mode 100644 sbt-app/src/sbt-test/run/jep-512/a3/A.java create mode 100644 sbt-app/src/sbt-test/run/jep-512/a4/A.java create mode 100644 sbt-app/src/sbt-test/run/jep-512/a5/A.java create mode 100644 sbt-app/src/sbt-test/run/jep-512/a6/A.java diff --git a/run/src/main/scala/sbt/Run.scala b/run/src/main/scala/sbt/Run.scala index f964d9b4b..c68bb830a 100644 --- a/run/src/main/scala/sbt/Run.scala +++ b/run/src/main/scala/sbt/Run.scala @@ -10,7 +10,7 @@ package sbt import java.io.File import java.lang.reflect.Method -import java.lang.reflect.Modifier.{ isPublic, isStatic } +import java.lang.reflect.Modifier.{ isPrivate, isPublic, isStatic } import sbt.internal.inc.ScalaInstance import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil } import sbt.internal.util.MessageOnlyException @@ -133,10 +133,17 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea currentThread.setContextClassLoader(loader) try { if (main.isStatic) { + if (Run.isJava25Plus) { + main.method.setAccessible(true) + } if (main.parameterCount > 0) main.method.invoke(null, options.toArray[String]) else main.method.invoke(null) } else { - val ref = main.mainClass.getDeclaredConstructor().newInstance().asInstanceOf[AnyRef] + val constructor = main.mainClass.getDeclaredConstructor() + if (Run.isJava25Plus) { + constructor.setAccessible(true) + } + val ref = constructor.newInstance().asInstanceOf[AnyRef] if (main.parameterCount > 0) main.method.invoke(ref, options.toArray[String]) else main.method.invoke(ref) } @@ -165,10 +172,24 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea val method = try { mainClass.getMethod("main", classOf[Array[String]]) } catch { - case _: NoSuchMethodException => mainClass.getMethod("main") + case _: NoSuchMethodException => + try { + mainClass.getMethod("main") + } catch { + case _: NoSuchMethodException => + try { + mainClass.getDeclaredMethod("main", classOf[Array[String]]) + } catch { + case _: NoSuchMethodException => + mainClass.getDeclaredMethod("main") + } + } + } + val modifiers = method.getModifiers + if (isPrivate(modifiers)) { + throw new NoSuchMethodException(s"${mainClassName}.main is private") } method.setAccessible(true) - val modifiers = method.getModifiers DetectedMain(mainClass, method, isStatic(modifiers), method.getParameterCount()) } else { val method = mainClass.getMethod("main", classOf[Array[String]]) diff --git a/sbt-app/src/sbt-test/run/jep-512/A.scala b/sbt-app/src/sbt-test/run/jep-512/a1/A.scala similarity index 100% rename from sbt-app/src/sbt-test/run/jep-512/A.scala rename to sbt-app/src/sbt-test/run/jep-512/a1/A.scala diff --git a/sbt-app/src/sbt-test/run/jep-512/a2/A.java b/sbt-app/src/sbt-test/run/jep-512/a2/A.java new file mode 100644 index 000000000..cb51194e0 --- /dev/null +++ b/sbt-app/src/sbt-test/run/jep-512/a2/A.java @@ -0,0 +1,7 @@ +package example; + +class A { + void main() { + System.out.println("package private no args"); + } +} diff --git a/sbt-app/src/sbt-test/run/jep-512/a3/A.java b/sbt-app/src/sbt-test/run/jep-512/a3/A.java new file mode 100644 index 000000000..c1d2792cb --- /dev/null +++ b/sbt-app/src/sbt-test/run/jep-512/a3/A.java @@ -0,0 +1,7 @@ +package example; + +class A { + protected void main() { + System.out.println("protected no args"); + } +} diff --git a/sbt-app/src/sbt-test/run/jep-512/a4/A.java b/sbt-app/src/sbt-test/run/jep-512/a4/A.java new file mode 100644 index 000000000..6b646c14f --- /dev/null +++ b/sbt-app/src/sbt-test/run/jep-512/a4/A.java @@ -0,0 +1,7 @@ +package example; + +class A { + void main(String[] args) { + System.out.println("package private with args"); + } +} diff --git a/sbt-app/src/sbt-test/run/jep-512/a5/A.java b/sbt-app/src/sbt-test/run/jep-512/a5/A.java new file mode 100644 index 000000000..bb441141a --- /dev/null +++ b/sbt-app/src/sbt-test/run/jep-512/a5/A.java @@ -0,0 +1,7 @@ +package example; + +class A { + private void main(String[] args) { + System.out.println("private"); + } +} diff --git a/sbt-app/src/sbt-test/run/jep-512/a6/A.java b/sbt-app/src/sbt-test/run/jep-512/a6/A.java new file mode 100644 index 000000000..7ce4a32e7 --- /dev/null +++ b/sbt-app/src/sbt-test/run/jep-512/a6/A.java @@ -0,0 +1,3 @@ +void main() { + IO.println("compact source file with java.lang.IO"); +} diff --git a/sbt-app/src/sbt-test/run/jep-512/build.sbt b/sbt-app/src/sbt-test/run/jep-512/build.sbt index e46b37039..3adcc19ef 100644 --- a/sbt-app/src/sbt-test/run/jep-512/build.sbt +++ b/sbt-app/src/sbt-test/run/jep-512/build.sbt @@ -1,11 +1,54 @@ -// 2.12.x uses Zinc's compiler bridge -ThisBuild / scalaVersion := "2.12.20" - @transient lazy val check = taskKey[Unit]("") -check := { - if (scala.util.Properties.isJavaAtLeast("25")) - (Compile / run).toTask(" ").value - else () -} +lazy val common = Def.settings( + // 2.12.x uses Zinc's compiler bridge + scalaVersion := "2.12.20", +) + +// use `runMain` instead of `run` because discoveredMainClasses return empty +// if JEP-512 java main method +// TODO fix zinc +// https://github.com/sbt/sbt/issues/7384#issuecomment-3361020003 +lazy val commonRunMainCheck = Def.settings( + check := { + if (scala.util.Properties.isJavaAtLeast("25")) { + (Compile / runMain).toTask(" example.A").value + } else () + } +) + +lazy val a1 = project + .settings(common) + .settings( + check := { + if (scala.util.Properties.isJavaAtLeast("25")) { + assert((Compile / discoveredMainClasses).value.size == 1) + (Compile / run).toTask(" ").value + } else () + } + ) + +lazy val a2 = project.settings(common, commonRunMainCheck) +lazy val a3 = project.settings(common, commonRunMainCheck) +lazy val a4 = project.settings(common, commonRunMainCheck) + +lazy val a5 = project.settings( + common, + check := { + if (scala.util.Properties.isJavaAtLeast("25")) { + (Compile / runMain).toTask(" example.A").value + } else { + sys.error("not jdk 25") + } + } +) + +lazy val a6 = project.settings( + common, + check := { + if (scala.util.Properties.isJavaAtLeast("25")) { + (Compile / runMain).toTask(" A").value + } else () + } +) diff --git a/sbt-app/src/sbt-test/run/jep-512/test b/sbt-app/src/sbt-test/run/jep-512/test index c28fe4985..9fbd123fa 100644 --- a/sbt-app/src/sbt-test/run/jep-512/test +++ b/sbt-app/src/sbt-test/run/jep-512/test @@ -1,2 +1,7 @@ # > run -> check +> a1/check +> a2/check +> a3/check +> a4/check +-> a5/check +> a6/check From 1e6afc58c4358478297cc8833f735943d7a55fa4 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 5 Oct 2025 14:21:40 -0400 Subject: [PATCH 08/17] Update to lm 1.11.6 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 17e157653..ccb7edda0 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -14,7 +14,7 @@ object Dependencies { // sbt modules private val ioVersion = nightlyVersion.getOrElse("1.10.5") private val lmVersion = - sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.11.5") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.11.6") val zincVersion = nightlyVersion.getOrElse("1.11.0") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From 9d2a5f478bde5d45562423cb6decf92b255b9517 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 5 Oct 2025 14:57:23 -0400 Subject: [PATCH 09/17] sbt 1.11.7 --- build.sbt | 2 +- sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 70ed6f40f..a028802da 100644 --- a/build.sbt +++ b/build.sbt @@ -11,7 +11,7 @@ import scala.util.Try // ThisBuild settings take lower precedence, // but can be shared across the multi projects. ThisBuild / version := { - val v = "1.11.7-SNAPSHOT" + val v = "1.11.8-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/sbt b/sbt index 7f03aa622..aa12e7446 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.11.6" +declare builtin_sbt_version="1.11.7" declare -a residual_args declare -a java_args declare -a scalac_args From 49c83060914e0c20ea912231da779dbc569a880e Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Thu, 23 Oct 2025 15:20:52 +0900 Subject: [PATCH 10/17] Update semanticdbVersion --- build.sbt | 2 +- main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index a028802da..f10004658 100644 --- a/build.sbt +++ b/build.sbt @@ -48,7 +48,7 @@ ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" Global / semanticdbEnabled := !(Global / insideCI).value // Change main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala too, if you change this. -Global / semanticdbVersion := "4.9.9" +Global / semanticdbVersion := "4.14.1" val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys") Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty) Global / excludeLint += componentID diff --git a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala index 46a018397..040d5bbf8 100644 --- a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala @@ -27,7 +27,7 @@ object SemanticdbPlugin extends AutoPlugin { semanticdbEnabled := SysProp.semanticdb, semanticdbIncludeInJar := false, semanticdbOptions := List(), - semanticdbVersion := "4.9.9" + semanticdbVersion := "4.14.1" ) override lazy val projectSettings: Seq[Def.Setting[_]] = Seq( From e42c54f7820c09454688a8319a7697d7643d67b9 Mon Sep 17 00:00:00 2001 From: danicheg Date: Thu, 30 Oct 2025 11:30:06 +0300 Subject: [PATCH 11/17] [1.x] Update scala213 to 2.13.17 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index ccb7edda0..c14030431 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,7 +5,7 @@ import sbt.contraband.ContrabandPlugin.autoImport._ object Dependencies { // WARNING: Please Scala update versions in PluginCross.scala too val scala212 = "2.12.20" - val scala213 = "2.13.16" + val scala213 = "2.13.17" val checkPluginCross = settingKey[Unit]("Make sure scalaVersion match up") val baseScalaVersion = scala212 def nightlyVersion: Option[String] = From ed7da85ef012b71919c8ce35b5e46c760db7766a Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 1 Nov 2025 14:53:58 -0400 Subject: [PATCH 12/17] Backport Compiler Backport scala.internal.Compiler from sbt 2.x so we can merge easier. --- main/src/main/scala/sbt/Defaults.scala | 178 +------------ .../main/scala/sbt/internal/Compiler.scala | 234 ++++++++++++++++++ 2 files changed, 243 insertions(+), 169 deletions(-) create mode 100644 main/src/main/scala/sbt/internal/Compiler.scala diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index fd49fdcc3..a6c2c5a56 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -689,7 +689,7 @@ object Defaults extends BuildCommon { } else topLoader }, - scalaInstance := scalaInstanceTask.value, + scalaInstance := Compiler.scalaInstanceTask.value, crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( (pluginCrossBuild / sbtVersion).value @@ -1139,34 +1139,8 @@ object Defaults extends BuildCommon { } } - def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Def.taskDyn { - // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed - // appropriately to avoid cycles - scalaHome.value match { - case Some(h) => scalaInstanceFromHome(h) - case None => - val scalaProvider = appConfiguration.value.provider.scalaProvider - val version = scalaVersion.value - if (version == scalaProvider.version) // use the same class loader as the Scala classes used by sbt - Def.task { - val allJars = scalaProvider.jars - val libraryJars = allJars.filter(_.getName == "scala-library.jar") - allJars.filter(_.getName == "scala-compiler.jar") match { - case Array(compilerJar) if libraryJars.nonEmpty => - makeScalaInstance( - version, - libraryJars, - allJars, - Seq.empty, - state.value, - scalaInstanceTopLoader.value - ) - case _ => ScalaInstance(version, scalaProvider) - } - } else - scalaInstanceFromUpdate - } - } + @deprecated("Use Compiler.scalaInstanceTask", "1.12.0") + def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Compiler.scalaInstanceTask // Returns the ScalaInstance only if it was not constructed via `update` // This is necessary to prevent cycles between `update` and `scalaInstance` @@ -1175,108 +1149,9 @@ object Defaults extends BuildCommon { if (scalaHome.value.isDefined) Def.task(Some(scalaInstance.value)) else Def.task(None) } - private[this] def noToolConfiguration(autoInstance: Boolean): String = { - val pre = "Missing Scala tool configuration from the 'update' report. " - val post = - if (autoInstance) - "'scala-tool' is normally added automatically, so this may indicate a bug in sbt or you may be removing it from ivyConfigurations, for example." - else - "Explicitly define scalaInstance or scalaHome or include Scala dependencies in the 'scala-tool' configuration." - pre + post - } + def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = + Compiler.scalaInstanceFromUpdate - def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = Def.task { - val sv = scalaVersion.value - val fullReport = update.value - val s = streams.value - - // For Scala 3, update scala-library.jar in `scala-tool` and `scala-doc-tool` in case a newer version - // is present in the `compile` configuration. This is needed once forwards binary compatibility is dropped - // to avoid NoSuchMethod exceptions when expanding macros. - def updateLibraryToCompileConfiguration(report: ConfigurationReport) = - if (!ScalaArtifacts.isScala3(sv)) report - else - (for { - compileConf <- fullReport.configuration(Configurations.Compile) - compileLibMod <- compileConf.modules.find(_.module.name == ScalaArtifacts.LibraryID) - reportLibMod <- report.modules.find(_.module.name == ScalaArtifacts.LibraryID) - if VersionNumber(reportLibMod.module.revision) - .matchesSemVer(SemanticSelector(s"<${compileLibMod.module.revision}")) - } yield { - val newMods = report.modules - .filterNot(_.module.name == ScalaArtifacts.LibraryID) :+ compileLibMod - report.withModules(newMods) - }).getOrElse(report) - - val toolReport = updateLibraryToCompileConfiguration( - fullReport - .configuration(Configurations.ScalaTool) - .getOrElse(sys.error(noToolConfiguration(managedScalaInstance.value))) - ) - - if (Classpaths.isScala213(sv)) { - val scalaDeps = for { - compileReport <- fullReport.configuration(Configurations.Compile).iterator - libName <- ScalaArtifacts.Artifacts.iterator - lib <- compileReport.modules.find(_.module.name == libName) - } yield lib - for (lib <- scalaDeps.take(1)) { - val libVer = lib.module.revision - val libName = lib.module.name - val proj = Def.displayBuildRelative(thisProjectRef.value.build, thisProjectRef.value) - if (VersionNumber(sv).matchesSemVer(SemanticSelector(s"<$libVer"))) { - val err = !allowUnsafeScalaLibUpgrade.value - val fix = - if (err) - """Upgrade the `scalaVersion` to fix the build. If upgrading the Scala compiler version is - |not possible (for example due to a regression in the compiler or a missing dependency), - |this error can be demoted by setting `allowUnsafeScalaLibUpgrade := true`.""".stripMargin - else - s"""Note that the dependency classpath and the runtime classpath of your project - |contain the newer $libName $libVer, even if the scalaVersion is $sv. - |Compilation (macro expansion) or using the Scala REPL in sbt may fail with a LinkageError.""".stripMargin - - val msg = - 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 `$proj evicted` to know why $libName $libVer is getting pulled in. - |""".stripMargin - if (err) sys.error(msg) - else s.log.warn(msg) - } - } - } - def file(id: String): File = { - val files = for { - m <- toolReport.modules if m.module.name.startsWith(id) - (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType - } yield file - files.headOption getOrElse sys.error(s"Missing $id jar file") - } - - val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) - val allDocJars = - fullReport - .configuration(Configurations.ScalaDocTool) - .map(updateLibraryToCompileConfiguration) - .toSeq - .flatMap(_.modules) - .flatMap(_.artifacts.map(_._2)) - val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) - - makeScalaInstance( - sv, - libraryJars, - allCompilerJars, - allDocJars, - state.value, - scalaInstanceTopLoader.value, - ) - } def makeScalaInstance( version: String, libraryJars: Array[File], @@ -1284,46 +1159,11 @@ object Defaults extends BuildCommon { allDocJars: Seq[File], state: State, topLoader: ClassLoader, - ): ScalaInstance = { - val classLoaderCache = state.extendedClassLoaderCache - val compilerJars = allCompilerJars.filterNot(libraryJars.contains).distinct.toArray - val docJars = allDocJars - .filterNot(jar => libraryJars.contains(jar) || compilerJars.contains(jar)) - .distinct - .toArray - val allJars = libraryJars ++ compilerJars ++ docJars + ): ScalaInstance = + Compiler.makeScalaInstance(version, libraryJars, allCompilerJars, allDocJars, state, topLoader) - val libraryLoader = classLoaderCache(libraryJars.toList, topLoader) - val compilerLoader = classLoaderCache(compilerJars.toList, libraryLoader) - val fullLoader = - if (docJars.isEmpty) compilerLoader - else classLoaderCache(docJars.distinct.toList, compilerLoader) - new ScalaInstance( - version = version, - loader = fullLoader, - loaderCompilerOnly = compilerLoader, - loaderLibraryOnly = libraryLoader, - libraryJars = libraryJars, - compilerJars = compilerJars, - allJars = allJars, - explicitActual = Some(version) - ) - } - def scalaInstanceFromHome(dir: File): Initialize[Task[ScalaInstance]] = Def.task { - val dummy = ScalaInstance(dir)(state.value.classLoaderCache.apply) - Seq(dummy.loader, dummy.loaderLibraryOnly).foreach { - case a: AutoCloseable => a.close() - case _ => - } - makeScalaInstance( - dummy.version, - dummy.libraryJars, - dummy.compilerJars, - dummy.allJars, - state.value, - scalaInstanceTopLoader.value, - ) - } + def scalaInstanceFromHome(dir: File): Initialize[Task[ScalaInstance]] = + Compiler.scalaInstanceFromHome(dir) private[this] def testDefaults = Defaults.globalDefaults( diff --git a/main/src/main/scala/sbt/internal/Compiler.scala b/main/src/main/scala/sbt/internal/Compiler.scala new file mode 100644 index 000000000..d52b33db5 --- /dev/null +++ b/main/src/main/scala/sbt/internal/Compiler.scala @@ -0,0 +1,234 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal + +import java.io.File +import sbt.internal.inc.ScalaInstance +import sbt.librarymanagement.{ + Artifact, + Configurations, + ConfigurationReport, + ScalaArtifacts, + SemanticSelector, + VersionNumber +} +import xsbti.ScalaProvider + +private[sbt] object Compiler { + def scalaInstanceTask: Def.Initialize[Task[ScalaInstance]] = + Def.taskDyn { + val sh = Keys.scalaHome.value + val app = Keys.appConfiguration.value + val managed = Keys.managedScalaInstance.value + val sv = Keys.scalaVersion.value + // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed + // appropriately to avoid cycles + sh match { + case Some(h) => scalaInstanceFromHome(h) + case _ => + val scalaProvider = app.provider.scalaProvider + if (!managed) emptyScalaInstance + else if (sv == scalaProvider.version) optimizedScalaInstance(sv, scalaProvider) + else scalaInstanceFromUpdate + } + } + + /** + * A dummy ScalaInstance for Java-only projects. + */ + def emptyScalaInstance: Def.Initialize[Task[ScalaInstance]] = Def.task { + makeScalaInstance( + "0.0.0", + Array.empty, + Seq.empty, + Seq.empty, + Keys.state.value, + Keys.scalaInstanceTopLoader.value, + ) + } + + // Use the same class loader as the Scala classes used by sbt + def optimizedScalaInstance( + sv: String, + scalaProvider: ScalaProvider + ): Def.Initialize[Task[ScalaInstance]] = Def.task { + val allJars = scalaProvider.jars + val libraryJars = allJars.filter { jar => + jar.getName == "scala-library.jar" || jar.getName.startsWith("scala3-library_3") + } + val compilerJar = allJars.filter { jar => + jar.getName == "scala-compiler.jar" || jar.getName.startsWith("scala3-compiler_3") + } + compilerJar match { + case Array(compilerJar) if libraryJars.nonEmpty => + makeScalaInstance( + sv, + libraryJars, + allJars.toSeq, + Seq.empty, + Keys.state.value, + Keys.scalaInstanceTopLoader.value, + ) + case _ => ScalaInstance(sv, scalaProvider) + } + } + + def scalaInstanceFromHome(dir: File): Def.Initialize[Task[ScalaInstance]] = Def.task { + val dummy = ScalaInstance(dir)(Keys.state.value.classLoaderCache.apply) + Seq(dummy.loader, dummy.loaderLibraryOnly).foreach { + case a: AutoCloseable => a.close() + case _ => + } + makeScalaInstance( + dummy.version, + dummy.libraryJars, + dummy.compilerJars.toSeq, + dummy.allJars.toSeq, + Keys.state.value, + Keys.scalaInstanceTopLoader.value, + ) + } + + def scalaInstanceFromUpdate: Def.Initialize[Task[ScalaInstance]] = Def.task { + val sv = Keys.scalaVersion.value + val fullReport = Keys.update.value + val s = Keys.streams.value + + // For Scala 3, update scala-library.jar in `scala-tool` and `scala-doc-tool` in case a newer version + // is present in the `compile` configuration. This is needed once forwards binary compatibility is dropped + // to avoid NoSuchMethod exceptions when expanding macros. + def updateLibraryToCompileConfiguration(report: ConfigurationReport) = + if (!ScalaArtifacts.isScala3(sv)) report + else + (for { + compileConf <- fullReport.configuration(Configurations.Compile) + compileLibMod <- compileConf.modules.find(_.module.name == ScalaArtifacts.LibraryID) + reportLibMod <- report.modules.find(_.module.name == ScalaArtifacts.LibraryID) + if VersionNumber(reportLibMod.module.revision) + .matchesSemVer(SemanticSelector(s"<${compileLibMod.module.revision}")) + } yield { + val newMods = report.modules + .filterNot(_.module.name == ScalaArtifacts.LibraryID) :+ compileLibMod + report.withModules(newMods) + }).getOrElse(report) + + val toolReport = updateLibraryToCompileConfiguration( + fullReport + .configuration(Configurations.ScalaTool) + .getOrElse(sys.error(noToolConfiguration(Keys.managedScalaInstance.value))) + ) + + if (Classpaths.isScala213(sv)) { + val scalaDeps = for { + compileReport <- fullReport.configuration(Configurations.Compile).iterator + libName <- ScalaArtifacts.Artifacts.iterator + lib <- compileReport.modules.find(_.module.name == libName) + } yield lib + for (lib <- scalaDeps.take(1)) { + val libVer = lib.module.revision + val libName = lib.module.name + val proj = + Def.displayBuildRelative(Keys.thisProjectRef.value.build, Keys.thisProjectRef.value) + if (VersionNumber(sv).matchesSemVer(SemanticSelector(s"<$libVer"))) { + val err = !Keys.allowUnsafeScalaLibUpgrade.value + val fix = + if (err) + """Upgrade the `scalaVersion` to fix the build. If upgrading the Scala compiler version is + |not possible (for example due to a regression in the compiler or a missing dependency), + |this error can be demoted by setting `allowUnsafeScalaLibUpgrade := true`.""".stripMargin + else + s"""Note that the dependency classpath and the runtime classpath of your project + |contain the newer $libName $libVer, even if the scalaVersion is $sv. + |Compilation (macro expansion) or using the Scala REPL in sbt may fail with a LinkageError.""".stripMargin + + val msg = + 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 `$proj evicted` to know why $libName $libVer is getting pulled in. + |""".stripMargin + if (err) sys.error(msg) + else s.log.warn(msg) + } + } + } + def file(id: String): File = { + val files = for { + m <- toolReport.modules if m.module.name.startsWith(id) + (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType + } yield file + files.headOption getOrElse sys.error(s"Missing $id jar file") + } + + val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) + val allDocJars = + fullReport + .configuration(Configurations.ScalaDocTool) + .map(updateLibraryToCompileConfiguration) + .toSeq + .flatMap(_.modules) + .flatMap(_.artifacts.map(_._2)) + val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) + + makeScalaInstance( + sv, + libraryJars, + allCompilerJars, + allDocJars, + Keys.state.value, + Keys.scalaInstanceTopLoader.value, + ) + } + + def makeScalaInstance( + version: String, + libraryJars: Array[File], + allCompilerJars: Seq[File], + allDocJars: Seq[File], + state: State, + topLoader: ClassLoader, + ): ScalaInstance = { + val classLoaderCache = state.extendedClassLoaderCache + val compilerJars = allCompilerJars.filterNot(libraryJars.contains).distinct.toArray + val docJars = allDocJars + .filterNot(jar => libraryJars.contains(jar) || compilerJars.contains(jar)) + .distinct + .toArray + val allJars = libraryJars ++ compilerJars ++ docJars + + val libraryLoader = classLoaderCache(libraryJars.toList, topLoader) + val compilerLoader = classLoaderCache(compilerJars.toList, libraryLoader) + val fullLoader = + if (docJars.isEmpty) compilerLoader + else classLoaderCache(docJars.distinct.toList, compilerLoader) + new ScalaInstance( + version = version, + loader = fullLoader, + loaderCompilerOnly = compilerLoader, + loaderLibraryOnly = libraryLoader, + libraryJars = libraryJars, + compilerJars = compilerJars, + allJars = allJars, + explicitActual = Some(version) + ) + } + + private def noToolConfiguration(autoInstance: Boolean): String = { + val pre = "Missing Scala tool configuration from the 'update' report. " + val post = + if (autoInstance) + "'scala-tool' is normally added automatically, so this may indicate a bug in sbt or you may be removing it from ivyConfigurations, for example." + else + "Explicitly define scalaInstance or scalaHome or include Scala dependencies in the 'scala-tool' configuration." + pre + post + } +} From 840b851445cc1fd4935cb9a0b6167c647589c3db Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 1 Nov 2025 20:50:01 -0400 Subject: [PATCH 13/17] [1.x] Add Scala 3.8 REPL support **Problem** Scala 3.8 REPL won't work since they've split the repl artifact into another JAR. **Solution** This works around it by creating a yet-another sandbox configuration ScalaReplTool (similar to ScalaTool and ScalaDocTool) and a separate scalaInstance for console task, so when Zinc is invoked we'll be able to conjure the right array of JARs. --- build.sbt | 2 +- main/src/main/scala/sbt/Defaults.scala | 190 +++++++++--------- .../main/scala/sbt/internal/Compiler.scala | 187 +++++++++-------- project/Dependencies.scala | 4 +- 4 files changed, 206 insertions(+), 177 deletions(-) diff --git a/build.sbt b/build.sbt index f10004658..8f6afffae 100644 --- a/build.sbt +++ b/build.sbt @@ -11,7 +11,7 @@ import scala.util.Try // ThisBuild settings take lower precedence, // but can be shared across the multi projects. ThisBuild / version := { - val v = "1.11.8-SNAPSHOT" + val v = "1.12.0-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index a6c2c5a56..1b149e855 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -671,89 +671,94 @@ object Defaults extends BuildCommon { ) // This is included into JvmPlugin.projectSettings - def compileBase = inTask(console)(compilersSetting :: Nil) ++ compileBaseGlobal ++ Seq( - useScalaReplJLine :== false, - scalaInstanceTopLoader := { - val topLoader = if (!useScalaReplJLine.value) { - // the JLineLoader contains the SbtInterfaceClassLoader - classOf[org.jline.terminal.Terminal].getClassLoader - } else classOf[Compilers].getClassLoader // the SbtInterfaceClassLoader + def compileBase = + inTask(console)( + Seq( + scalaInstance := Compiler.scalaInstanceTask(Some(Configurations.ScalaReplTool)).value, + ) ++ compilersSetting + ) ++ compileBaseGlobal ++ Seq( + useScalaReplJLine :== false, + scalaInstanceTopLoader := { + val topLoader = if (!useScalaReplJLine.value) { + // the JLineLoader contains the SbtInterfaceClassLoader + classOf[org.jline.terminal.Terminal].getClassLoader + } else classOf[Compilers].getClassLoader // the SbtInterfaceClassLoader - // Scala 2.10 shades jline in the console so we need to make sure that it loads a compatible - // jansi version. Because of the shading, console does not work with the thin client for 2.10.x. - if (scalaVersion.value.startsWith("2.10.")) new ClassLoader(topLoader) { - override protected def loadClass(name: String, resolve: Boolean): Class[_] = { - if (name.startsWith("org.fusesource")) throw new ClassNotFoundException(name) - super.loadClass(name, resolve) + // Scala 2.10 shades jline in the console so we need to make sure that it loads a compatible + // jansi version. Because of the shading, console does not work with the thin client for 2.10.x. + if (scalaVersion.value.startsWith("2.10.")) new ClassLoader(topLoader) { + override protected def loadClass(name: String, resolve: Boolean): Class[_] = { + if (name.startsWith("org.fusesource")) throw new ClassNotFoundException(name) + super.loadClass(name, resolve) + } } - } - else topLoader - }, - scalaInstance := Compiler.scalaInstanceTask.value, - crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), - pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( - (pluginCrossBuild / sbtVersion).value - ), - // Use (sbtVersion in pluginCrossBuild) to pick the sbt module to depend from the plugin. - // Because `sbtVersion in pluginCrossBuild` can be scoped to project level, - // this setting needs to be set here too. - pluginCrossBuild / sbtDependency := { - val app = appConfiguration.value - val id = app.provider.id - val sv = (pluginCrossBuild / sbtVersion).value - val scalaV = (pluginCrossBuild / scalaVersion).value - val binVersion = (pluginCrossBuild / scalaBinaryVersion).value - val cross = id.crossVersionedValue match { - case CrossValue.Disabled => Disabled() - case CrossValue.Full => CrossVersion.full - case CrossValue.Binary => CrossVersion.binary - } - val base = ModuleID(id.groupID, id.name, sv).withCrossVersion(cross) - CrossVersion(scalaV, binVersion)(base).withCrossVersion(Disabled()) - }, - crossSbtVersions := Vector((pluginCrossBuild / sbtVersion).value), - crossTarget := makeCrossTarget( - target.value, - scalaVersion.value, - scalaBinaryVersion.value, - (pluginCrossBuild / sbtBinaryVersion).value, - sbtPlugin.value, - crossPaths.value - ), - cleanIvy := IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log), - clean := { - val _ = cleanIvy.value - try { - val store = AnalysisUtil.staticCachedStore( - analysisFile = (Compile / compileAnalysisFile).value.toPath, - useTextAnalysis = !(Compile / enableBinaryCompileAnalysis).value, - useConsistent = (Compile / enableConsistentCompileAnalysis).value, - ) - store.clearCache() - } catch { - case NonFatal(_) => () - } - clean.value - }, - scalaCompilerBridgeBinaryJar := Def.settingDyn { - val sv = scalaVersion.value - if (ScalaArtifacts.isScala3(sv) || VersionNumber(sv) - .matchesSemVer(SemanticSelector(s"=2.13 >=${ZincLmUtil.scala2SbtBridgeStart}"))) - fetchBridgeBinaryJarTask(sv) - else Def.task[Option[File]](None) - }.value, - scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeSourceModule(scalaVersion.value), - auxiliaryClassFiles ++= { - if (ScalaArtifacts.isScala3(scalaVersion.value)) List(TastyFiles.instance) - else Nil - }, - consoleProject / scalaCompilerBridgeBinaryJar := None, - consoleProject / scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeSourceModule( - appConfiguration.value.provider.scalaProvider.version - ), - classpathOptions := ClasspathOptionsUtil.noboot(scalaVersion.value), - console / classpathOptions := ClasspathOptionsUtil.replNoboot(scalaVersion.value), - ) + else topLoader + }, + scalaInstance := Compiler.scalaInstanceTask(None).value, + crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), + pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( + (pluginCrossBuild / sbtVersion).value + ), + // Use (sbtVersion in pluginCrossBuild) to pick the sbt module to depend from the plugin. + // Because `sbtVersion in pluginCrossBuild` can be scoped to project level, + // this setting needs to be set here too. + pluginCrossBuild / sbtDependency := { + val app = appConfiguration.value + val id = app.provider.id + val sv = (pluginCrossBuild / sbtVersion).value + val scalaV = (pluginCrossBuild / scalaVersion).value + val binVersion = (pluginCrossBuild / scalaBinaryVersion).value + val cross = id.crossVersionedValue match { + case CrossValue.Disabled => Disabled() + case CrossValue.Full => CrossVersion.full + case CrossValue.Binary => CrossVersion.binary + } + val base = ModuleID(id.groupID, id.name, sv).withCrossVersion(cross) + CrossVersion(scalaV, binVersion)(base).withCrossVersion(Disabled()) + }, + crossSbtVersions := Vector((pluginCrossBuild / sbtVersion).value), + crossTarget := makeCrossTarget( + target.value, + scalaVersion.value, + scalaBinaryVersion.value, + (pluginCrossBuild / sbtBinaryVersion).value, + sbtPlugin.value, + crossPaths.value + ), + cleanIvy := IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log), + clean := { + val _ = cleanIvy.value + try { + val store = AnalysisUtil.staticCachedStore( + analysisFile = (Compile / compileAnalysisFile).value.toPath, + useTextAnalysis = !(Compile / enableBinaryCompileAnalysis).value, + useConsistent = (Compile / enableConsistentCompileAnalysis).value, + ) + store.clearCache() + } catch { + case NonFatal(_) => () + } + clean.value + }, + scalaCompilerBridgeBinaryJar := Def.settingDyn { + val sv = scalaVersion.value + if (ScalaArtifacts.isScala3(sv) || VersionNumber(sv) + .matchesSemVer(SemanticSelector(s"=2.13 >=${ZincLmUtil.scala2SbtBridgeStart}"))) + fetchBridgeBinaryJarTask(sv) + else Def.task[Option[File]](None) + }.value, + scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeSourceModule(scalaVersion.value), + auxiliaryClassFiles ++= { + if (ScalaArtifacts.isScala3(scalaVersion.value)) List(TastyFiles.instance) + else Nil + }, + consoleProject / scalaCompilerBridgeBinaryJar := None, + consoleProject / scalaCompilerBridgeSource := ZincLmUtil.getDefaultBridgeSourceModule( + appConfiguration.value.provider.scalaProvider.version + ), + classpathOptions := ClasspathOptionsUtil.noboot(scalaVersion.value), + console / classpathOptions := ClasspathOptionsUtil.replNoboot(scalaVersion.value), + ) // must be a val: duplication detected by object identity private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults( Seq( @@ -1140,7 +1145,7 @@ object Defaults extends BuildCommon { } @deprecated("Use Compiler.scalaInstanceTask", "1.12.0") - def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Compiler.scalaInstanceTask + def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Compiler.scalaInstanceTask(None) // Returns the ScalaInstance only if it was not constructed via `update` // This is necessary to prevent cycles between `update` and `scalaInstance` @@ -1149,8 +1154,9 @@ object Defaults extends BuildCommon { if (scalaHome.value.isDefined) Def.task(Some(scalaInstance.value)) else Def.task(None) } + @deprecated("Use Compiler.scalaInstanceFromUpdate", "1.12.0") def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = - Compiler.scalaInstanceFromUpdate + Compiler.scalaInstanceFromUpdate(None) def makeScalaInstance( version: String, @@ -2062,6 +2068,7 @@ object Defaults extends BuildCommon { def docTaskSettings(key: TaskKey[File] = doc): Seq[Setting[_]] = inTask(key)( Seq( + scalaInstance := Compiler.scalaInstanceTask(Some(Configurations.ScalaDocTool)).value, apiMappings ++= { val dependencyCp = dependencyClasspath.value val log = streams.value.log @@ -2139,7 +2146,7 @@ object Defaults extends BuildCommon { } out } - ) + ) ++ compilersSetting ) def mainBgRunTask = mainBgRunTaskForConfig(Select(Runtime)) @@ -3189,7 +3196,7 @@ object Classpaths { ivyConfigurations ++= Configurations.auxiliary, ivyConfigurations ++= { if (managedScalaInstance.value && scalaHome.value.isEmpty) - Configurations.ScalaTool :: Configurations.ScalaDocTool :: Nil + Configurations.ScalaTool :: Configurations.ScalaDocTool :: Configurations.ScalaReplTool :: Nil else Nil }, // Coursier needs these @@ -3385,17 +3392,18 @@ object Classpaths { val pluginAdjust = if (isPlugin) sbtdeps +: base else base - val sbtOrg = scalaOrganization.value + val scalaOrg = scalaOrganization.value val version = scalaVersion.value - val extResolvers = externalResolvers.value val isScala3M123 = ScalaArtifacts.isScala3M123(version) val allToolDeps = if (scalaHome.value.isDefined || scalaModuleInfo.value.isEmpty || !managedScalaInstance.value) Nil - else if (!isScala3M123 || extResolvers.contains(Resolver.JCenterRepository)) { - ScalaArtifacts.toolDependencies(sbtOrg, version) ++ - ScalaArtifacts.docToolDependencies(sbtOrg, version) - } else ScalaArtifacts.toolDependencies(sbtOrg, version) + else if (isScala3M123) + ScalaArtifacts.toolDependencies(scalaOrg, version) + else + ScalaArtifacts.toolDependencies(scalaOrg, version) ++ + ScalaArtifacts.docToolDependencies(scalaOrg, version) ++ + ScalaArtifacts.replToolDependencies(scalaOrg, version) allToolDeps ++ pluginAdjust }, // in case of meta build, exclude all sbt modules from the dependency graph, so we can use the sbt resolved by the launcher diff --git a/main/src/main/scala/sbt/internal/Compiler.scala b/main/src/main/scala/sbt/internal/Compiler.scala index d52b33db5..473e10137 100644 --- a/main/src/main/scala/sbt/internal/Compiler.scala +++ b/main/src/main/scala/sbt/internal/Compiler.scala @@ -1,6 +1,7 @@ /* * sbt - * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. * Copyright 2008 - 2010, Mark Harrah * Licensed under Apache License 2.0 (see LICENSE) */ @@ -12,16 +13,23 @@ import java.io.File import sbt.internal.inc.ScalaInstance import sbt.librarymanagement.{ Artifact, + Configuration, Configurations, ConfigurationReport, ScalaArtifacts, SemanticSelector, + UpdateReport, VersionNumber } import xsbti.ScalaProvider private[sbt] object Compiler { - def scalaInstanceTask: Def.Initialize[Task[ScalaInstance]] = + + /** + * Returns a ScalaInstance. + * extraToolConf is used for Scala 3 since it started splitting up scaladoc and repl. + */ + def scalaInstanceTask(extraToolConf: Option[Configuration]): Def.Initialize[Task[ScalaInstance]] = Def.taskDyn { val sh = Keys.scalaHome.value val app = Keys.appConfiguration.value @@ -35,7 +43,7 @@ private[sbt] object Compiler { val scalaProvider = app.provider.scalaProvider if (!managed) emptyScalaInstance else if (sv == scalaProvider.version) optimizedScalaInstance(sv, scalaProvider) - else scalaInstanceFromUpdate + else scalaInstanceFromUpdate(extraToolConf) } } @@ -95,60 +103,49 @@ private[sbt] object Compiler { ) } - def scalaInstanceFromUpdate: Def.Initialize[Task[ScalaInstance]] = Def.task { - val sv = Keys.scalaVersion.value - val fullReport = Keys.update.value - val s = Keys.streams.value + /** + * Returns a ScalaInstance. + * extraToolConf is used for Scala 3 since it started splitting up scaladoc and repl. + */ + def scalaInstanceFromUpdate( + extraToolConf: Option[Configuration] + ): Def.Initialize[Task[ScalaInstance]] = + Def.task { + val sv = Keys.scalaVersion.value + val fullReport = Keys.update.value + val s = Keys.streams.value - // For Scala 3, update scala-library.jar in `scala-tool` and `scala-doc-tool` in case a newer version - // is present in the `compile` configuration. This is needed once forwards binary compatibility is dropped - // to avoid NoSuchMethod exceptions when expanding macros. - def updateLibraryToCompileConfiguration(report: ConfigurationReport) = - if (!ScalaArtifacts.isScala3(sv)) report - else - (for { - compileConf <- fullReport.configuration(Configurations.Compile) - compileLibMod <- compileConf.modules.find(_.module.name == ScalaArtifacts.LibraryID) - reportLibMod <- report.modules.find(_.module.name == ScalaArtifacts.LibraryID) - if VersionNumber(reportLibMod.module.revision) - .matchesSemVer(SemanticSelector(s"<${compileLibMod.module.revision}")) - } yield { - val newMods = report.modules - .filterNot(_.module.name == ScalaArtifacts.LibraryID) :+ compileLibMod - report.withModules(newMods) - }).getOrElse(report) + val toolReport = updateLibraryToCompileConfiguration(sv, fullReport)( + fullReport + .configuration(Configurations.ScalaTool) + .getOrElse(sys.error(noToolConfiguration(Keys.managedScalaInstance.value))) + ) - val toolReport = updateLibraryToCompileConfiguration( - fullReport - .configuration(Configurations.ScalaTool) - .getOrElse(sys.error(noToolConfiguration(Keys.managedScalaInstance.value))) - ) - - if (Classpaths.isScala213(sv)) { - val scalaDeps = for { - compileReport <- fullReport.configuration(Configurations.Compile).iterator - libName <- ScalaArtifacts.Artifacts.iterator - lib <- compileReport.modules.find(_.module.name == libName) - } yield lib - for (lib <- scalaDeps.take(1)) { - val libVer = lib.module.revision - val libName = lib.module.name - val proj = - Def.displayBuildRelative(Keys.thisProjectRef.value.build, Keys.thisProjectRef.value) - if (VersionNumber(sv).matchesSemVer(SemanticSelector(s"<$libVer"))) { - val err = !Keys.allowUnsafeScalaLibUpgrade.value - val fix = - if (err) - """Upgrade the `scalaVersion` to fix the build. If upgrading the Scala compiler version is + if (Classpaths.isScala213(sv)) { + val scalaDeps = for { + compileReport <- fullReport.configuration(Configurations.Compile).iterator + libName <- ScalaArtifacts.Artifacts.iterator + lib <- compileReport.modules.find(_.module.name == libName) + } yield lib + for (lib <- scalaDeps.take(1)) { + val libVer = lib.module.revision + val libName = lib.module.name + val proj = + Def.displayBuildRelative(Keys.thisProjectRef.value.build, Keys.thisProjectRef.value) + if (VersionNumber(sv).matchesSemVer(SemanticSelector(s"<$libVer"))) { + val err = !Keys.allowUnsafeScalaLibUpgrade.value + val fix = + if (err) + """Upgrade the `scalaVersion` to fix the build. If upgrading the Scala compiler version is |not possible (for example due to a regression in the compiler or a missing dependency), |this error can be demoted by setting `allowUnsafeScalaLibUpgrade := true`.""".stripMargin - else - s"""Note that the dependency classpath and the runtime classpath of your project + else + s"""Note that the dependency classpath and the runtime classpath of your project |contain the newer $libName $libVer, even if the scalaVersion is $sv. |Compilation (macro expansion) or using the Scala REPL in sbt may fail with a LinkageError.""".stripMargin - val msg = - s"""Expected `$proj scalaVersion` to be $libVer or later, but found $sv. + val msg = + 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. | @@ -156,60 +153,84 @@ private[sbt] object Compiler { | |See `$proj evicted` to know why $libName $libVer is getting pulled in. |""".stripMargin - if (err) sys.error(msg) - else s.log.warn(msg) + if (err) sys.error(msg) + else s.log.warn(msg) + } } } - } - def file(id: String): File = { - val files = for { - m <- toolReport.modules if m.module.name.startsWith(id) - (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType - } yield file - files.headOption getOrElse sys.error(s"Missing $id jar file") + def file(id: String): File = { + val files = for { + m <- toolReport.modules if m.module.name.startsWith(id) + (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType + } yield file + files.headOption getOrElse sys.error(s"Missing $id jar file") + } + + val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) + val extraToolJars = + extraToolConf match { + case Some(extra) => + fullReport + .configuration(extra) + .map(updateLibraryToCompileConfiguration(sv, fullReport)) + .toSeq + .flatMap(_.modules) + .flatMap(_.artifacts.map(_._2)) + case None => Nil + } + val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) + + makeScalaInstance( + sv, + libraryJars, + allCompilerJars, + extraToolJars, + Keys.state.value, + Keys.scalaInstanceTopLoader.value, + ) } - val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) - val allDocJars = - fullReport - .configuration(Configurations.ScalaDocTool) - .map(updateLibraryToCompileConfiguration) - .toSeq - .flatMap(_.modules) - .flatMap(_.artifacts.map(_._2)) - val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) - - makeScalaInstance( - sv, - libraryJars, - allCompilerJars, - allDocJars, - Keys.state.value, - Keys.scalaInstanceTopLoader.value, - ) - } + // For Scala 3, update scala-library.jar in `scala-tool` and `scala-doc-tool` in case a newer version + // is present in the `compile` configuration. This is needed once forwards binary compatibility is dropped + // to avoid NoSuchMethod exceptions when expanding macros. + private def updateLibraryToCompileConfiguration(sv: String, fullReport: UpdateReport)( + report: ConfigurationReport + ) = + if (!ScalaArtifacts.isScala3(sv)) report + else + (for { + compileConf <- fullReport.configuration(Configurations.Compile) + compileLibMod <- compileConf.modules.find(_.module.name == ScalaArtifacts.LibraryID) + reportLibMod <- report.modules.find(_.module.name == ScalaArtifacts.LibraryID) + if VersionNumber(reportLibMod.module.revision) + .matchesSemVer(SemanticSelector(s"<${compileLibMod.module.revision}")) + } yield { + val newMods = report.modules + .filterNot(_.module.name == ScalaArtifacts.LibraryID) :+ compileLibMod + report.withModules(newMods) + }).getOrElse(report) def makeScalaInstance( version: String, libraryJars: Array[File], allCompilerJars: Seq[File], - allDocJars: Seq[File], + extraToolJars: Seq[File], state: State, topLoader: ClassLoader, ): ScalaInstance = { val classLoaderCache = state.extendedClassLoaderCache val compilerJars = allCompilerJars.filterNot(libraryJars.contains).distinct.toArray - val docJars = allDocJars + val toolJars = extraToolJars .filterNot(jar => libraryJars.contains(jar) || compilerJars.contains(jar)) .distinct .toArray - val allJars = libraryJars ++ compilerJars ++ docJars + val allJars = libraryJars ++ compilerJars ++ toolJars val libraryLoader = classLoaderCache(libraryJars.toList, topLoader) val compilerLoader = classLoaderCache(compilerJars.toList, libraryLoader) val fullLoader = - if (docJars.isEmpty) compilerLoader - else classLoaderCache(docJars.distinct.toList, compilerLoader) + if (toolJars.isEmpty) compilerLoader + else classLoaderCache(toolJars.distinct.toList, compilerLoader) new ScalaInstance( version = version, loader = fullLoader, diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c14030431..47d798632 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -14,8 +14,8 @@ object Dependencies { // sbt modules private val ioVersion = nightlyVersion.getOrElse("1.10.5") private val lmVersion = - sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.11.6") - val zincVersion = nightlyVersion.getOrElse("1.11.0") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.12.0-M1") + val zincVersion = nightlyVersion.getOrElse("1.12.0-M1") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From 854d76b761a013a356bda3b3e14b2481046d5212 Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Mon, 3 Nov 2025 14:11:11 -0500 Subject: [PATCH 14/17] Update checkout references to 1.12.x --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3f264a16..0a5682d4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,13 +59,13 @@ jobs: uses: actions/checkout@v5 with: repository: sbt/librarymanagement - ref: develop + ref: 1.12.x path: librarymanagement - name: Checkout sbt/zinc uses: actions/checkout@v5 with: repository: sbt/zinc - ref: 1.10.x + ref: 1.12.x path: zinc - name: Setup JDK uses: actions/setup-java@v5 From ce117c5584be03c10fd97db9226862098b209e67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 19:53:22 +0000 Subject: [PATCH 15/17] [1.x] Bump coursier/cache-action from 6 to 7 Bumps [coursier/cache-action](https://github.com/coursier/cache-action) from 6 to 7. - [Release notes](https://github.com/coursier/cache-action/releases) - [Commits](https://github.com/coursier/cache-action/compare/v6...v7) --- updated-dependencies: - dependency-name: coursier/cache-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a4aa1fd19..3f601beab 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -46,7 +46,7 @@ jobs: distribution: "${{ matrix.distribution }}" java-version: "${{ matrix.java }}" - name: Coursier cache - uses: coursier/cache-action@v6 + uses: coursier/cache-action@v7 - name: Build and deploy run: | # build from fresh IO, LM, and Zinc From 6daa99b2dbba2e75ca16738de8f3d60d974f2aca Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 14 Nov 2025 00:38:03 -0500 Subject: [PATCH 16/17] fix: Parse with -Xsource:3 **Problem** On IntelliJ the users are getting the hint to upgrade to -Xsource:3 style, however the supported syntax do not parse. **Solution** This adds -Xsource:3 to the parser. The metabuild compilation uses -Xsource:3 since sbt 1.6.0. --- .../scala/sbt/internal/parser/SbtParser.scala | 2 +- main/src/test/resources/xsource3/1.sbt.txt | 7 ++++ .../sbt/internal/parser/Xsource3Spec.scala | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 main/src/test/resources/xsource3/1.sbt.txt create mode 100644 main/src/test/scala/sbt/internal/parser/Xsource3Spec.scala diff --git a/main/src/main/scala/sbt/internal/parser/SbtParser.scala b/main/src/main/scala/sbt/internal/parser/SbtParser.scala index eb7bed7cb..f703cf271 100644 --- a/main/src/main/scala/sbt/internal/parser/SbtParser.scala +++ b/main/src/main/scala/sbt/internal/parser/SbtParser.scala @@ -129,7 +129,7 @@ private[sbt] object SbtParser { private[sbt] var scalacGlobalInitReporter: Option[ConsoleReporter] = None private[sbt] final val (defaultGlobalForParser, globalReporter) = { - val options = "-cp" :: s"$defaultClasspath" :: "-Yrangepos" :: Nil + val options = "-cp" :: s"$defaultClasspath" :: "-Yrangepos" :: "-Xsource:3" :: Nil val reportError = (msg: String) => System.err.println(msg) val command = new CompilerCommand(options, reportError) val settings = command.settings diff --git a/main/src/test/resources/xsource3/1.sbt.txt b/main/src/test/resources/xsource3/1.sbt.txt new file mode 100644 index 000000000..d37ff7c3a --- /dev/null +++ b/main/src/test/resources/xsource3/1.sbt.txt @@ -0,0 +1,7 @@ +ThisBuild / scalaVersion := "3.3.4" + +def foo(): Unit = { + List("") match { case List(path@_*) => () } + List("") match { case List(path *) => () } + List("") match { case List(path*) => () } +} diff --git a/main/src/test/scala/sbt/internal/parser/Xsource3Spec.scala b/main/src/test/scala/sbt/internal/parser/Xsource3Spec.scala new file mode 100644 index 000000000..1c1b9a658 --- /dev/null +++ b/main/src/test/scala/sbt/internal/parser/Xsource3Spec.scala @@ -0,0 +1,33 @@ +/* + * sbt + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal +package parser + +import java.io.File + +import scala.io.Source + +object Xsource3Spec extends AbstractSpec { + implicit val splitter: SplitExpressions.SplitExpression = EvaluateConfigurations.splitExpressions + + test("Parser should handle -Xsource:3 syntax") { + val rootPath = getClass.getResource("/xsource3").getPath + println(s"Reading files from: $rootPath") + val allFiles = new File(rootPath).listFiles.toList + allFiles foreach { path => + println(s"$path") + val lines = Source.fromFile(path).getLines().toList + val (_, statements) = splitter(path, lines) + assert(statements.nonEmpty, s""" + |***should contains statements*** + |$lines """.stripMargin) + } + } +} From ee03e7606ee43f9269400a4267a0f0467f613f8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 04:43:00 +0000 Subject: [PATCH 17/17] [1.x] Bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/client-test.yml | 2 +- .github/workflows/dependency-graph.yml | 2 +- .github/workflows/nightly.yml | 8 ++++---- .github/workflows/server-test.yml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a5682d4c..3c3e3d839 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,21 +48,21 @@ jobs: SPARK_LOCAL_IP: "127.0.0.1" steps: - name: Checkout sbt/sbt - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Checkout sbt/io - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/io ref: develop path: io - name: Checkout sbt/librarymanagement - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/librarymanagement ref: 1.12.x path: librarymanagement - name: Checkout sbt/zinc - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/zinc ref: 1.12.x diff --git a/.github/workflows/client-test.yml b/.github/workflows/client-test.yml index df0ef6ab4..4b7c51903 100644 --- a/.github/workflows/client-test.yml +++ b/.github/workflows/client-test.yml @@ -28,7 +28,7 @@ jobs: SBT_ETC_FILE: $HOME/etc/sbt/sbtopts TEST_SBT_VER: 1.11.4 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup JDK uses: actions/setup-java@v5 with: diff --git a/.github/workflows/dependency-graph.yml b/.github/workflows/dependency-graph.yml index cbad57297..5414f60eb 100644 --- a/.github/workflows/dependency-graph.yml +++ b/.github/workflows/dependency-graph.yml @@ -12,6 +12,6 @@ jobs: name: Submit Dependency Graph runs-on: ubuntu-latest # or windows-latest, or macOS-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: sbt/setup-sbt@v1 - uses: scalacenter/sbt-dependency-submission@v3 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3f601beab..9bfeef14d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -21,21 +21,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@v5 + uses: actions/checkout@v6 - name: Checkout sbt/io - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/io ref: develop path: io - name: Checkout sbt/librarymanagement - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/librarymanagement ref: develop path: librarymanagement - name: Checkout sbt/zinc - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: sbt/zinc ref: 1.10.x diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index f5a0902c8..07871cb31 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -14,7 +14,7 @@ jobs: JVM_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8 SBT_ETC_FILE: $HOME/etc/sbt/sbtopts steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup JDK uses: actions/setup-java@v5 with: