diff --git a/build.sc b/build.sc index 6d6eb51aad..3868eec2e4 100644 --- a/build.sc +++ b/build.sc @@ -1037,6 +1037,7 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests | def scala3LtsPrefix = "${Scala.scala3LtsPrefix}" | def scala3Lts = "${Scala.scala3Lts}" | def scala3NextRc = "${Scala.scala3NextRc}" + | def scala3NextRcAnnounced = "${Scala.scala3NextRcAnnounced}" | def scala3Next = "${Scala.scala3Next}" | def scala3NextAnnounced = "${Scala.scala3NextAnnounced}" | def defaultScala = "${Scala.defaultUser}" diff --git a/modules/integration/src/test/scala/scala/cli/integration/CoursierScalaInstallationTestHelper.scala b/modules/integration/src/test/scala/scala/cli/integration/CoursierScalaInstallationTestHelper.scala new file mode 100644 index 0000000000..2eb53db2e8 --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/CoursierScalaInstallationTestHelper.scala @@ -0,0 +1,94 @@ +package scala.cli.integration + +import com.eed3si9n.expecty.Expecty.expect + +import java.nio.charset.Charset + +import scala.jdk.CollectionConverters.IteratorHasAsScala +import scala.util.Properties + +trait CoursierScalaInstallationTestHelper { + def withScalaRunnerWrapper( + root: os.Path, + localCache: os.Path, + localBin: os.Path, + scalaVersion: String + )(f: os.Path => Unit): Unit = { + os.proc( + TestUtil.cs, + "install", + "--cache", + localCache, + "--install-dir", + localBin, + s"scala:$scalaVersion" + ).call(cwd = root) + val (launchScalaPath: os.Path, underlyingScriptPath: os.Path) = + if (Properties.isWin) { + val batchWrapperScript: os.Path = localBin / "scala.bat" + val charset = Charset.defaultCharset().toString + val batchWrapperContent = new String(os.read.bytes(batchWrapperScript), charset) + val setCommandLine = batchWrapperContent + .lines() + .iterator() + .asScala + .toList + .find(_.startsWith("SET CMDLINE=")) + .getOrElse("") + val scriptPathRegex = """SET CMDLINE="(.*\\bin\\scala\.bat)" %CMD_LINE_ARGS%""".r + val batchScript = + setCommandLine match { case scriptPathRegex(extractedPath) => extractedPath } + val batchScriptPath = os.Path(batchScript) + val oldContent = os.read(batchScriptPath) + val newContent = oldContent.replace( + "call %SCALA_CLI_CMD_WIN%", + s"""set "SCALA_CLI_CMD_WIN=${TestUtil.cliPath}" + |call %SCALA_CLI_CMD_WIN%""".stripMargin + ) + expect(newContent != oldContent) + os.write.over(batchScriptPath, newContent) + batchWrapperScript -> batchScriptPath + } + else { + val scalaBinary: os.Path = localBin / "scala" + val fileBytes = os.read.bytes(scalaBinary) + val shebang = new String(fileBytes.takeWhile(_ != '\n'), "UTF-8") + val binaryData = fileBytes.drop(shebang.length + 1) + val execLine = new String(binaryData.takeWhile(_ != '\n'), "UTF-8") + val scriptPathRegex = """exec "([^"]+/bin/scala).*"""".r + val scalaScript = execLine match { case scriptPathRegex(extractedPath) => extractedPath } + val scalaScriptPath = os.Path(scalaScript) + val lineToChange = "eval \"${SCALA_CLI_CMD_BASH[@]}\" \\" + // FIXME: the way the scala script calls the launcher currently ignores the --debug flag + val newContent = os.read(scalaScriptPath).replace( + lineToChange, + s"""SCALA_CLI_CMD_BASH=(\"\\\"${TestUtil.cliPath}\\\"\") + |$lineToChange""".stripMargin + ) + os.write.over(scalaScriptPath, newContent) + scalaBinary -> scalaScriptPath + } + val wrapperVersion = os.proc(launchScalaPath, "version", "--cli-version") + .call(cwd = root).out.trim() + val cliVersion = os.proc(TestUtil.cli, "version", "--cli-version") + .call(cwd = root).out.trim() + expect(wrapperVersion == cliVersion) + f(launchScalaPath) + // clean up cs local binaries + val csPrebuiltBinaryDir = + os.Path(underlyingScriptPath.toString().substring( + 0, + underlyingScriptPath.toString().indexOf(scalaVersion) + scalaVersion.length + )) + System.err.println(s"Cleaning up, trying to remove $csPrebuiltBinaryDir") + try { + os.remove.all(csPrebuiltBinaryDir) + + System.err.println(s"Cleanup complete. Removed $csPrebuiltBinaryDir") + } + catch { + case ex: java.nio.file.FileSystemException => + System.err.println(s"Failed to remove $csPrebuiltBinaryDir: $ex") + } + } +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/SipScalaTests.scala b/modules/integration/src/test/scala/scala/cli/integration/SipScalaTests.scala index bcb5f257ee..992d111a1f 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/SipScalaTests.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/SipScalaTests.scala @@ -5,7 +5,10 @@ import os.CommandResult import scala.util.Properties -class SipScalaTests extends ScalaCliSuite with SbtTestHelper with MillTestHelper { +class SipScalaTests extends ScalaCliSuite + with SbtTestHelper + with MillTestHelper + with CoursierScalaInstallationTestHelper { implicit class StringEnrichment(s: String) { def containsExperimentalWarningOf(featureNameAndType: String): Boolean = s.contains(s"The $featureNameAndType is experimental") || @@ -833,40 +836,20 @@ class SipScalaTests extends ScalaCliSuite with SbtTestHelper with MillTestHelper } } - if (!Properties.isWin) // FIXME: run this test on Windows - test("coursier scala installation works in --offline mode") { - TestInputs.empty.fromRoot { root => - val localCache = root / "local-cache" - val localBin = root / "local-bin" - val sv = "3.5.0-RC4" - os.proc( - TestUtil.cs, - "install", - "--cache", - localCache, - "--install-dir", - localBin, - s"scala:$sv" - ).call(cwd = root) - val scalaBinary: os.Path = localBin / "scala" - val fileBytes = os.read.bytes(scalaBinary) - val shebang = new String(fileBytes.takeWhile(_ != '\n'), "UTF-8") - val binaryData = fileBytes.drop(shebang.length + 1) - val execLine = new String(binaryData.takeWhile(_ != '\n'), "UTF-8") - val scriptPathRegex = """exec "([^"]+/bin/scala).*"""".r - val scalaScript = execLine match { case scriptPathRegex(extractedPath) => extractedPath } - val scalaScriptPath = os.Path(scalaScript) - val lineToChange = "eval \"${SCALA_CLI_CMD_BASH[@]}\" \\" - // FIXME: the way the scala script calls the launcher currently ignores the --debug flag - val newContent = os.read(scalaScriptPath).replace( - lineToChange, - s"""SCALA_CLI_CMD_BASH=(\"\\\"${TestUtil.cliPath}\\\"\") - |$lineToChange""".stripMargin - ) - os.write.over(scalaScriptPath, newContent) + test("coursier scala installation works in --offline mode") { + TestInputs.empty.fromRoot { root => + val localCache = root / "local-cache" + val localBin = root / "local-bin" + val scalaVersion = Constants.scala3NextRcAnnounced + withScalaRunnerWrapper( + root = root, + localCache = localCache, + localBin = localBin, + scalaVersion = scalaVersion + ) { launchScalaPath => val r = os.proc( - scalaScript, + launchScalaPath, "--offline", "--power", "--with-compiler", @@ -877,18 +860,11 @@ class SipScalaTests extends ScalaCliSuite with SbtTestHelper with MillTestHelper env = Map("COURSIER_CACHE" -> localCache.toString), check = false // need to clean up even on failure ) - // clean up cs local binaries - val csPrebuiltBinaryDir = - os.Path(scalaScript.substring(0, scalaScript.indexOf(sv) + sv.length)) - try os.remove.all(csPrebuiltBinaryDir) - catch { - case ex: java.nio.file.FileSystemException => - println(s"Failed to remove $csPrebuiltBinaryDir: $ex") - } expect(r.exitCode == 0) - expect(r.out.trim() == sv) + expect(r.out.trim() == scalaVersion) } } + } // this check is just to ensure this isn't being run for LTS RC jobs // should be adjusted when a new LTS line is released diff --git a/project/deps.sc b/project/deps.sc index fe3a383ff5..c837c456d9 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -10,8 +10,9 @@ object Scala { def scala3Lts = s"$scala3LtsPrefix.4" // the LTS version currently used in the build def scala3NextPrefix = "3.5" def scala3Next = s"$scala3NextPrefix.2" // the newest/next version of Scala - def scala3NextAnnounced = scala3Next // the newest/next version of Scala that's been announced - def scala3NextRc = "3.6.2-RC3" // the latest RC version of Scala Next + def scala3NextAnnounced = scala3Next // the newest/next version of Scala that's been announced + def scala3NextRc = "3.6.2-RC3" // the latest RC version of Scala Next + def scala3NextRcAnnounced = scala3NextRc // the latest RC version of Scala Next // The Scala version used to build the CLI itself. def defaultInternal = sys.props.get("scala.version.internal").getOrElse(scala3Lts)