diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c2cc30a4f..5d302c00fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: - name: Coursier cache uses: coursier/cache-action@v6 - name: Cache sbt - uses: actions/cache@v3.0.11 + uses: actions/cache@v3 with: path: ~/.sbt key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} diff --git a/.gitignore b/.gitignore index 322179c4ac..b36926580a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ npm-debug.log .bsp/ metals.sbt launcher-package/citest/freshly-baked +.vscode diff --git a/DEVELOPING.md b/DEVELOPING.md index 40cbfda3ab..909fb566a3 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -7,12 +7,15 @@ Create a [fork](https://docs.github.com/en/github/getting-started-with-github/fo ### Branch to work against -sbt uses two branches for development: +sbt uses **two or three** branches for development: +Generally the default branch set on Github is what we recommend as the base line for PRs. -- Development branch: `develop` (this is also called "master") -- Stable branch: `1.$MINOR.x`, where `$MINOR` is current minor version (e.g. `1.1.x` during 1.1.x series) +- Next minor branch: `1.$MINOR.x`, where `$MINOR` is next minor version (e.g. `1.9.x` during 1.8.x series) +- Development branch: `develop` +- Stable branch: `1.$MINOR.x`, where `$MINOR` is current minor version (e.g. `1.8.x` during 1.8.x series) -The `develop` branch represents the next major version of sbt. Only new features are pushed to the `develop` branch. This is the branch that you will branch off of to make your changes. +Currently `develop` branch represents the next major version of sbt, i.e. sbt 2. +Next minor branch is where new features can be added as long as it is binary compatible with sbt 1.0. The `stable` branch represents the current stable sbt release. Only bug fixes are back-ported to the stable branch. ### Instruction to build just sbt diff --git a/build.sbt b/build.sbt index 46681bca6c..6bd6e6fb80 100644 --- a/build.sbt +++ b/build.sbt @@ -4,6 +4,7 @@ import com.typesafe.tools.mima.core.ProblemFilters._ import com.typesafe.tools.mima.core._ import local.Scripted import java.nio.file.{ Files, Path => JPath } +import java.util.Locale import scala.util.Try @@ -1146,6 +1147,10 @@ lazy val serverTestProj = (project in file("server-test")) ) val isWin = scala.util.Properties.isWin +val isLinux = scala.util.Properties.isLinux +val isArmArchitecture: Boolean = sys.props + .getOrElse("os.arch", "") + .toLowerCase(Locale.ROOT) == "aarch64" val buildThinClient = inputKey[JPath]("generate a java implementation of the thin client") // Use a TaskKey rather than SettingKey for nativeInstallDirectory so it can left unset by default @@ -1177,7 +1182,9 @@ lazy val sbtClientProj = (project in file("client")) "-H:+ReportExceptionStackTraces", "-H:-ParseRuntimeOptions", s"-H:Name=${target.value / "bin" / "sbtn"}", - ), + ) ++ (if (isLinux && isArmArchitecture) + Seq("-H:PageSize=65536") // Make sure binary runs on kernels with page size set to 4k, 16 and 64k + else Nil), buildThinClient := { val isFish = Def.spaceDelimited("").parsed.headOption.fold(false)(_ == "--fish") val ext = if (isWin) ".bat" else if (isFish) ".fish" else ".sh" diff --git a/client/src/main/resources/META-INF/native-image/resource-config.json b/client/src/main/resources/META-INF/native-image/resource-config.json index 0bc65dde47..19d10f4a9e 100644 --- a/client/src/main/resources/META-INF/native-image/resource-config.json +++ b/client/src/main/resources/META-INF/native-image/resource-config.json @@ -16,6 +16,7 @@ {"pattern":"org/jline/utils/screen.caps"}, {"pattern":"library.properties"}, {"pattern":"darwin/x86_64/libsbtipcsocket.dylib"}, + {"pattern":"linux/aarch64/libsbtipcsocket.so"}, {"pattern":"linux/x86_64/libsbtipcsocket.so"}, {"pattern":"win32/x86_64/sbtipcsocket.dll"} ] diff --git a/launcher-package/build.sbt b/launcher-package/build.sbt index cceaebd16e..60ff78f3bb 100755 --- a/launcher-package/build.sbt +++ b/launcher-package/build.sbt @@ -72,9 +72,11 @@ val exportRepoCsrDirectory = settingKey[File]("") val x86MacPlatform = "x86_64-apple-darwin" val x86LinuxPlatform = "x86_64-pc-linux" +val aarch64LinuxPlatform = "aarch64-pc-linux" val x86WindowsPlatform = "x86_64-pc-win32" val x86MacImageName = s"sbtn-$x86MacPlatform" val x86LinuxImageName = s"sbtn-$x86LinuxPlatform" +val aarch64LinuxImageName = s"sbtn-$aarch64LinuxPlatform" val x86WindowsImageName = s"sbtn-$x86WindowsPlatform.exe" organization in ThisBuild := "org.scala-sbt" @@ -119,17 +121,19 @@ val root = (project in file(".")). file }, // update sbt.sh at root - sbtnVersion := "1.7.0", + sbtnVersion := "1.8.1", sbtnJarsBaseUrl := "https://github.com/sbt/sbtn-dist/releases/download", sbtnJarsMappings := { val baseUrl = sbtnJarsBaseUrl.value val v = sbtnVersion.value val macosImageTar = s"sbtn-$x86MacPlatform-$v.tar.gz" - val linuxImageTar = s"sbtn-$x86LinuxPlatform-$v.tar.gz" + val linuxX86ImageTar = s"sbtn-$x86LinuxPlatform-$v.tar.gz" + val linuxAarch64ImageTar = s"sbtn-$aarch64LinuxPlatform-$v.tar.gz" val windowsImageZip = s"sbtn-$x86WindowsPlatform-$v.zip" val t = target.value val macosTar = t / macosImageTar - val linuxTar = t / linuxImageTar + val linuxX86Tar = t / linuxX86ImageTar + val linuxAarch64Tar = t / linuxAarch64ImageTar val windowsZip = t / windowsImageZip import dispatch.classic._ if(!macosTar.exists && !isWindows && sbtIncludeSbtn) { @@ -142,16 +146,26 @@ val root = (project in file(".")). s"tar zxvf $macosTar --directory $platformDir".! IO.move(platformDir / "sbtn", t / x86MacImageName) } - if(!linuxTar.exists && !isWindows && sbtIncludeSbtn) { - IO.touch(linuxTar) - val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxTar)) - try Http(url(s"$baseUrl/v$v/$linuxImageTar") >>> writer) + if(!linuxX86Tar.exists && !isWindows && sbtIncludeSbtn) { + IO.touch(linuxX86Tar) + val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxX86Tar)) + try Http(url(s"$baseUrl/v$v/$linuxX86ImageTar") >>> writer) finally writer.close() val platformDir = t / x86LinuxPlatform IO.createDirectory(platformDir) - s"""tar zxvf $linuxTar --directory $platformDir""".! + s"""tar zxvf $linuxX86Tar --directory $platformDir""".! IO.move(platformDir / "sbtn", t / x86LinuxImageName) } + if(!linuxAarch64Tar.exists && !isWindows && sbtIncludeSbtn) { + IO.touch(linuxAarch64Tar) + val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(linuxAarch64Tar)) + try Http(url(s"$baseUrl/v$v/$linuxAarch64ImageTar") >>> writer) + finally writer.close() + val platformDir = t / aarch64LinuxPlatform + IO.createDirectory(platformDir) + s"""tar zxvf $linuxAarch64Tar --directory $platformDir""".! + IO.move(platformDir / "sbtn", t / aarch64LinuxImageName) + } if(!windowsZip.exists && sbtIncludeSbtn) { IO.touch(windowsZip) val writer = new java.io.BufferedOutputStream(new java.io.FileOutputStream(windowsZip)) @@ -166,6 +180,7 @@ val root = (project in file(".")). else Seq(t / x86MacImageName -> s"bin/$x86MacImageName", t / x86LinuxImageName -> s"bin/$x86LinuxImageName", + t / aarch64LinuxImageName -> s"bin/$aarch64LinuxImageName", t / x86WindowsImageName -> s"bin/$x86WindowsImageName") }, @@ -222,7 +237,7 @@ val root = (project in file(".")). val orig = (linuxPackageMappings in Rpm).value val nativeMappings = sbtnJarsMappings.value orig.map(o => o.copy(mappings = o.mappings.toList filterNot { - case (x, p) => p.contains("sbtn-x86_64") + case (x, p) => p.contains("sbtn-x86_64") || p.contains("sbtn-aarch64") })) }, rpmVendor := "lightbend", diff --git a/main/src/main/scala/sbt/internal/InstallSbtn.scala b/main/src/main/scala/sbt/internal/InstallSbtn.scala index b6a1a26827..e5edd4b6f6 100644 --- a/main/src/main/scala/sbt/internal/InstallSbtn.scala +++ b/main/src/main/scala/sbt/internal/InstallSbtn.scala @@ -64,7 +64,11 @@ private[sbt] object InstallSbtn { if (Properties.isWin) "pc-win32.exe" else if (Properties.isLinux) "pc-linux" else "apple-darwin" - val sbtnName = s"sbt/bin/sbtn-x86_64-$bin" + val isArmArchitecture: Boolean = sys.props + .getOrElse("os.arch", "") + .toLowerCase(java.util.Locale.ROOT) == "aarch64" + val arch = if (Properties.isLinux && isArmArchitecture) "aarch64" else "x86_64" + val sbtnName = s"sbt/bin/sbtn-$arch-$bin" val fis = new FileInputStream(sbtZip.toFile) val zipInputStream = new ZipInputStream(fis) var foundBinary = false diff --git a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala index 392cc1fc98..4123418102 100644 --- a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala +++ b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala @@ -37,7 +37,7 @@ class InstallSbtnSpec extends AnyFlatSpec { "InstallSbtn" should "extract native sbtn" ignore withTemp(".zip") { tmp => withTemp(".exe") { sbtn => - InstallSbtn.extractSbtn(term, "1.4.1", tmp, sbtn) + InstallSbtn.extractSbtn(term, "1.8.1", tmp, sbtn) val tmpDir = Files.createTempDirectory("sbtn-test").toRealPath() Files.createDirectories(tmpDir.resolve("project")) val foo = tmpDir.resolve("foo") @@ -46,7 +46,7 @@ class InstallSbtnSpec extends AnyFlatSpec { IO.write(tmpDir.resolve("build.sbt").toFile, build) IO.write( tmpDir.resolve("project").resolve("build.properties").toFile, - "sbt.version=1.4.1" + "sbt.version=1.8.0" ) try { val proc = diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 33941806c9..0a9c69c2ab 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -26,7 +26,7 @@ object Dependencies { val launcherInterface = "org.scala-sbt" % "launcher-interface" % launcherVersion val rawLauncher = "org.scala-sbt" % "launcher" % launcherVersion val testInterface = "org.scala-sbt" % "test-interface" % "1.0" - val ipcSocket = "org.scala-sbt.ipcsocket" % "ipcsocket" % "1.5.0" + val ipcSocket = "org.scala-sbt.ipcsocket" % "ipcsocket" % "1.6.1" private val compilerInterface = "org.scala-sbt" % "compiler-interface" % zincVersion private val compilerClasspath = "org.scala-sbt" %% "zinc-classpath" % zincVersion @@ -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.0.13" + val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.15" def sjsonNew(n: String) = Def.setting("com.eed3si9n" %% n % "0.9.1") // contrabandSjsonNewVersion.value diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index bdc850cd22..4317f893df 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -63,8 +63,10 @@ object BuildServerConnection { // For those who use an old sbt script, the -Dsbt.script is not set // As a fallback we try to find the sbt script in $PATH val fileName = if (Properties.isWin) "sbt.bat" else "sbt" - val envPath = sys.env.getOrElse("PATH", "") - val allPaths = envPath.split(File.pathSeparator).map(Paths.get(_)) + val envPath = sys.env.collectFirst { + case (k, v) if k.toUpperCase() == "PATH" => v + } + val allPaths = envPath.map(_.split(File.pathSeparator).map(Paths.get(_))).getOrElse(Array.empty) allPaths .map(_.resolve(fileName)) .find(file => Files.exists(file) && Files.isExecutable(file)) diff --git a/sbt b/sbt index 6d4d96c4e4..0872548454 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.8.0" +declare builtin_sbt_version="1.8.1" declare -a residual_args declare -a java_args declare -a scalac_args @@ -24,7 +24,7 @@ declare build_props_sbt_version= declare use_sbtn= declare no_server= declare sbtn_command="$SBTN_CMD" -declare sbtn_version="1.7.0" +declare sbtn_version="1.8.1" ### ------------------------------- ### ### Helper methods for BASH scripts ### @@ -171,9 +171,16 @@ acquire_sbtn () { local target="$p/sbtn" local archive_target= local url= + local arch = "x86_64" if [[ "$OSTYPE" == "linux-gnu"* ]]; then - archive_target="$p/sbtn-x86_64-pc-linux-${sbtn_v}.tar.gz" - url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-x86_64-pc-linux-${sbtn_v}.tar.gz" + arch=$(uname -m) + if [[ "$arch" == "aarch64" ]] || [[ "$arch" == "x86_64" ]]; then + 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" + exit 2 + fi elif [[ "$OSTYPE" == "darwin"* ]]; then archive_target="$p/sbtn-x86_64-apple-darwin-${sbtn_v}.tar.gz" url="https://github.com/sbt/sbtn-dist/releases/download/v${sbtn_v}/sbtn-x86_64-apple-darwin-${sbtn_v}.tar.gz" @@ -189,7 +196,7 @@ acquire_sbtn () { if [[ -f "$target" ]]; then sbtn_command="$target" else - echoerr "downloading sbtn ${sbtn_v}" + echoerr "downloading sbtn ${sbtn_v} for ${arch}" download_url "$url" "$archive_target" if [[ "$OSTYPE" == "linux-gnu"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then tar zxf "$archive_target" --directory "$p" @@ -710,7 +717,8 @@ detectNativeClient() { if [[ "$sbtn_command" != "" ]]; then : elif [[ "$OSTYPE" == "linux-gnu"* ]]; then - [[ -f "${sbt_bin_dir}/sbtn-x86_64-pc-linux" ]] && sbtn_command="${sbt_bin_dir}/sbtn-x86_64-pc-linux" + arch=$(uname -m) + [[ -f "${sbt_bin_dir}/sbtn-${arch}-pc-linux" ]] && sbtn_command="${sbt_bin_dir}/sbtn-${arch}-pc-linux" elif [[ "$OSTYPE" == "darwin"* ]]; then [[ -f "${sbt_bin_dir}/sbtn-x86_64-apple-darwin" ]] && sbtn_command="${sbt_bin_dir}/sbtn-x86_64-apple-darwin" elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then